HAxis sos
This commit is contained in:
130
Source/UnrealProject/GUI/SkillTree/EffectSelector.cpp
Normal file
130
Source/UnrealProject/GUI/SkillTree/EffectSelector.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "EffectSelector.h"
|
||||
#include "EffectSlot.h"
|
||||
#include "BaseSkillObject.h"
|
||||
#include "AbilityInfo.h"
|
||||
#include "SkillWidget.h"
|
||||
|
||||
TSubclassOf<class UEffectSelector> defaultEffectSelectorClass;
|
||||
|
||||
UEffectSelector::UEffectSelector(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
defaultEffectSelectorClass = ConstructorHelpers::FClassFinder<UEffectSelector>(L"/Game/Assets/GUI/WEEGEE_SkillEffectSelector").Class;
|
||||
}
|
||||
void UEffectSelector::NativeConstruct()
|
||||
{
|
||||
m_container = Cast<UPanelWidget>(WidgetTree->FindWidget("EffectSlotContainer"));
|
||||
if(!m_container)
|
||||
{
|
||||
GERROR("\"Container\" not found in effect selector widget " + GetName());
|
||||
}
|
||||
|
||||
onItemSelected.AddDynamic(this, &UEffectSelector::m_OnItemSelected);
|
||||
onItemSelectionConfirmed.AddDynamic(this, &UEffectSelector::m_OnItemSelectionConfirmed);
|
||||
|
||||
m_nameField = Cast<UTextBlock>(WidgetTree->FindWidget("NameField"));
|
||||
m_descriptionField = Cast<UMultiLineEditableTextBox>(WidgetTree->FindWidget("DescField"));
|
||||
|
||||
Super::NativeConstruct();
|
||||
}
|
||||
|
||||
void UEffectSelector::Init(class USkillWidget* widget)
|
||||
{
|
||||
this->skill = widget->skillAsset;
|
||||
this->widget = widget;
|
||||
|
||||
// Remove old items
|
||||
for(UEffectSlot* slot : m_effectSlots)
|
||||
{
|
||||
if(slot)
|
||||
slot->RemoveFromParent();
|
||||
}
|
||||
|
||||
if(!skill)
|
||||
{
|
||||
m_effectSlots.SetNum(0);
|
||||
RescanItems();
|
||||
return;
|
||||
}
|
||||
|
||||
// Add effect slot buttons
|
||||
for(UAbilityInfo* abilityEffect : skill->abilityEffects)
|
||||
{
|
||||
if(abilityEffect)
|
||||
{
|
||||
UEffectSlot* slot = CreateWidget<UEffectSlot>(GetWorld(), effectSlotClass);
|
||||
m_container->AddChild(slot);
|
||||
slot->Init(abilityEffect);
|
||||
m_effectSlots.Add(slot);
|
||||
}
|
||||
else
|
||||
{
|
||||
GERROR("Didn't set ability on skill " + skill->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
RescanItems();
|
||||
}
|
||||
|
||||
void UEffectSelector::Init2(class TArray<UAbilityInfo*> abilities)
|
||||
{
|
||||
this->skill = nullptr;
|
||||
this->widget = nullptr;
|
||||
// Remove old items
|
||||
for(UEffectSlot* slot : m_effectSlots)
|
||||
{
|
||||
if(slot)
|
||||
slot->RemoveFromParent();
|
||||
}
|
||||
|
||||
// Add effect slot buttons
|
||||
for(UAbilityInfo* abilityEffect : abilities)
|
||||
{
|
||||
if(abilityEffect)
|
||||
{
|
||||
UEffectSlot* slot = CreateWidget<UEffectSlot>(GetWorld(), effectSlotClass);
|
||||
m_container->AddChild(slot);
|
||||
slot->Init(abilityEffect);
|
||||
m_effectSlots.Add(slot);
|
||||
}
|
||||
else
|
||||
{
|
||||
GERROR("Didn't set ability on skill " + skill->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
RescanItems();
|
||||
}
|
||||
|
||||
void UEffectSelector::m_OnItemSelected(UMenuItemBase* item)
|
||||
{
|
||||
UEffectSlot* slot = Cast<UEffectSlot>(item);
|
||||
if(slot && slot->ability)
|
||||
{
|
||||
if(m_nameField)
|
||||
m_nameField->SetText(FText::FromString(slot->ability->name));
|
||||
if(m_descriptionField)
|
||||
m_descriptionField->SetText(FText::FromString(slot->ability->description));
|
||||
}
|
||||
}
|
||||
|
||||
void UEffectSelector::m_OnItemSelectionConfirmed(UMenuItemBase* item)
|
||||
{
|
||||
UEffectSlot* slot = Cast<UEffectSlot>(item);
|
||||
if(slot && slot->ability)
|
||||
{
|
||||
if(widget)
|
||||
{
|
||||
widget->SetSelectedEffect(slot->index);
|
||||
}
|
||||
onEffectSelected.Broadcast(slot->index);
|
||||
OnSelectionConfirmed(slot);
|
||||
}
|
||||
else
|
||||
{
|
||||
GERROR(L"Invalid ability selected");
|
||||
}
|
||||
}
|
||||
52
Source/UnrealProject/GUI/SkillTree/EffectSelector.h
Normal file
52
Source/UnrealProject/GUI/SkillTree/EffectSelector.h
Normal file
@@ -0,0 +1,52 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GUI/Menu/SubMenu.h"
|
||||
#include "EffectSelector.generated.h"
|
||||
|
||||
extern TSubclassOf<class UEffectSelector> defaultEffectSelectorClass;
|
||||
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UEffectSelector : public USubMenu
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UEffectSelector(const FObjectInitializer& init);
|
||||
virtual void NativeConstruct();
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent)
|
||||
void OnSelectionConfirmed(UEffectSlot* effect);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="EffectSelector")
|
||||
void Init(class USkillWidget* widget);
|
||||
UFUNCTION(BlueprintCallable, Category = "EffectSelector")
|
||||
void Init2(TArray<class UAbilityInfo*> abilities);
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TSubclassOf<class UEffectSlot> effectSlotClass;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
class UBaseSkillObject* skill;
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
class USkillWidget* widget;
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnEffectSelected, int32, selected);
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FOnEffectSelected onEffectSelected;
|
||||
|
||||
private:
|
||||
UFUNCTION()
|
||||
void m_OnItemSelected(UMenuItemBase* item);
|
||||
UFUNCTION()
|
||||
void m_OnItemSelectionConfirmed(UMenuItemBase* item);
|
||||
|
||||
UPROPERTY()
|
||||
UTextBlock* m_nameField;
|
||||
UPROPERTY()
|
||||
UMultiLineEditableTextBox* m_descriptionField;
|
||||
UPROPERTY()
|
||||
UPanelWidget* m_container;
|
||||
UPROPERTY()
|
||||
TArray<class UEffectSlot*> m_effectSlots;
|
||||
};
|
||||
31
Source/UnrealProject/GUI/SkillTree/EffectSlot.cpp
Normal file
31
Source/UnrealProject/GUI/SkillTree/EffectSlot.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "EffectSlot.h"
|
||||
#include "AbilityInfo.h"
|
||||
|
||||
void UEffectSlot::NativeConstruct()
|
||||
{
|
||||
m_name = Cast<UTextBlock>(WidgetTree->FindWidget("NameField"));
|
||||
m_image = Cast<UImage>(WidgetTree->FindWidget("Icon"));
|
||||
|
||||
Super::NativeConstruct();
|
||||
}
|
||||
void UEffectSlot::Init(class UAbilityInfo* ability)
|
||||
{
|
||||
this->ability = ability;
|
||||
|
||||
if(!ability)
|
||||
return;
|
||||
|
||||
if(m_name)
|
||||
{
|
||||
m_name->SetText(FText::FromString(ability->name));
|
||||
}
|
||||
if(m_image)
|
||||
{
|
||||
m_image->SetBrushFromTexture(ability->icon);
|
||||
}
|
||||
|
||||
OnInit(ability);
|
||||
}
|
||||
31
Source/UnrealProject/GUI/SkillTree/EffectSlot.h
Normal file
31
Source/UnrealProject/GUI/SkillTree/EffectSlot.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GUI/Menu/MenuButton.h"
|
||||
#include "EffectSlot.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UEffectSlot : public UMenuButton
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
virtual void NativeConstruct();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "EffectSelector")
|
||||
void Init(class UAbilityInfo* ability);
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "EffectSelector")
|
||||
void OnInit(class UAbilityInfo* ability);
|
||||
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
class UAbilityInfo* ability;
|
||||
|
||||
private:
|
||||
UImage* m_image;
|
||||
UTextBlock* m_name;
|
||||
};
|
||||
22
Source/UnrealProject/GUI/SkillTree/HexagonTile.cpp
Normal file
22
Source/UnrealProject/GUI/SkillTree/HexagonTile.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "HexagonTile.h"
|
||||
|
||||
void UHexagonTile::NativeConstruct()
|
||||
{
|
||||
TArray<UWidget*> widgets;
|
||||
WidgetTree->GetAllWidgets(widgets);
|
||||
|
||||
for (int32 i = 0; i < widgets.Num(); i++)
|
||||
{
|
||||
UImage* tmp = Cast<UImage>(widgets[i]);
|
||||
if (tmp)
|
||||
{
|
||||
material = tmp->GetDynamicMaterial();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
30
Source/UnrealProject/GUI/SkillTree/HexagonTile.h
Normal file
30
Source/UnrealProject/GUI/SkillTree/HexagonTile.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "HexagonTile.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UHexagonTile : public UUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UPROPERTY( EditAnywhere, Category = "UI" )
|
||||
int32 x;
|
||||
|
||||
UPROPERTY( EditAnywhere, Category = "UI" )
|
||||
int32 y;
|
||||
|
||||
FMargin GetMargins()
|
||||
{
|
||||
return GetFullScreenOffset();
|
||||
}
|
||||
|
||||
class UMaterialInstanceDynamic* material;
|
||||
|
||||
virtual void NativeConstruct() override;
|
||||
};
|
||||
155
Source/UnrealProject/GUI/SkillTree/SkillTreeState.h
Normal file
155
Source/UnrealProject/GUI/SkillTree/SkillTreeState.h
Normal file
@@ -0,0 +1,155 @@
|
||||
#pragma once
|
||||
#include "SkillTreeState.Generated.h"
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FSkillTreeStateObject
|
||||
{
|
||||
GENERATED_BODY();
|
||||
UPROPERTY()
|
||||
FVector2D gridIndex;
|
||||
UPROPERTY()
|
||||
float rotation;
|
||||
UPROPERTY()
|
||||
TArray<FIntPoint> placedPoints;
|
||||
UPROPERTY()
|
||||
UClass* skillObject;
|
||||
UPROPERTY()
|
||||
int32 selectedEffect;
|
||||
|
||||
bool ContainsRoot(FIntPoint root)
|
||||
{
|
||||
for (int32 i = 0; i < placedPoints.Num(); i++)
|
||||
{
|
||||
if (placedPoints[i] == root) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
TArray<FSkillTreeStateObject*> ConnectedSkills( TMap<FIntPoint, FSkillTreeStateObject*>& skillsMap )
|
||||
{
|
||||
TArray<FSkillTreeStateObject*> result;
|
||||
const FIntPoint offsets[2][6]{
|
||||
{ FIntPoint(0, -1), FIntPoint(1, -1), FIntPoint(1, 0), FIntPoint(0, 1), FIntPoint(-1, 0), FIntPoint(-1, -1) },
|
||||
{ FIntPoint(0, -1), FIntPoint(1, 0), FIntPoint(1, 1), FIntPoint(0, 1), FIntPoint(-1, 1), FIntPoint(-1, 0) } };
|
||||
for (int32 i = 0; i < placedPoints.Num(); i++)
|
||||
{
|
||||
int32 k = placedPoints[i].X & 1;
|
||||
for (int32 j = 0; j < 6; j++)
|
||||
{
|
||||
FIntPoint checkPoint = placedPoints[i] + offsets[k][j];
|
||||
if (placedPoints.Contains(checkPoint)) continue;
|
||||
if (skillsMap.Contains(checkPoint))
|
||||
{
|
||||
FSkillTreeStateObject* skill = *skillsMap.Find(checkPoint);
|
||||
if (result.Contains(skill)) continue;
|
||||
result.Push(skill);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FSkillTreeState
|
||||
{
|
||||
GENERATED_BODY();
|
||||
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
TArray<FSkillTreeStateObject> objects;
|
||||
|
||||
private:
|
||||
void WalkTree(TMap<FSkillTreeStateObject*, TArray<FSkillTreeStateObject*>>* a_map, TArray<FSkillTreeStateObject*>* a_checked, TArray<FSkillTreeStateObject*> a_nodes)
|
||||
{
|
||||
for (int32 i = 0; i < a_nodes.Num(); i++)
|
||||
{
|
||||
if (a_checked->Contains(a_nodes[i])) continue;
|
||||
a_checked->Push(a_nodes[i]);
|
||||
TArray<FSkillTreeStateObject*>* connected = a_map->Find(a_nodes[i]);
|
||||
if (!connected)
|
||||
{
|
||||
YERROR("Could not find the connected skills.");
|
||||
continue;
|
||||
}
|
||||
WalkTree(a_map, a_checked, *connected);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
bool ValidateSkillTree()
|
||||
{
|
||||
bool rootResult = false;
|
||||
bool connectResult = true;
|
||||
|
||||
if (objects.Num() == 0) return true;
|
||||
|
||||
|
||||
TMap<FSkillTreeStateObject*, TArray<FSkillTreeStateObject*>> connectedSkillsMap;
|
||||
TMap<FIntPoint, FSkillTreeStateObject*> skillsMap;
|
||||
FSkillTreeStateObject* rootSkill = NULL;
|
||||
for (int32 i = 0; i < objects.Num(); i++)
|
||||
{
|
||||
TArray<FIntPoint> points = objects[i].placedPoints;
|
||||
for (int32 j = 0; j < points.Num(); j++)
|
||||
{
|
||||
skillsMap.Add(points[j], &objects[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < objects.Num(); i++)
|
||||
{
|
||||
TArray<FIntPoint> points = objects[i].placedPoints;
|
||||
if (!rootResult)
|
||||
{
|
||||
bool rootTest = objects[i].ContainsRoot(FIntPoint(6,15));
|
||||
if (rootTest)
|
||||
{
|
||||
rootResult = true;
|
||||
rootSkill = &objects[i];
|
||||
}
|
||||
}
|
||||
TArray<FSkillTreeStateObject*> connectedSkills = objects[i].ConnectedSkills(skillsMap);
|
||||
connectedSkillsMap.Add(&objects[i], connectedSkills);
|
||||
if (connectedSkills.Num() == 0)
|
||||
{
|
||||
connectResult = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (connectResult && rootResult)
|
||||
{
|
||||
if (!rootSkill)
|
||||
{
|
||||
YERROR("Root Skill is NULL!");
|
||||
return false;
|
||||
}
|
||||
TArray<FSkillTreeStateObject*> checkedSkills;
|
||||
checkedSkills.Push(rootSkill);
|
||||
TArray<FSkillTreeStateObject*>* connected = connectedSkillsMap.Find(rootSkill);
|
||||
if (!connected)
|
||||
{
|
||||
YPRINT("Root Skill is not attached to any skills!");
|
||||
return false;
|
||||
}
|
||||
WalkTree(&connectedSkillsMap, &checkedSkills, *connected);
|
||||
if (objects.Num() != checkedSkills.Num())
|
||||
connectResult = false;
|
||||
else
|
||||
{
|
||||
for (int32 i = 0; i < objects.Num(); i++)
|
||||
{
|
||||
if (!checkedSkills.Contains(&objects[i]))
|
||||
{
|
||||
connectResult = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bool isValid = false;
|
||||
if (objects.Num() == 1 && rootResult)
|
||||
isValid = true;
|
||||
else
|
||||
isValid = (rootResult && connectResult);
|
||||
return isValid;
|
||||
}
|
||||
};
|
||||
678
Source/UnrealProject/GUI/SkillTree/SkillTreeWidget.cpp
Normal file
678
Source/UnrealProject/GUI/SkillTree/SkillTreeWidget.cpp
Normal file
@@ -0,0 +1,678 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "SkillTreeWidget.h"
|
||||
#include "SkillTreeObject.h"
|
||||
#include "BaseSkillObject.h"
|
||||
#include "HexagonTile.h"
|
||||
#include "ScrollBox.h"
|
||||
#include "SkillWidget.h"
|
||||
#include "CanvasPanel.h"
|
||||
#include "PlayerControllerBase.h"
|
||||
#include "DefaultGameInstance.h"
|
||||
#include "CharacterSettings.h"
|
||||
#include "SlateBlueprintLibrary.h"
|
||||
#include "ToolTipWidget.h"
|
||||
#include "AbilityInfo.h"
|
||||
#include "SizeBorder.h"
|
||||
#include "WidgetLayoutLibrary.h"
|
||||
|
||||
int32 roundToNearestOdd1(float a_in)
|
||||
{
|
||||
return 2 * FMath::FloorToInt((a_in / 2) + 0.5f) - 2;
|
||||
}
|
||||
|
||||
int32 roundToNearestEven1(float a_in)
|
||||
{
|
||||
return 2 * FMath::FloorToInt(a_in / 2);
|
||||
}
|
||||
|
||||
void USkillTreeWidget::NativeOnSkillTreeChanged(ESkillTreeChangeEvent event, UBaseSkillObject* relevantObject)
|
||||
{
|
||||
// Recalculate dominantDamageType
|
||||
int32_t categoryCounters[] = { 0,0,0 };
|
||||
int32_t largest = 0;
|
||||
for(USkillWidget* skill : m_skillWidgets)
|
||||
{
|
||||
if(skill->selectedEffect >= 0 && skill->skillAsset)
|
||||
{
|
||||
if(skill->selectedEffect >= skill->skillAsset->abilityEffects.Num())
|
||||
{
|
||||
GERROR("CORRUPT SKILL TREE");
|
||||
continue;
|
||||
}
|
||||
|
||||
UAbilityInfo* info = skill->skillAsset->abilityEffects[skill->selectedEffect];
|
||||
int32_t& myCounter = categoryCounters[(size_t)info->abilityCategory];
|
||||
myCounter++;
|
||||
|
||||
if(myCounter >= largest)
|
||||
{
|
||||
largest = myCounter;
|
||||
dominantAbilityCategory = info->abilityCategory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onSkillTreeChanged.Broadcast(event, relevantObject);
|
||||
}
|
||||
|
||||
USkillTreeWidget::USkillTreeWidget(const FObjectInitializer& init)
|
||||
: Super( init )
|
||||
{
|
||||
m_interactive = true;
|
||||
m_shown = false;
|
||||
m_lastFocusedWidget = nullptr;
|
||||
isValid = false;
|
||||
placedSkillHexMap = new FHexMap();
|
||||
for (int32 x = 0; x < 13; x++)
|
||||
{
|
||||
placedSkillHexMap->rawdata[x] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void USkillTreeWidget::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
|
||||
UpdateVisibility();
|
||||
|
||||
// Get the tooltip widget
|
||||
m_toolTipWidget = Cast<UToolTipWidget>(WidgetTree->FindWidget("ToolTipSWidget"));
|
||||
|
||||
m_sizeBorder = Cast<USizeBorder>(WidgetTree->FindWidget("SizeBorder"));
|
||||
|
||||
if ( !skillTreeAsset ) return;
|
||||
TArray<UWidget*> widgets;
|
||||
WidgetTree->GetAllWidgets( widgets );
|
||||
UScrollBox* scrollBox = NULL;
|
||||
m_skillTreeCanvas = WidgetTree->FindWidget<UCanvasPanel>("Main_SkillTree");
|
||||
//m_focusBorder = WidgetTree->FindWidget<UBorder>("FocusBorder");
|
||||
m_inputCapture = WidgetTree->FindWidget<UBorder>("InputCapture");
|
||||
m_inputCapture->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
|
||||
for ( int32 i = 0; i < widgets.Num(); i++ )
|
||||
{
|
||||
UHexagonTile* tmpHex = Cast<UHexagonTile>( widgets[i] );
|
||||
UScrollBox* tmpScrollBox = Cast<UScrollBox>( widgets[i] );
|
||||
//USkillWidget* tmpSkill = Cast<USkillWidget>( widgets[i] );
|
||||
if ( tmpScrollBox ) scrollBox = tmpScrollBox;
|
||||
//if ( tmpSkill ) m_selectedSkill = tmpSkill;
|
||||
if ( !tmpHex ) continue;
|
||||
tiles.Push( tmpHex );
|
||||
bool test = skillTreeAsset->hexMap.Get( tmpHex->x, tmpHex->y );
|
||||
if ( test ) tmpHex->SetVisibility( ESlateVisibility::Hidden );
|
||||
}
|
||||
if ( m_selectedSkill )
|
||||
{
|
||||
m_selectedSkill->parent = this;
|
||||
m_selectedSkill->SetDragable( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
YWARNING( "No Selected Skill found!" );
|
||||
}
|
||||
}
|
||||
void USkillTreeWidget::NativeDestruct()
|
||||
{
|
||||
delete placedSkillHexMap;
|
||||
Super::NativeDestruct();
|
||||
}
|
||||
|
||||
void USkillTreeWidget::NativeTick(const FGeometry& MyGeometry, float DeltaTime)
|
||||
{
|
||||
Super::NativeTick(MyGeometry, DeltaTime);
|
||||
|
||||
//if ((m_focusBorder && m_focusBorder->IsHovered()) || draggingWidget)
|
||||
//{
|
||||
// //m_inputCapture->SetVisibility(ESlateVisibility::Visible);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// //m_inputCapture->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
|
||||
//}
|
||||
|
||||
if (m_toolTipWidget)
|
||||
{
|
||||
m_toolTipWidget->showTooltip = false;
|
||||
|
||||
FVector2D mousePos;
|
||||
UWidgetLayoutLibrary::GetMousePositionScaledByDPI(GetOwningPlayer(), mousePos.X, mousePos.Y);
|
||||
FIntPoint mouseGridPos = GetGridIndex(mousePos);
|
||||
USkillWidget** sw = tileMap.Find(mouseGridPos);
|
||||
USkillWidget* skill = sw ? *sw : nullptr;
|
||||
if (skill)
|
||||
{
|
||||
// Reset hovered state
|
||||
UAbilityInfo* info = skill->GetSelectedEffectAbility();
|
||||
if (info)
|
||||
{
|
||||
m_toolTipWidget->SetTitle(info->name);
|
||||
m_toolTipWidget->SetText(info->description);
|
||||
m_toolTipWidget->position = skill->tooltipAreaPosition;
|
||||
m_toolTipWidget->size = skill->tooltipAreaSize;
|
||||
m_toolTipWidget->showTooltip = true;
|
||||
}
|
||||
skill->hovered = true;
|
||||
}
|
||||
if (m_lastFocusedWidget && m_lastFocusedWidget != skill)
|
||||
{
|
||||
m_lastFocusedWidget->hovered = false;
|
||||
}
|
||||
m_lastFocusedWidget = skill;
|
||||
}
|
||||
}
|
||||
|
||||
FReply USkillTreeWidget::NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
|
||||
{
|
||||
if(!IsInteractive())
|
||||
return FReply::Handled();
|
||||
//GWPRINT(L"Skill tree up");
|
||||
if(draggingWidget && !draggingWidget->IsUsingController())
|
||||
{
|
||||
draggingWidget->StopDragging();
|
||||
return FReply::Handled();
|
||||
}
|
||||
return FReply::Handled();
|
||||
}
|
||||
FReply USkillTreeWidget::NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
|
||||
{
|
||||
if(!IsInteractive())
|
||||
return FReply::Handled();
|
||||
//GWPRINT(L"Skill tree down");
|
||||
FKey button = InMouseEvent.GetEffectingButton();
|
||||
if(button == EKeys::LeftMouseButton)
|
||||
{
|
||||
if(draggingWidget && !draggingWidget->IsUsingController())
|
||||
{
|
||||
draggingWidget->StopDragging();
|
||||
return FReply::Handled();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_lastFocusedWidget)
|
||||
{
|
||||
if(m_lastFocusedWidget->hovered)
|
||||
m_lastFocusedWidget->StartDragging();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(button == EKeys::RightMouseButton)
|
||||
{
|
||||
if(!draggingWidget && m_lastFocusedWidget)
|
||||
{
|
||||
if(m_lastFocusedWidget->hovered)
|
||||
{
|
||||
m_lastFocusedWidget->OnRequireSkillEffect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FReply::Handled();
|
||||
}
|
||||
FReply USkillTreeWidget::NativeOnMouseWheel(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
|
||||
{
|
||||
//GWPRINT(L"USkillTreeWidget MouseWheel " + InMouseEvent.GetWheelDelta());
|
||||
if (draggingWidget)
|
||||
{
|
||||
float add = 60.0f * FMath::FloorToFloat(InMouseEvent.GetWheelDelta());
|
||||
draggingWidget->SetSkillRotation(add + draggingWidget->GetSkillRotation());
|
||||
}
|
||||
return FReply::Unhandled();
|
||||
}
|
||||
|
||||
void USkillTreeWidget::SetIsInteractive(bool interactive)
|
||||
{
|
||||
m_interactive = interactive;
|
||||
UpdateVisibility();
|
||||
}
|
||||
void USkillTreeWidget::UpdateVisibility()
|
||||
{
|
||||
if (m_shown)
|
||||
{
|
||||
SetVisibility(ESlateVisibility::SelfHitTestInvisible);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
UImage* validImage = WidgetTree->FindWidget<UImage>("Validation_Image");
|
||||
if (m_interactive)
|
||||
{
|
||||
validImage->SetVisibility(ESlateVisibility::Visible);
|
||||
}
|
||||
else
|
||||
{
|
||||
validImage->SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
}
|
||||
|
||||
void WalkTree(TMap<USkillWidget*, TArray<USkillWidget*>>* a_map, TArray<USkillWidget*>* a_checked, TArray<USkillWidget*> a_nodes)
|
||||
{
|
||||
for (int32 i = 0; i < a_nodes.Num(); i++)
|
||||
{
|
||||
if (a_checked->Contains(a_nodes[i])) continue;
|
||||
a_checked->Push(a_nodes[i]);
|
||||
TArray<USkillWidget*>* connected = a_map->Find(a_nodes[i]);
|
||||
if (!connected)
|
||||
{
|
||||
YERROR("Could not find the connected skills.");
|
||||
continue;
|
||||
}
|
||||
WalkTree(a_map, a_checked, *connected);
|
||||
}
|
||||
}
|
||||
|
||||
bool USkillTreeWidget::ValidateSkillTree()
|
||||
{
|
||||
bool rootResult = false;
|
||||
bool connectResult = true;
|
||||
if (m_skillWidgets.Num() == 0) return true;
|
||||
TMap<USkillWidget*, TArray<USkillWidget*>> connectedSkillsMap;
|
||||
USkillWidget* rootSkill = NULL;
|
||||
for (int32 i = 0; i < m_skillWidgets.Num(); i++)
|
||||
{
|
||||
TArray<FIntPoint> points = m_skillWidgets[i]->GetPoints();
|
||||
if (!rootResult)
|
||||
{
|
||||
bool rootTest = m_skillWidgets[i]->ContainsRoot(points);
|
||||
if (rootTest)
|
||||
{
|
||||
rootResult = true;
|
||||
rootSkill = m_skillWidgets[i];
|
||||
}
|
||||
}
|
||||
TArray<USkillWidget*> connectedSkills = m_skillWidgets[i]->ConnectedSkills(points);
|
||||
connectedSkillsMap.Add(m_skillWidgets[i], connectedSkills);
|
||||
if ( connectedSkills.Num() == 0 )
|
||||
{
|
||||
connectResult = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (connectResult && rootResult)
|
||||
{
|
||||
if (!rootSkill)
|
||||
{
|
||||
YERROR("Root Skill is NULL!");
|
||||
return false;
|
||||
}
|
||||
TArray<USkillWidget*> checkedSkills;
|
||||
checkedSkills.Push(rootSkill);
|
||||
TArray<USkillWidget*>* connected = connectedSkillsMap.Find(rootSkill);
|
||||
if (!connected)
|
||||
{
|
||||
YPRINT("Root Skill is not attached to any skills!");
|
||||
return false;
|
||||
}
|
||||
WalkTree(&connectedSkillsMap, &checkedSkills, *connected);
|
||||
if (m_skillWidgets.Num() != checkedSkills.Num())
|
||||
connectResult = false;
|
||||
else
|
||||
{
|
||||
for (int32 i = 0; i < m_skillWidgets.Num(); i++)
|
||||
{
|
||||
if (!checkedSkills.Contains(m_skillWidgets[i]))
|
||||
{
|
||||
connectResult = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_skillWidgets.Num() == 1 && rootResult)
|
||||
isValid = true;
|
||||
else
|
||||
isValid = (rootResult && connectResult);
|
||||
if (isValid)
|
||||
{
|
||||
UpdateLevel(10.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateLevel(0.0f);
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
||||
FSkillTreeState USkillTreeWidget::GetState()
|
||||
{
|
||||
FSkillTreeState state;
|
||||
for(int32 i = 0; i < m_skillWidgets.Num(); i++)
|
||||
{
|
||||
FSkillTreeStateObject obj;
|
||||
USkillWidget* skill = m_skillWidgets[i];
|
||||
obj.gridIndex = skill->GetGridIndex() /*- FVector2D(1.5,4) * m_skillTreeCanvas->RenderTransform.Scale.X*/;
|
||||
obj.placedPoints = skill->placedPoints;
|
||||
obj.skillObject = skill->skillAsset->GetClass();
|
||||
obj.rotation = skill->GetSkillRotation();
|
||||
obj.selectedEffect = skill->selectedEffect;
|
||||
state.objects.Add(obj);
|
||||
|
||||
//GWPRINT(L"Saving gridIndex " + obj.gridIndex);
|
||||
//for(int32 i = 0; i < obj.placedPoints.Num(); i++)
|
||||
//{
|
||||
// GWPRINT(L"Saving Placed point " + i + L" " + obj.placedPoints[i].X + L", " + obj.placedPoints[i].Y);
|
||||
//}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
TArray<class UBaseSkillObject*> USkillTreeWidget::GetApearanceState()
|
||||
{
|
||||
return m_skillClasses;
|
||||
}
|
||||
|
||||
void USkillTreeWidget::Clear()
|
||||
{
|
||||
// Remove all placed hexes
|
||||
auto arrayCopy = m_skillWidgets;
|
||||
for(int32 i = 0; i < arrayCopy.Num(); i++)
|
||||
{
|
||||
arrayCopy[i]->RemoveFromParent();
|
||||
RemoveSkill(arrayCopy[i], arrayCopy[i]->placedPoints);
|
||||
}
|
||||
m_skillWidgets.SetNum(0);
|
||||
m_skillClasses.SetNum(0);
|
||||
tileMap.Reset();
|
||||
|
||||
// Clear Hex map
|
||||
for(int32 x = 0; x < 13; x++)
|
||||
{
|
||||
placedSkillHexMap->rawdata[x] = 0;
|
||||
}
|
||||
|
||||
isValid = true;
|
||||
|
||||
// Trigger Callbacks
|
||||
NativeOnSkillTreeChanged(ESkillTreeChangeEvent::Cleared, nullptr);
|
||||
}
|
||||
void USkillTreeWidget::BuildFromState(const FSkillTreeState& state)
|
||||
{
|
||||
Clear();
|
||||
for(int32 i = 0; i < state.objects.Num(); i++)
|
||||
{
|
||||
const FSkillTreeStateObject& obj = state.objects[i];
|
||||
UBaseSkillObject* baseSkill = obj.skillObject->GetDefaultObject<UBaseSkillObject>();
|
||||
|
||||
if(!baseSkill)
|
||||
continue;
|
||||
|
||||
//GWPRINT(L"gridIndex " + obj.gridIndex);
|
||||
//for(int32 i = 0; i < obj.placedPoints.Num(); i++)
|
||||
//{
|
||||
// GWPRINT(L"Placed point " + i + L" " + obj.placedPoints[i].X + L", " + obj.placedPoints[i].Y);
|
||||
//}
|
||||
|
||||
m_selectedSkill = CreateWidget<USkillWidget>(GetWorld(), WidgetTemplate);
|
||||
m_selectedSkill->skillAsset = baseSkill;
|
||||
m_selectedSkill->parent = this;
|
||||
if(m_skillTreeCanvas)
|
||||
m_selectedSkill->SetRenderScale(m_skillTreeCanvas->RenderTransform.Scale);
|
||||
m_selectedSkill->SetPlaced();
|
||||
if(m_skillTreeCanvas)
|
||||
m_skillTreeCanvas->GetParent()->AddChild(m_selectedSkill);
|
||||
UCanvasPanelSlot* slot = Cast<UCanvasPanelSlot>(m_selectedSkill->Slot);
|
||||
if(slot)
|
||||
{
|
||||
slot->SetAutoSize(true);
|
||||
slot->SetAlignment(FVector2D(-0.5f, -0.5f));
|
||||
}
|
||||
m_selectedSkill->SetSelectedEffect(obj.selectedEffect);
|
||||
m_selectedSkill->placedPoints = obj.placedPoints;
|
||||
m_selectedSkill->SetSkillRotation(obj.rotation);
|
||||
m_selectedSkill->PlaceOnGridIndex(obj.gridIndex);
|
||||
AddSkill(m_selectedSkill, obj.placedPoints);
|
||||
}
|
||||
}
|
||||
|
||||
void USkillTreeWidget::RemoveSkill(UBaseSkillObject* skillObject)
|
||||
{
|
||||
int32 skillID = m_skillClasses.Find(skillObject);
|
||||
if (skillID == INDEX_NONE) return;
|
||||
CancelSkill(m_skillWidgets[skillID]);
|
||||
m_skillWidgets[skillID]->Remove();
|
||||
}
|
||||
|
||||
bool USkillTreeWidget::IsUsingSkill(UBaseSkillObject* skillObject) const
|
||||
{
|
||||
return m_skillClasses.Contains(skillObject);
|
||||
}
|
||||
|
||||
USkillWidget* USkillTreeWidget::GetUsedSkill(class UBaseSkillObject* skillObject)
|
||||
{
|
||||
for (int32 i = 0; i < m_skillWidgets.Num(); i++)
|
||||
{
|
||||
if (m_skillWidgets[i]->skillAsset == skillObject)
|
||||
return m_skillWidgets[i];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void USkillTreeWidget::Save(int32 saveSlot)
|
||||
{
|
||||
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetGameInstance());
|
||||
UCharacterSettings* settings = inst->GetCharacterSettings();
|
||||
|
||||
if (saveSlot < 0 || saveSlot >= settings->characterSaves.Num())
|
||||
{
|
||||
JERROR("Invalid save slot");
|
||||
return;
|
||||
}
|
||||
|
||||
settings->characterSaves[saveSlot].skillTreeState = GetState();
|
||||
inst->SaveSettings();
|
||||
}
|
||||
void USkillTreeWidget::Load(int32 saveSlot)
|
||||
{
|
||||
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetGameInstance());
|
||||
UCharacterSettings* settings = inst->GetCharacterSettings();
|
||||
|
||||
if (saveSlot < 0 || saveSlot >= settings->characterSaves.Num())
|
||||
{
|
||||
JERROR("Invalid save slot");
|
||||
return;
|
||||
}
|
||||
|
||||
BuildFromState(settings->characterSaves[saveSlot].skillTreeState);
|
||||
ValidateSkillTree();
|
||||
}
|
||||
|
||||
FIntPoint USkillTreeWidget::GetGridIndex(FVector2D in) const
|
||||
{
|
||||
FVector2D result;
|
||||
UCanvasPanelSlot* tmpSlot = UWidgetLayoutLibrary::SlotAsCanvasSlot(m_skillTreeCanvas);
|
||||
float viewportScale = UWidgetLayoutLibrary::GetViewportScale(const_cast<USkillTreeWidget*>(this));
|
||||
FVector2D topLeft;
|
||||
float scale = 32.0f * (m_skillTreeCanvas->RenderTransform.Scale.X / 2);
|
||||
float XScale = (scale * 1.73205f);
|
||||
float YScale = scale;
|
||||
if (tmpSlot)
|
||||
{
|
||||
FVector2D screenTopRight = FVector2D(GEngine->GameViewport->Viewport->GetSizeXY().X * tmpSlot->GetAnchors().Minimum.X, GEngine->GameViewport->Viewport->GetSizeXY().Y * tmpSlot->GetAnchors().Minimum.Y);
|
||||
FVector2D offset = tmpSlot->GetPosition() * viewportScale;
|
||||
FVector2D widgetTopLeft = ((tmpSlot->GetSize() * m_skillTreeCanvas->RenderTransform.Scale.X * viewportScale) / 2);
|
||||
topLeft = screenTopRight + offset - widgetTopLeft;
|
||||
topLeft /= viewportScale;
|
||||
//topLeft.X -= 16.0f;
|
||||
}
|
||||
|
||||
float XPreFloor = (in.X - topLeft.X) / XScale;
|
||||
float YPreFloor = (in.Y - topLeft.Y) / YScale;
|
||||
int32 XIndex = FMath::FloorToInt(XPreFloor);
|
||||
int32 YIndex = FMath::FloorToInt(YPreFloor);
|
||||
/*FVector2D magicOffset = FVector2D(1.5, 4) * m_skillTreeCanvas->RenderTransform.Scale.X;*/
|
||||
bool odd = (XIndex % 2) == 1;
|
||||
if (odd)
|
||||
YIndex = roundToNearestOdd1(YIndex);
|
||||
else
|
||||
YIndex = roundToNearestEven1(YIndex);
|
||||
return FIntPoint(XIndex, (YIndex) / 2.0f);
|
||||
}
|
||||
|
||||
void USkillTreeWidget::StartDragging(USkillWidget* widget)
|
||||
{
|
||||
check(draggingWidget == nullptr);
|
||||
draggingWidget = widget;
|
||||
m_inputCapture->SetVisibility(ESlateVisibility::Visible);
|
||||
}
|
||||
|
||||
void USkillTreeWidget::StopDragging(USkillWidget* widget)
|
||||
{
|
||||
if(draggingWidget != widget)
|
||||
{
|
||||
GERROR("Calling StopDragging twice");
|
||||
}
|
||||
draggingWidget = nullptr;
|
||||
m_inputCapture->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
|
||||
}
|
||||
|
||||
void USkillTreeWidget::UpdateTextInfo_Implementation()
|
||||
{
|
||||
}
|
||||
|
||||
void USkillTreeWidget::AddSkill(USkillWidget* a_skill, const TArray<FIntPoint>& a_points)
|
||||
{
|
||||
for ( int32 i = 0; i < a_points.Num(); i++ )
|
||||
{
|
||||
placedSkillHexMap->Set( a_points[i].X, a_points[i].Y, true );
|
||||
|
||||
tileMap.Add(a_points[i], a_skill);
|
||||
}
|
||||
|
||||
UWorld* const world = GetWorld();
|
||||
if ( !world )
|
||||
{
|
||||
YWARNING( "Couldn't get the World." );
|
||||
return;
|
||||
}
|
||||
APlayerControllerBase* const controller = Cast<APlayerControllerBase>( GetOwningPlayer() );
|
||||
if ( !controller )
|
||||
{
|
||||
YWARNING( "Couldn't get the Player." );
|
||||
return;
|
||||
}
|
||||
controller->OnLearnSkill( a_skill->skillAsset );
|
||||
m_skillWidgets.Add(a_skill);
|
||||
m_skillClasses.Add(a_skill->skillAsset);
|
||||
|
||||
// Trigger Callbacks
|
||||
NativeOnSkillTreeChanged(ESkillTreeChangeEvent::Added, a_skill->skillAsset);
|
||||
|
||||
ValidateSkillTree();
|
||||
}
|
||||
|
||||
void USkillTreeWidget::RemoveSkill( USkillWidget* a_skill, const TArray<FIntPoint>& a_points )
|
||||
{
|
||||
m_skillClasses.Remove(a_skill->skillAsset);
|
||||
m_skillWidgets.Remove(a_skill);
|
||||
for ( int32 i = 0; i < a_points.Num(); i++ )
|
||||
{
|
||||
placedSkillHexMap->Set( a_points[i].X, a_points[i].Y, false );
|
||||
tileMap.Remove(a_points[i]);
|
||||
}
|
||||
|
||||
UWorld* const world = GetWorld();
|
||||
if ( !world )
|
||||
{
|
||||
YWARNING( "Couldn't get the World." );
|
||||
return;
|
||||
}
|
||||
APlayerControllerBase* const controller = Cast<APlayerControllerBase>( GetOwningPlayer() );
|
||||
if ( !controller )
|
||||
{
|
||||
YWARNING( "Couldn't get the Player." );
|
||||
return;
|
||||
}
|
||||
controller->OnUnlearnSkill( a_skill->skillAsset );
|
||||
|
||||
// Trigger Callbacks
|
||||
NativeOnSkillTreeChanged(ESkillTreeChangeEvent::Removed, a_skill->skillAsset);
|
||||
}
|
||||
|
||||
USkillWidget* USkillTreeWidget::NewSkill( USkillWidget* a_skill, bool controller )
|
||||
{
|
||||
return NewSkillFromAsset(a_skill->skillAsset, controller);
|
||||
}
|
||||
|
||||
class USkillWidget* USkillTreeWidget::NewSkillFromAsset(UBaseSkillObject* skillAsset, bool controller /*= false*/)
|
||||
{
|
||||
if(draggingWidget)
|
||||
return NULL;
|
||||
//a_skill->Disable();
|
||||
m_selectedSkill = CreateWidget<USkillWidget>(GetWorld(), WidgetTemplate);
|
||||
m_selectedSkill->skillAsset = skillAsset;
|
||||
m_selectedSkill->parent = this;
|
||||
m_selectedSkill->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
|
||||
m_selectedSkill->SetDragable(true, controller);
|
||||
m_selectedSkill->SetRenderScale(m_skillTreeCanvas->RenderTransform.Scale);
|
||||
m_skillTreeCanvas->GetParent()->AddChild(m_selectedSkill);
|
||||
m_selectedSkill->SetUserFocus(GetOwningPlayer());
|
||||
UCanvasPanelSlot* slot = Cast<UCanvasPanelSlot>(m_selectedSkill->Slot);
|
||||
if(slot)
|
||||
{
|
||||
slot->SetAutoSize(true);
|
||||
slot->SetAlignment(FVector2D(-0.5f, -0.5f));
|
||||
}
|
||||
|
||||
if(controller)
|
||||
{
|
||||
// Set initial position
|
||||
m_selectedSkill->MoveSkillAbsolute(lastGridIndex);
|
||||
}
|
||||
|
||||
return m_selectedSkill;
|
||||
}
|
||||
|
||||
void USkillTreeWidget::CancelSkill(USkillWidget* a_skill)
|
||||
{
|
||||
a_skill->RemoveFromParent();
|
||||
ValidateSkillTree();
|
||||
}
|
||||
|
||||
void USkillTreeWidget::Show()
|
||||
{
|
||||
m_shown = true;
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
void USkillTreeWidget::Hide()
|
||||
{
|
||||
m_shown = false;
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
void USkillTreeWidget::UpdateLevel(float level)
|
||||
{
|
||||
for (int32 i = 0; i < m_skillWidgets.Num(); i++)
|
||||
{
|
||||
m_skillWidgets[i]->UpdateLevel(level);
|
||||
}
|
||||
if (IsInteractable())
|
||||
{
|
||||
UpdateTextInfo();
|
||||
}
|
||||
}
|
||||
|
||||
void USkillTreeWidget::UpdateInfo(float skilltreeHeight, float skilltreeOffset)
|
||||
{
|
||||
for (int32 i = 0; i < m_skillWidgets.Num(); i++)
|
||||
{
|
||||
m_skillWidgets[i]->UpdateInfo(skilltreeHeight, skilltreeOffset);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void USkillTreeWidget::NativeTick(const FGeometry& MyGeometry, float DeltaTime)
|
||||
{
|
||||
FVector2D minPos;
|
||||
FVector2D maxPos;
|
||||
FVector2D viewportPos;
|
||||
USlateBlueprintLibrary::LocalToViewport(this, MyGeometry, MyGeometry.GetLocalSize(), maxPos, viewportPos);
|
||||
USlateBlueprintLibrary::LocalToViewport(this, MyGeometry, FVector2D(0,0), minPos, viewportPos);
|
||||
FVector2D viewportSize = maxPos - minPos;
|
||||
for (int32 i = 0; i < m_skillWidgets.Num(); i++)
|
||||
{
|
||||
m_skillWidgets[i]->UpdateInfo(viewportSize.Y, minPos.Y);
|
||||
}
|
||||
}
|
||||
*/
|
||||
155
Source/UnrealProject/GUI/SkillTree/SkillTreeWidget.h
Normal file
155
Source/UnrealProject/GUI/SkillTree/SkillTreeWidget.h
Normal file
@@ -0,0 +1,155 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Menu/SubMenu.h"
|
||||
#include "SkillTreeState.h"
|
||||
#include "AbilityInfo.h"
|
||||
#include "SkillTreeWidget.generated.h"
|
||||
|
||||
class USkillTreeObject;
|
||||
class USkillWidget;
|
||||
class UCanvasPanel;
|
||||
class UHexagonTile;
|
||||
class ADefaultPlayerController;
|
||||
struct FHexMap;
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class ESkillTreeChangeEvent : uint8
|
||||
{
|
||||
Added,
|
||||
Removed,
|
||||
Cleared,
|
||||
};
|
||||
|
||||
/*
|
||||
Yosho's skill tree?
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API USkillTreeWidget : public USubMenu
|
||||
{
|
||||
GENERATED_BODY()
|
||||
private:
|
||||
TArray<class USkillWidget*> m_skillWidgets;
|
||||
TArray<class UBaseSkillObject*> m_skillClasses;
|
||||
USkillWidget* m_selectedSkill;
|
||||
UCanvasPanel* m_skillTreeCanvas;
|
||||
UBorder* m_inputCapture;
|
||||
UBorder* m_focusBorder;
|
||||
class USizeBorder* m_sizeBorder;
|
||||
class UToolTipWidget* m_toolTipWidget;
|
||||
USkillWidget* m_lastFocusedWidget;
|
||||
|
||||
bool m_interactive;
|
||||
bool m_shown;
|
||||
|
||||
public:
|
||||
UPROPERTY(BlueprintReadOnly, Category = "UI")
|
||||
bool isValid;
|
||||
|
||||
TMap<FIntPoint, USkillWidget*> tileMap;
|
||||
TArray<UHexagonTile*> tiles;
|
||||
UPROPERTY( EditAnywhere, Category = "UI" )
|
||||
USkillTreeObject* skillTreeAsset;
|
||||
UPROPERTY( EditAnywhere, Category = "UI" )
|
||||
FIntPoint rootPoint;
|
||||
FVector2D lastGridIndex;
|
||||
|
||||
class UToolTipWidget* GetToolTipWidget() const {
|
||||
return m_toolTipWidget;
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void SetIsInteractive(bool interactive);
|
||||
void UpdateVisibility();
|
||||
bool IsShow() const { return m_shown; }
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
bool IsInteractive() const { return m_interactive; }
|
||||
class USizeBorder* GetSizeBorder() const { return m_sizeBorder; }
|
||||
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
EAbilityCategory dominantAbilityCategory;
|
||||
|
||||
// Returns the complete state to reconstruct this skilltree later with BuildFromState()
|
||||
UFUNCTION(BlueprintCallable, Category = "Skill Tree")
|
||||
FSkillTreeState GetState();
|
||||
// Returns the array of used skill objects for visual usage
|
||||
UFUNCTION(BlueprintCallable, Category = "Skill Tree")
|
||||
TArray<class UBaseSkillObject*> GetApearanceState();
|
||||
// Removes all skills from this skill tree widget
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void Clear();
|
||||
// Restores a given skill tree setup from a state struct
|
||||
UFUNCTION(BlueprintCallable, Category = "Skill Tree")
|
||||
void BuildFromState(const FSkillTreeState& state);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
bool IsUsingSkill(class UBaseSkillObject* skillObject) const;
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
USkillWidget* GetUsedSkill(class UBaseSkillObject* skillObject);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void Save(int32 saveSlot);
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void Load(int32 saveSlot);
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void RemoveSkill(class UBaseSkillObject* skillObject);
|
||||
|
||||
void StartDragging(USkillWidget* widget);
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void StopDragging(USkillWidget* widget);
|
||||
|
||||
FIntPoint GetGridIndex(FVector2D in) const;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "UI")
|
||||
USkillWidget* draggingWidget;
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "UI")
|
||||
void UpdateTextInfo();
|
||||
|
||||
FHexMap* placedSkillHexMap;
|
||||
ADefaultPlayerController* parent;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
bool ValidateSkillTree();
|
||||
|
||||
UCanvasPanel* GetCanvas()
|
||||
{
|
||||
return m_skillTreeCanvas;
|
||||
}
|
||||
void AddSkill( USkillWidget* a_skill, const TArray<FIntPoint>& a_points );
|
||||
void RemoveSkill( USkillWidget* a_skill, const TArray<FIntPoint>& a_points );
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
class USkillWidget* NewSkill(USkillWidget* a_skill, bool controller = false);
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
class USkillWidget* NewSkillFromAsset(UBaseSkillObject* skillAsset, bool controller = false);
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void CancelSkill( USkillWidget* a_skill );
|
||||
|
||||
void UpdateLevel( float level );
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void UpdateInfo( float skilltreeHeight, float skilltreeOffset );
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="UI")
|
||||
void Show();
|
||||
UFUNCTION(BlueprintCallable, Category="UI")
|
||||
void Hide();
|
||||
|
||||
UPROPERTY( EditDefaultsOnly, BlueprintReadOnly, Category = UI )
|
||||
TSubclassOf<USkillWidget> WidgetTemplate;
|
||||
|
||||
// Callback for when the skill tree state changes
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSkillTreeChanged, ESkillTreeChangeEvent, event, UBaseSkillObject*, object);
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FOnSkillTreeChanged onSkillTreeChanged;
|
||||
|
||||
virtual void NativeOnSkillTreeChanged(ESkillTreeChangeEvent event, UBaseSkillObject* relevantObject);
|
||||
|
||||
USkillTreeWidget( const FObjectInitializer& init );
|
||||
|
||||
virtual void NativeConstruct() override;
|
||||
virtual void NativeDestruct() override;
|
||||
virtual void NativeTick(const FGeometry& MyGeometry, float DeltaTime) override;
|
||||
virtual FReply NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
|
||||
virtual FReply NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
|
||||
virtual FReply NativeOnMouseWheel(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
|
||||
};
|
||||
843
Source/UnrealProject/GUI/SkillTree/SkillWidget.cpp
Normal file
843
Source/UnrealProject/GUI/SkillTree/SkillWidget.cpp
Normal file
@@ -0,0 +1,843 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "SkillWidget.h"
|
||||
#include "BaseSkillObject.h"
|
||||
#include "SkillTreeObject.h"
|
||||
#include "HexagonTile.h"
|
||||
#include "CanvasPanel.h"
|
||||
#include "Border.h"
|
||||
#include "SkillTreeWidget.h"
|
||||
#include "HexagonTile.h"
|
||||
#include "WidgetLayoutLibrary.h"
|
||||
#include "AbilityInfo.h"
|
||||
#include "SizeBorder.h"
|
||||
#include "MenuScreenBase.h"
|
||||
|
||||
int32 roundToNearestOdd(float a_in)
|
||||
{
|
||||
return 2 * FMath::FloorToInt(a_in / 2) + 1;
|
||||
}
|
||||
|
||||
int32 roundToNearestEven(float a_in)
|
||||
{
|
||||
return 2 * FMath::FloorToInt(a_in / 2);
|
||||
}
|
||||
|
||||
//Convert from Odd-q coordinate system to Cube.
|
||||
FIntVector Oddq2Cube( FIntPoint in )
|
||||
{
|
||||
int32 x = in.X;
|
||||
int32 z = int32( float( in.Y ) - float( in.X - ( in.X & 1 ) ) / 2.0f );
|
||||
int32 y = -x - z;
|
||||
return FIntVector( x, y, z );
|
||||
}
|
||||
|
||||
//Convert from Cube coordinate system to Odd-q.
|
||||
FIntPoint Cube2Oddq( FIntVector in )
|
||||
{
|
||||
int32 x = in.X;
|
||||
int32 y = int32( float( in.Z ) + float( in.X - ( in.X & 1 ) ) / 2.0f );
|
||||
return FIntPoint( x, y );
|
||||
}
|
||||
|
||||
//Convert from Even-q coordinate system to Cube.
|
||||
FIntVector Evenq2Cube( FIntPoint in )
|
||||
{
|
||||
int32 x = in.X;
|
||||
int32 z = int32( float( in.Y ) - float( in.X + ( in.X & 1 ) ) / 2.0f );
|
||||
int32 y = -x - z;
|
||||
return FIntVector( x, y, z );
|
||||
}
|
||||
|
||||
//Convert from Cube coordinate system to Even-q.
|
||||
FIntPoint Cube2Evenq( FIntVector in )
|
||||
{
|
||||
int32 x = in.X;
|
||||
int32 y = int32( float( in.Z ) + float( in.X + ( in.X & 1 ) ) / 2.0f );
|
||||
return FIntPoint( x, y );
|
||||
}
|
||||
|
||||
//Rotates a hexoganal position by the angle.
|
||||
//The position must be in Cube coordinates.
|
||||
//The angle must be in degrees.
|
||||
FIntVector RotateHexPos( FIntVector in, float angle )
|
||||
{
|
||||
while ( angle < 0 )
|
||||
{
|
||||
angle += 360;
|
||||
}
|
||||
while ( angle > 360 )
|
||||
{
|
||||
angle -= 360;
|
||||
}
|
||||
int32 steps = FMath::FloorToInt( angle / 60 );
|
||||
FIntVector result = in;
|
||||
for ( int32 i = 0; i < steps; i++ )
|
||||
{
|
||||
FIntVector tmp = FIntVector( -result.Z, -result.X, -result.Y );
|
||||
result = tmp;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//Rotates a hexoganal position by the angle.
|
||||
//The position must be in Odd-q or Even-q coordinates.
|
||||
//The OddQ boolean decides what coordinate system is used.
|
||||
//The angle must be in degrees.
|
||||
FIntPoint RotateHexPos( FIntPoint in, float angle, bool oddq )
|
||||
{
|
||||
FIntVector cubeIn;
|
||||
if ( oddq )
|
||||
cubeIn = Oddq2Cube( in );
|
||||
else
|
||||
cubeIn = Evenq2Cube( in );
|
||||
|
||||
FIntVector cubeOut = RotateHexPos( cubeIn, angle );
|
||||
|
||||
FIntPoint Out;
|
||||
if ( oddq )
|
||||
Out = Cube2Oddq( cubeOut );
|
||||
else
|
||||
Out = Cube2Evenq( cubeOut );
|
||||
return Out;
|
||||
}
|
||||
|
||||
void USkillWidget::PlaceOnGridIndex(FVector2D index)
|
||||
{
|
||||
m_lastGridIndex = index /*+ FVector2D(1.5, 4) * RenderTransform.Scale.X*/;
|
||||
UCanvasPanelSlot* tmpSlot = UWidgetLayoutLibrary::SlotAsCanvasSlot(parent->GetCanvas());
|
||||
float viewportScale = UWidgetLayoutLibrary::GetViewportScale(parent);
|
||||
FVector2D topLeft = GetSkillTreePos();
|
||||
float scale = 32.0f * (RenderTransform.Scale.X / 2);
|
||||
float XScale = (scale * 1.73205f);
|
||||
float YScale = scale;
|
||||
if(tmpSlot)
|
||||
{
|
||||
FVector2D result;
|
||||
result.X = index.X * XScale;
|
||||
result.X += topLeft.X;
|
||||
//result.X -= 2;
|
||||
result.Y = index.Y * YScale;
|
||||
result.Y += topLeft.Y;
|
||||
//result.Y += 14.5f;
|
||||
|
||||
UCanvasPanelSlot* selfSlot = UWidgetLayoutLibrary::SlotAsCanvasSlot(this);
|
||||
selfSlot->SetPosition(result);
|
||||
|
||||
placedPoints.SetNum(0);
|
||||
CheckPosition(m_lastGridIndex, &placedPoints);
|
||||
ChangeColor(GetShapeTypeColor());
|
||||
}
|
||||
}
|
||||
|
||||
void USkillWidget::SetPlaced()
|
||||
{
|
||||
m_dragable = true;
|
||||
m_placed = true;
|
||||
}
|
||||
|
||||
void USkillWidget::UpdateSkill()
|
||||
{
|
||||
m_hexagons.Empty();
|
||||
if ( !skillAsset )
|
||||
{
|
||||
//YWARNING( "No Skill Asset assigned to the Skill Widget." );
|
||||
SetVisibility( ESlateVisibility::Hidden );
|
||||
return;
|
||||
}
|
||||
SetVisibility(ESlateVisibility::SelfHitTestInvisible);
|
||||
TArray<UWidget*> widgets;
|
||||
WidgetTree->GetAllWidgets( widgets );
|
||||
UCanvasPanel* canvasPanel = NULL;
|
||||
|
||||
FLinearColor color = GetShapeTypeColor();
|
||||
|
||||
for ( int32 i = 0; i < widgets.Num(); i++ )
|
||||
{
|
||||
UHexagonTile* tmp = Cast<UHexagonTile>( widgets[i] );
|
||||
UCanvasPanel* tmpPanel = Cast<UCanvasPanel>( widgets[i] );
|
||||
if ( tmpPanel ) canvasPanel = tmpPanel;
|
||||
if ( !tmp ) continue;
|
||||
bool test = skillAsset->hexMap.Get( tmp->x, tmp->y );
|
||||
//tmp->SetColorAndOpacity( skillColor );
|
||||
m_hexagons.Push( tmp );
|
||||
if ( !test )
|
||||
{
|
||||
tmp->SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
|
||||
}
|
||||
}
|
||||
if (!m_dragable)
|
||||
{
|
||||
UpdateLevel(0);
|
||||
}
|
||||
if ( canvasPanel )
|
||||
{
|
||||
m_canvasPanel = canvasPanel;
|
||||
UCanvasPanelSlot* slot = Cast<UCanvasPanelSlot>( canvasPanel->Slot );
|
||||
if ( slot )
|
||||
{
|
||||
m_slot = slot;
|
||||
float offset = 1.0f;
|
||||
float width = ( skillAsset->hexMap.width * 27.7128f ) + 4.2871f;
|
||||
FVector2D newSize = FVector2D(width, ( (skillAsset->hexMap.height * 32.0f) - offset ));
|
||||
m_slot->SetSize(newSize);
|
||||
//GWPRINT(L"Size of " + skillAsset->GetName() + L"(placed=" + m_placed + L") = " + newSize);
|
||||
}
|
||||
if ( m_dragable )
|
||||
{
|
||||
FVector2D transformPivot;
|
||||
transformPivot.X = ( float( skillAsset->pivot.X ) + 0.5f ) / float( skillAsset->hexMap.width );
|
||||
transformPivot.Y = ( float( skillAsset->pivot.Y ) + ( ( skillAsset->pivot.X & 1 ) ? 1.0f : 0.5f ) ) / float( skillAsset->hexMap.height );
|
||||
canvasPanel->SetRenderTransformPivot( transformPivot );
|
||||
//YPRINT( "Pivot: X=" + transformPivot.X + ", Y=" + transformPivot.Y );
|
||||
}
|
||||
}
|
||||
UCanvasPanel* mainCanvas = WidgetTree->FindWidget<UCanvasPanel>("Main_Canvas");
|
||||
if ( m_dragable )
|
||||
{
|
||||
//m_spacer->SetVisibility( ESlateVisibility::Hidden );
|
||||
SetRenderScale( parent->WidgetTree->FindWidget<UCanvasPanel>("Main_SkillTree")->RenderTransform.Scale );
|
||||
}
|
||||
else
|
||||
{
|
||||
//m_spacer->SetVisibility( ESlateVisibility::Visible );
|
||||
SetRenderScale( FVector2D( 1, 1 ) );
|
||||
}
|
||||
//float scale = RenderTransform.Scale.X - 1.0f;
|
||||
//float alignment = ( m_dragable ) ? (-scale * 0.5f) : 0.5f;
|
||||
//FVector2D alignment2D ( alignment, alignment );
|
||||
//tmpSlot->SetAlignment( alignment2D );
|
||||
|
||||
if ( m_dragable && !m_controller )
|
||||
{
|
||||
FVector2D mousePos;
|
||||
UWidgetLayoutLibrary::GetMousePositionScaledByDPI( GetOwningPlayer(), mousePos.X, mousePos.Y );
|
||||
FVector2D skillPos;
|
||||
skillPos = mousePos - ( m_slot->GetSize() / 2 );
|
||||
UCanvasPanelSlot* tmpSlot2 = Cast<UCanvasPanelSlot>( Slot );
|
||||
if ( tmpSlot2 )
|
||||
{
|
||||
tmpSlot2->SetPosition( skillPos );
|
||||
}
|
||||
if(!m_placed)
|
||||
StartDragging();
|
||||
else
|
||||
{
|
||||
FVector2D position = GetViewportPos();
|
||||
FVector2D mousePos;
|
||||
UWidgetLayoutLibrary::GetMousePositionScaledByDPI(GetOwningPlayer(), mousePos.X, mousePos.Y);
|
||||
m_offset = position - mousePos;
|
||||
}
|
||||
m_offset = -( ( m_slot->GetSize() * (RenderTransform.Scale.X / 2) ) / 2);
|
||||
}
|
||||
else if (m_controller)
|
||||
{
|
||||
StartDragging();
|
||||
}
|
||||
|
||||
// Update color of hexagons
|
||||
UpdateSkillIcon();
|
||||
ChangeColor(color);
|
||||
}
|
||||
|
||||
void USkillWidget::NativeConstruct()
|
||||
{
|
||||
selectedEffect = -1;
|
||||
hovered = false;
|
||||
UpdateSkill();
|
||||
FIntPoint point( 0, 1 );
|
||||
FIntPoint a = RotateHexPos( point, 60, false );
|
||||
//YPRINT( "60: X:" + a.X + ", Y:" + a.Y );
|
||||
/*
|
||||
FIntPoint b = RotateHexPos( point, 120 );
|
||||
YPRINT( "120: X:" + b.X + ", Y:" + b.Y );
|
||||
FIntPoint c = RotateHexPos( point, 180 );
|
||||
YPRINT( "180: X:" + c.X + ", Y:" + c.Y );
|
||||
FIntPoint d = RotateHexPos( point, 240 );
|
||||
YPRINT( "240: X:" + d.X + ", Y:" + d.Y );
|
||||
FIntPoint e = RotateHexPos( point, 300 );
|
||||
YPRINT( "300: X:" + e.X + ", Y:" + e.Y );
|
||||
FIntPoint f = RotateHexPos( point, -60 );
|
||||
YPRINT( "-60: X:" + f.X + ", Y:" + f.Y );
|
||||
FIntPoint g = RotateHexPos( point, -120 );
|
||||
YPRINT( "-120: X:" + g.X + ", Y:" + g.Y );
|
||||
FIntPoint h = RotateHexPos( point, -180 );
|
||||
YPRINT( "-180: X:" + h.X + ", Y:" + h.Y );
|
||||
*/
|
||||
|
||||
//m_border = WidgetTree->FindWidget<UBorder>("Border");
|
||||
//m_border->SetVisibility(ESlateVisibility::Hidden);
|
||||
|
||||
Super::NativeConstruct();
|
||||
}
|
||||
|
||||
void USkillWidget::NativeDestruct()
|
||||
{
|
||||
Super::NativeDestruct();
|
||||
}
|
||||
|
||||
void USkillWidget::UpdateSkillColor()
|
||||
{
|
||||
FLinearColor color;
|
||||
if(m_dragging)
|
||||
{
|
||||
bool hover = CheckPosition(m_lastGridIndex);
|
||||
if(hover)
|
||||
{
|
||||
m_hovering = true;
|
||||
color = FLinearColor(0, 1, 0, 1);
|
||||
if(!GetSelectedEffectAbility())
|
||||
color = FLinearColor::Yellow;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hovering = false;
|
||||
color = FLinearColor(1, 0, 0, 1);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
color = GetShapeTypeColor();
|
||||
}
|
||||
ChangeColor(color);
|
||||
}
|
||||
|
||||
void USkillWidget::UpdateSkillIcon()
|
||||
{
|
||||
for(int32 i = 0; i < m_hexagons.Num(); i++)
|
||||
{
|
||||
if(m_hexagons[i]->material)
|
||||
{
|
||||
m_hexagons[i]->material->SetTextureParameterValue("Skill_Texture", m_skillIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void USkillWidget::SetSelectedEffect(int32 effect)
|
||||
{
|
||||
//UpdateSkill();
|
||||
|
||||
if(effect >= 0 && effect < skillAsset->abilityEffects.Num())
|
||||
{
|
||||
selectedEffect = effect;
|
||||
|
||||
// Set icon on hexagons
|
||||
UAbilityInfo* ability = skillAsset->abilityEffects[selectedEffect];
|
||||
if(ability)
|
||||
{
|
||||
m_skillIcon = ability->icon;
|
||||
}
|
||||
}
|
||||
|
||||
// Update material
|
||||
UpdateSkillIcon();
|
||||
UpdateSkillColor();
|
||||
}
|
||||
|
||||
class UAbilityInfo* USkillWidget::GetSelectedEffectAbility() const
|
||||
{
|
||||
if(selectedEffect >= 0 && selectedEffect < skillAsset->abilityEffects.Num())
|
||||
{
|
||||
return skillAsset->abilityEffects[selectedEffect];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void USkillWidget::Select()
|
||||
{
|
||||
//if ( !m_spacer ) return;
|
||||
//m_spacer->SetBrushColor( FLinearColor( 1, 1, 1, 0.68f ) );
|
||||
//parent->DeselectOther( this );
|
||||
//m_selected = true;
|
||||
//UWidgetLayoutLibrary::GetMousePositionScaledByDPI( GetOwningPlayer(), m_mousedownPos.X, m_mousedownPos.Y );
|
||||
}
|
||||
|
||||
void USkillWidget::Deselect()
|
||||
{
|
||||
//if ( !m_spacer ) return;
|
||||
//m_spacer->SetBrushColor( FLinearColor( 0, 0, 0, 0.68f ) );
|
||||
//m_selected = false;
|
||||
}
|
||||
|
||||
void USkillWidget::Remove()
|
||||
{
|
||||
parent->RemoveSkill(this, placedPoints);
|
||||
}
|
||||
|
||||
bool USkillWidget::RestartDragging()
|
||||
{
|
||||
if (parent->draggingWidget)
|
||||
return false;
|
||||
|
||||
parent->RemoveSkill(this, placedPoints);
|
||||
SetDragable(true, true);
|
||||
SetUserFocus(GetOwningPlayer());
|
||||
|
||||
parent->draggingWidget = this;
|
||||
|
||||
m_hovering = true;
|
||||
ChangeColor(FLinearColor(0, 1, 0, 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
void USkillWidget::StartDragging()
|
||||
{
|
||||
if(!m_dragging && parent->draggingWidget == nullptr && parent->IsInteractive())
|
||||
{
|
||||
m_dragging = true;
|
||||
FVector2D position = GetViewportPos();
|
||||
FVector2D mousePos;
|
||||
UWidgetLayoutLibrary::GetMousePositionScaledByDPI(GetOwningPlayer(), mousePos.X, mousePos.Y);
|
||||
m_offset = position - mousePos;
|
||||
if(m_placed) parent->RemoveSkill(this, placedPoints);
|
||||
m_placed = false;
|
||||
parent->StartDragging(this);
|
||||
OnStartDragging();
|
||||
}
|
||||
//YPRINT( "Start... (X: " + position.X + ", Y: " + position.Y + ")" );
|
||||
}
|
||||
|
||||
bool USkillWidget::PlaceSkill()
|
||||
{
|
||||
// Check if we have selected a valid effect
|
||||
bool canPlace = true;
|
||||
bool effectAssigned = GetSelectedEffectAbility() != nullptr;
|
||||
//if(m_controller && !effectAssigned)
|
||||
// canPlace = false;
|
||||
if(skillAsset->abilityEffects.Num() == 0)
|
||||
{
|
||||
GERROR("Skill has no ability effects assigned, " + skillAsset->GetName());
|
||||
canPlace = false;
|
||||
}
|
||||
|
||||
TArray<FIntPoint> points;
|
||||
placedPoints.Empty();
|
||||
if(!CheckPosition(m_lastGridIndex, &points))
|
||||
canPlace = false;
|
||||
|
||||
if(canPlace)
|
||||
{
|
||||
placedPoints = points;
|
||||
parent->AddSkill(this, points);
|
||||
m_placed = true;
|
||||
ChangeColor(GetShapeTypeColor());
|
||||
parent->StopDragging(this);
|
||||
|
||||
if(m_controller)
|
||||
{
|
||||
GetScreen()->CloseSubMenu(this);
|
||||
}
|
||||
|
||||
m_dragging = false;
|
||||
if(!effectAssigned)
|
||||
{
|
||||
OnRequireSkillEffect();
|
||||
}
|
||||
|
||||
OnPlaceDone(true);
|
||||
return true;
|
||||
}
|
||||
else if(!m_controller)
|
||||
{
|
||||
// Using mouse
|
||||
parent->CancelSkill(this);
|
||||
parent->StopDragging(this);
|
||||
OnPlaceDone(false);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
OnPlaceDone(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void USkillWidget::StopDragging()
|
||||
{
|
||||
if(m_dragging)
|
||||
{
|
||||
FVector2D mousePos;
|
||||
UWidgetLayoutLibrary::GetMousePositionScaledByDPI(GetOwningPlayer(), mousePos.X, mousePos.Y);
|
||||
FVector2D newPos = mousePos + m_offset;
|
||||
FVector4 gridresult = GetGridPos(newPos);
|
||||
FVector2D gridPos = FVector2D(gridresult.X, gridresult.Y);
|
||||
FVector2D gridIndex = FVector2D(gridresult.Z, gridresult.W);
|
||||
m_dragging = false;
|
||||
PlaceSkill();
|
||||
}
|
||||
}
|
||||
|
||||
FVector2D USkillWidget::GetPositionFromIndex(FIntPoint in)
|
||||
{
|
||||
FVector2D result;
|
||||
UCanvasPanelSlot* tmpSlot = UWidgetLayoutLibrary::SlotAsCanvasSlot(parent->GetCanvas());
|
||||
float viewportScale = UWidgetLayoutLibrary::GetViewportScale(parent);
|
||||
FVector2D topLeft = GetSkillTreePos();
|
||||
float scale = 32.0f * ( RenderTransform.Scale.X / 2);
|
||||
float XScale = (scale * 1.73205f);
|
||||
float YScale = scale;
|
||||
//FVector2D magicOffset = FVector2D(1.5, 4) * RenderTransform.Scale.X;
|
||||
float XIndex = (float)in.X;// -magicOffset.X;
|
||||
float YIndex = (float)in.Y;// -magicOffset.Y;
|
||||
result.X = XIndex * XScale + topLeft.X;
|
||||
result.Y = YIndex * YScale + topLeft.Y;
|
||||
return result;
|
||||
}
|
||||
|
||||
FVector2D USkillWidget::GetSkillTreePos()
|
||||
{
|
||||
UCanvasPanelSlot* tmpSlot = UWidgetLayoutLibrary::SlotAsCanvasSlot(parent->GetCanvas());
|
||||
float viewportScale = UWidgetLayoutLibrary::GetViewportScale(parent->GetCanvas());
|
||||
FVector2D topLeft;
|
||||
if (tmpSlot)
|
||||
{
|
||||
FVector2D screenTopRight = FVector2D(GEngine->GameViewport->Viewport->GetSizeXY().X * tmpSlot->GetAnchors().Minimum.X, GEngine->GameViewport->Viewport->GetSizeXY().Y * tmpSlot->GetAnchors().Minimum.Y);
|
||||
FVector2D offset = tmpSlot->GetPosition() * viewportScale;
|
||||
FVector2D widgetTopLeft = ((tmpSlot->GetSize() * RenderTransform.Scale.X * viewportScale) / 2) ;
|
||||
topLeft = screenTopRight + offset - widgetTopLeft;
|
||||
topLeft /= viewportScale;
|
||||
//topLeft.X -= 16.0f;
|
||||
}
|
||||
return topLeft;
|
||||
}
|
||||
|
||||
FVector2D USkillWidget::GetViewportPos()
|
||||
{
|
||||
FVector2D result;
|
||||
FVector2D position;
|
||||
UCanvasPanelSlot* tmpSlot = Cast<UCanvasPanelSlot>( Slot );
|
||||
if ( tmpSlot )
|
||||
{
|
||||
position = tmpSlot->GetPosition( );
|
||||
}
|
||||
result.X = position.X;
|
||||
result.Y = position.Y;
|
||||
return result;
|
||||
}
|
||||
|
||||
FVector4 USkillWidget::GetGridPos( FVector2D in )
|
||||
{
|
||||
FVector2D result;
|
||||
FVector2D topLeft = GetSkillTreePos();
|
||||
float scale = 32.0f * (RenderTransform.Scale.X / 2);
|
||||
float XScale = (scale * 1.73205f);
|
||||
float YScale = scale;
|
||||
int32 XIndex = FMath::FloorToInt( ( in.X - topLeft.X ) / XScale );
|
||||
int32 YIndex = FMath::FloorToInt( ( in.Y - topLeft.Y ) / YScale );
|
||||
if ( XIndex % 2 == 0 )
|
||||
YIndex = roundToNearestOdd( YIndex );
|
||||
else
|
||||
YIndex = roundToNearestEven(YIndex);
|
||||
result.X = XIndex * XScale;
|
||||
result.X += topLeft.X;
|
||||
result.Y = YIndex * YScale;
|
||||
result.Y += topLeft.Y;
|
||||
m_lastGridIndex = FVector2D(XIndex, YIndex) - FVector2D(1, 0);// Store last grid position
|
||||
return FVector4(result.X , result.Y , XIndex, YIndex);
|
||||
}
|
||||
|
||||
bool USkillWidget::CheckPosition(FVector2D in, TArray<FIntPoint>* points)
|
||||
{
|
||||
bool result = true;
|
||||
TArray<FIntPoint> localPoints;
|
||||
//Check if positions are valid and available.
|
||||
for ( int32 x1 = 0; x1 < skillAsset->hexMap.width; x1++ )
|
||||
{
|
||||
for ( int32 y1 = 0; y1 < skillAsset->hexMap.height; y1++ )
|
||||
{
|
||||
if ( skillAsset->hexMap.Get( x1, y1 ) )
|
||||
{
|
||||
int32 x2 = FMath::FloorToInt( in.X );
|
||||
int32 y2;
|
||||
int32 angle = FMath::FloorToInt( m_canvasPanel->RenderTransform.Angle );
|
||||
FIntPoint pos1 = RotateHexPos( FIntPoint( x1 - skillAsset->pivot.X, y1 - skillAsset->pivot.Y ), angle, !(skillAsset->pivot.X & 1) );
|
||||
pos1.X += skillAsset->pivot.X;
|
||||
pos1.Y += skillAsset->pivot.Y;
|
||||
if ( FMath::FloorToInt( in.X ) % 2 != 0 && pos1.X % 2 != 0 )
|
||||
y2 = FMath::FloorToInt( ( in.Y + 1 ) / 2 );
|
||||
else
|
||||
y2 = FMath::FloorToInt( in.Y / 2 );
|
||||
FIntPoint pos2 = pos1 + FIntPoint( x2, y2 );
|
||||
localPoints.Push( pos2 );
|
||||
|
||||
if (pos2.X < 0 || pos2.X >= 13 || pos2.Y < 0 || pos2.Y >= ( (pos2.X & 1) ? 15 : 16 ) || parent->skillTreeAsset->hexMap.Get(pos2.X, pos2.Y) || parent->placedSkillHexMap->Get(pos2.X, pos2.Y))
|
||||
{
|
||||
result = false;
|
||||
if ( !points )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !result && !points ) break;
|
||||
}
|
||||
if ( points ) ( *points ) = localPoints;
|
||||
|
||||
/*
|
||||
for ( int32 i = 0; i < parent->tiles.Num(); i++ )
|
||||
{
|
||||
bool test = true;
|
||||
for ( int32 j = 0; j < points.Num(); j++ )
|
||||
{
|
||||
if ( parent->tiles[i]->x == points[j].X && parent->tiles[i]->y == points[j].Y )
|
||||
{
|
||||
parent->tiles[i]->SetColorAndOpacity( FLinearColor::Yellow );
|
||||
parent->tiles[i]->SetVisibility( ESlateVisibility::Visible );
|
||||
test = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( test )
|
||||
{
|
||||
if ( !parent->skillTreeAsset->hexMap.Get( parent->tiles[i]->x, parent->tiles[i]->y ) )
|
||||
{
|
||||
parent->tiles[i]->SetColorAndOpacity( FLinearColor::White );
|
||||
parent->tiles[i]->SetVisibility( ESlateVisibility::Visible );
|
||||
}
|
||||
else
|
||||
{
|
||||
parent->tiles[i]->SetColorAndOpacity( FLinearColor::White );
|
||||
parent->tiles[i]->SetVisibility( ESlateVisibility::Hidden );
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return result;
|
||||
}
|
||||
|
||||
void USkillWidget::SetSkillRotation(float angle)
|
||||
{
|
||||
if(m_canvasPanel) m_canvasPanel->SetRenderAngle(angle);
|
||||
else YWARNING("No canvas panel found!");
|
||||
NativeOnSkillMove();
|
||||
OnRotate();
|
||||
}
|
||||
|
||||
void USkillWidget::MoveSkill(FVector2D offset)
|
||||
{
|
||||
//Check if odd
|
||||
FVector2D tmpOffset = offset;
|
||||
if (((int32)m_lastGridIndex.X) & 1 && tmpOffset.X != 0) tmpOffset.Y -= 1;
|
||||
if (!(((int32)m_lastGridIndex.X) & 1) && tmpOffset.X != 0) tmpOffset.Y += 1;
|
||||
m_lastGridIndex += tmpOffset;
|
||||
|
||||
if(parent->lastGridIndex != m_lastGridIndex)
|
||||
{
|
||||
parent->lastGridIndex = m_lastGridIndex; // Store last index
|
||||
NativeOnSkillMove();
|
||||
}
|
||||
}
|
||||
|
||||
void USkillWidget::MoveSkillAbsolute(FVector2D gridIndex)
|
||||
{
|
||||
m_lastGridIndex = gridIndex;
|
||||
parent->lastGridIndex = m_lastGridIndex; // Store last index
|
||||
NativeOnSkillMove();
|
||||
}
|
||||
|
||||
void USkillWidget::ChangeColor(FLinearColor color)
|
||||
{
|
||||
for ( int32 i = 0; i < m_hexagons.Num(); i++ )
|
||||
{
|
||||
if (m_hexagons[i]->material) m_hexagons[i]->material->SetVectorParameterValue("Skill_Color", color);
|
||||
}
|
||||
}
|
||||
|
||||
void USkillWidget::UpdateLevel( float level )
|
||||
{
|
||||
if (!m_dragable) return;
|
||||
for (int32 i = 0; i < m_hexagons.Num(); i++)
|
||||
{
|
||||
if( m_hexagons[i]->material ) m_hexagons[i]->material->SetScalarParameterValue("Skill_Level", level);
|
||||
}
|
||||
|
||||
float offset = 1.0f - level;
|
||||
float skillHeight = 13.0f * offset;
|
||||
float height = FMath::CeilToFloat(skillHeight);
|
||||
int32 hexcount = 0;
|
||||
|
||||
for (int32 i = 0; i < placedPoints.Num(); i++)
|
||||
{
|
||||
float YPos = ( placedPoints[i].X & 1 ) ? (float(placedPoints[i].Y) + 0.5f) : (float(placedPoints[i].Y));
|
||||
if ( YPos < height ) hexcount++;
|
||||
}
|
||||
|
||||
m_power = float(placedPoints.Num()) / float(hexcount);
|
||||
}
|
||||
|
||||
void USkillWidget::UpdateInfo(float skilltreeHeight, float skilltreeOffset)
|
||||
{
|
||||
for (int32 i = 0; i < m_hexagons.Num(); i++)
|
||||
{
|
||||
if (m_hexagons[i]->material)
|
||||
{
|
||||
m_hexagons[i]->material->SetScalarParameterValue("Skill_Tree_Height", skilltreeHeight);
|
||||
m_hexagons[i]->material->SetScalarParameterValue("Skill_Offset", skilltreeOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TArray<USkillWidget*> USkillWidget::ConnectedSkills(TArray<FIntPoint>& points)
|
||||
{
|
||||
//Check if surrounding positions contain another skill.
|
||||
//if ( !PointsCointainsRoot(localPoints))
|
||||
//{
|
||||
TArray<USkillWidget*> result;
|
||||
const FIntPoint offsets[2][6]{
|
||||
{ FIntPoint(0, -1), FIntPoint(1, -1), FIntPoint(1, 0), FIntPoint(0, 1), FIntPoint(-1, 0), FIntPoint(-1, -1) },
|
||||
{ FIntPoint(0, -1), FIntPoint(1, 0), FIntPoint(1, 1), FIntPoint(0, 1), FIntPoint(-1, 1), FIntPoint(-1, 0) } };
|
||||
for (int32 i = 0; i < points.Num(); i++)
|
||||
{
|
||||
int32 k = points[i].X & 1;
|
||||
for (int32 j = 0; j < 6; j++)
|
||||
{
|
||||
FIntPoint checkPoint = points[i] + offsets[k][j];
|
||||
if ( points.Contains( checkPoint ) ) continue;
|
||||
if (parent->skillTreeAsset->hexMap.Get(checkPoint.X, checkPoint.Y)) continue;
|
||||
if (parent->placedSkillHexMap->Get(checkPoint.X, checkPoint.Y))
|
||||
{
|
||||
USkillWidget* widget = *parent->tileMap.Find(checkPoint);
|
||||
if (result.Contains(widget)) continue;
|
||||
result.Push(widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
//}
|
||||
}
|
||||
|
||||
bool USkillWidget::ContainsRoot(TArray<FIntPoint>& points)
|
||||
{
|
||||
return PointsCointainsRoot(points);
|
||||
}
|
||||
|
||||
TArray<FIntPoint> USkillWidget::GetPoints()
|
||||
{
|
||||
TArray<FIntPoint> points;
|
||||
CheckPosition(m_lastGridIndex, &points);
|
||||
return points;
|
||||
}
|
||||
|
||||
bool USkillWidget::PointsCointainsRoot( TArray<FIntPoint>& points )
|
||||
{
|
||||
for ( int32 i = 0; i < points.Num(); i++ )
|
||||
{
|
||||
if ( points[i] == parent->rootPoint ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void USkillWidget::NativeOnSkillMove()
|
||||
{
|
||||
UpdateSkillColor();
|
||||
|
||||
OnMove();
|
||||
}
|
||||
|
||||
void USkillWidget::NativeTick( const FGeometry& geometry, float deltaTime )
|
||||
{
|
||||
FVector2D mousePos;
|
||||
UWidgetLayoutLibrary::GetMousePositionScaledByDPI(GetOwningPlayer(), mousePos.X, mousePos.Y);
|
||||
|
||||
if ( m_dragging && !m_controller )
|
||||
{
|
||||
FVector2D newPos = mousePos + m_offset;
|
||||
|
||||
UCanvasPanelSlot* tmpSlot = Cast<UCanvasPanelSlot>( Slot );
|
||||
if ( tmpSlot )
|
||||
{
|
||||
FVector4 gridresult = GetGridPos( newPos );
|
||||
FVector2D gridPos = FVector2D( gridresult.X, gridresult.Y );
|
||||
FVector2D gridIndex = FVector2D( gridresult.Z, gridresult.W );
|
||||
if(gridPos != m_lastGridPos)
|
||||
{
|
||||
NativeOnSkillMove();
|
||||
m_lastGridPos = gridPos;
|
||||
}
|
||||
}
|
||||
else
|
||||
YWARNING( "Couldn't get Slot." );
|
||||
}
|
||||
else if( !m_dragging )
|
||||
{
|
||||
if (hovered)
|
||||
{
|
||||
ChangeColor(GetShapeTypeColor() * 2.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
ChangeColor(GetShapeTypeColor() * 0.5f);
|
||||
}
|
||||
if(parent->draggingWidget == this)
|
||||
parent->StopDragging(this);
|
||||
}
|
||||
if ( m_selected && m_enabled)
|
||||
{
|
||||
FVector2D mousePos;
|
||||
UWidgetLayoutLibrary::GetMousePositionScaledByDPI( GetOwningPlayer(), mousePos.X, mousePos.Y );
|
||||
FVector2D distanceVect = mousePos - m_mousedownPos;
|
||||
if ( distanceVect.SizeSquared() > 100 )
|
||||
{
|
||||
parent->NewSkill( this );
|
||||
m_selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
UCanvasPanelSlot* tmpSlot = UWidgetLayoutLibrary::SlotAsCanvasSlot(parent->GetCanvas());
|
||||
if (m_dragable)
|
||||
{
|
||||
float scale = 32.0f * (RenderTransform.Scale.X / 2);
|
||||
float XScale = (scale * 1.73205f);
|
||||
float YScale = scale;
|
||||
|
||||
FVector2D topLeft = GetSkillTreePos();
|
||||
FVector2D result;
|
||||
result.X = (m_lastGridIndex.X) * XScale;
|
||||
result.X += topLeft.X;
|
||||
result.Y = (m_lastGridIndex.Y) * YScale;
|
||||
result.Y += topLeft.Y;
|
||||
|
||||
UCanvasPanelSlot* selfSlot = UWidgetLayoutLibrary::SlotAsCanvasSlot(this);
|
||||
if (selfSlot)
|
||||
{
|
||||
selfSlot->SetPosition(result);
|
||||
}
|
||||
}
|
||||
|
||||
Super::NativeTick( geometry, deltaTime );
|
||||
}
|
||||
|
||||
FLinearColor USkillWidget::GetShapeTypeColor() const
|
||||
{
|
||||
if(selectedEffect == -1)
|
||||
return FLinearColor(1.0f, 1.0f, 1.0f) * 1.0f; // Hwhite
|
||||
|
||||
static FLinearColor shapeTypeColors[] =
|
||||
{
|
||||
FLinearColor(0.1f, 1.0f, 0.3f) * 0.75f, // Green
|
||||
FLinearColor(1.0f, 0.3f, 0.1f) * 0.6f, // Red-Ish
|
||||
FLinearColor(0.0f, 0.0f, 1.0f) * 0.6f, // Blue
|
||||
};
|
||||
|
||||
int32 idx = 0;
|
||||
if(skillAsset)
|
||||
{
|
||||
idx = (int32)skillAsset->abilityEffects[selectedEffect]->abilityCategory;
|
||||
}
|
||||
idx = FMath::Clamp(idx, 0, 2);
|
||||
return FLinearColor(shapeTypeColors[idx].R, shapeTypeColors[idx].G, shapeTypeColors[idx].B, 1.0f);
|
||||
}
|
||||
|
||||
void USkillWidget::SetDragable(bool dragable, bool controller /*= false */)
|
||||
{
|
||||
m_controller = controller;
|
||||
m_dragable = dragable;
|
||||
UpdateSkill();
|
||||
}
|
||||
191
Source/UnrealProject/GUI/SkillTree/SkillWidget.h
Normal file
191
Source/UnrealProject/GUI/SkillTree/SkillWidget.h
Normal file
@@ -0,0 +1,191 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SubMenu.h"
|
||||
#include "SkillWidget.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class UBaseSkillObject;
|
||||
class UBorder;
|
||||
class USkillTreeWidget;
|
||||
class UHexagonTile;
|
||||
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API USkillWidget : public USubMenu
|
||||
{
|
||||
GENERATED_BODY()
|
||||
private:
|
||||
//Variables
|
||||
|
||||
//Skill State
|
||||
bool m_dragable = false;
|
||||
bool m_dragging = false;
|
||||
bool m_selected = false;
|
||||
bool m_enabled = true;
|
||||
bool m_hovering = false;
|
||||
bool m_placed = false;
|
||||
bool m_controller = false;
|
||||
//SKill Widget pointers
|
||||
UCanvasPanelSlot* m_slot;
|
||||
UCanvasPanel* m_canvasPanel;
|
||||
//Positions
|
||||
FVector2D m_mousedownPos;
|
||||
FVector2D m_offset;
|
||||
FVector2D m_lastGridIndex;
|
||||
FVector2D m_lastGridPos;
|
||||
FVector2D m_hexSize;
|
||||
|
||||
UPROPERTY()
|
||||
UTexture2D* m_skillIcon;
|
||||
|
||||
//Hexagons
|
||||
TArray<UHexagonTile*> m_hexagons;
|
||||
float m_power;
|
||||
|
||||
//Functions
|
||||
bool PointsCointainsRoot( TArray<FIntPoint>& points );
|
||||
public:
|
||||
//Variables
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "UI" )
|
||||
UBaseSkillObject* skillAsset;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "UI")
|
||||
USkillTreeWidget* parent;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "UI")
|
||||
bool hovered;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
int32 selectedEffect;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "UI")
|
||||
FVector2D tooltipAreaPosition;
|
||||
UPROPERTY(BlueprintReadWrite, Category = "UI")
|
||||
FVector2D tooltipAreaSize;
|
||||
|
||||
TArray<FIntPoint> placedPoints;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
bool IsUsingController() const { return m_controller; }
|
||||
|
||||
void UpdateSkillColor();
|
||||
void UpdateSkillIcon();
|
||||
|
||||
// Checks if a point is contained in on of the hexagons of this skill
|
||||
bool ContainsPoint(FVector2D screenPoint);
|
||||
// Checks if the mouse is contained within one of the hexagons
|
||||
bool ContainsMouse();
|
||||
|
||||
// Updates the selected effect for this skill widget
|
||||
void SetSelectedEffect(int32 effect);
|
||||
// Return the ability info class selected by this skill widget
|
||||
class UAbilityInfo* GetSelectedEffectAbility() const;
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "UI")
|
||||
void OnRequireSkillEffect();
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "UI")
|
||||
void OnPlaceDone(bool successful);
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "UI")
|
||||
void OnStartDragging();
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "UI")
|
||||
void OnRotate();
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "UI")
|
||||
void OnMove();
|
||||
|
||||
UFUNCTION( BlueprintCallable, Category = "UI" )
|
||||
void Select();
|
||||
UFUNCTION( BlueprintCallable, Category = "UI" )
|
||||
void Release()
|
||||
{
|
||||
m_selected = false;
|
||||
};
|
||||
void Deselect();
|
||||
void Enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
ChangeColor( FLinearColor( 0.1216f, 0.9569f, 1.0f ) );
|
||||
}
|
||||
void Disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
ChangeColor( FLinearColor::Gray );
|
||||
}
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void UpdateSkill();
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
bool GetEnabled()
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
FVector2D GetSkillTreePos();
|
||||
FVector2D GetViewportPos();
|
||||
FVector4 GetGridPos( FVector2D in );
|
||||
FVector2D GetPositionFromIndex(FIntPoint in);
|
||||
bool CheckPosition( FVector2D in, TArray<FIntPoint>* points = NULL );
|
||||
UFUNCTION( BlueprintCallable, Category = "UI" )
|
||||
void StartDragging();
|
||||
UFUNCTION( BlueprintCallable, Category = "UI" )
|
||||
void StopDragging();
|
||||
|
||||
FVector2D GetGridIndex() const
|
||||
{
|
||||
return m_lastGridIndex;
|
||||
}
|
||||
void PlaceOnGridIndex(FVector2D index);
|
||||
void SetPlaced();
|
||||
void NativeOnSkillMove();
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
bool PlaceSkill();
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void Remove();
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
bool RestartDragging();
|
||||
|
||||
FLinearColor GetShapeTypeColor() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void SetDragable( bool dragable, bool controller = false );
|
||||
UFUNCTION( BlueprintCallable, Category = "UI" )
|
||||
bool GetDragable()
|
||||
{
|
||||
return m_dragable;
|
||||
}
|
||||
UFUNCTION( BlueprintCallable, Category = "UI" )
|
||||
bool GetDragging()
|
||||
{
|
||||
return m_dragging;
|
||||
}
|
||||
UFUNCTION( BlueprintCallable, Category = "UI" )
|
||||
void SetSkillRotation( float angle );
|
||||
UFUNCTION( BlueprintCallable, Category = "UI" )
|
||||
float GetSkillRotation()
|
||||
{
|
||||
if ( m_canvasPanel ) return m_canvasPanel->RenderTransform.Angle;
|
||||
else YWARNING("No canvas panel found!");
|
||||
return 0;
|
||||
}
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void MoveSkill(FVector2D offset);
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void MoveSkillAbsolute(FVector2D gridIndex);
|
||||
|
||||
float GetPower()
|
||||
{
|
||||
return m_power;
|
||||
}
|
||||
|
||||
void ChangeColor( FLinearColor color );
|
||||
void UpdateLevel( float level );
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void UpdateInfo( float skilltreeHeight, float skilltreeOffset );
|
||||
bool ContainsRoot(TArray<FIntPoint>& points);
|
||||
TArray<USkillWidget*> ConnectedSkills(TArray<FIntPoint>& points);
|
||||
TArray<FIntPoint> GetPoints();
|
||||
|
||||
virtual void NativeConstruct() override;
|
||||
virtual void NativeDestruct() override;
|
||||
virtual void NativeTick( const FGeometry& geometry, float deltaTime ) override;
|
||||
};
|
||||
65
Source/UnrealProject/GUI/SkillTree/SpellInfo.cpp
Normal file
65
Source/UnrealProject/GUI/SkillTree/SpellInfo.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "DefaultPlayerController.h"
|
||||
|
||||
USpellInfo::USpellInfo(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
showDuration = 1.0f;
|
||||
}
|
||||
|
||||
void USpellInfo::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
|
||||
{
|
||||
m_life -= InDeltaTime;
|
||||
if(m_life <= 0.0f)
|
||||
{
|
||||
RemoveFromParent();
|
||||
}
|
||||
|
||||
Super::NativeTick(MyGeometry, InDeltaTime);
|
||||
}
|
||||
|
||||
void USpellInfo::Set(class UAbilityInfo* info, int32 level, float power, class USpellInfoDisplay* parent)
|
||||
{
|
||||
m_ability = info;
|
||||
m_parent = parent;
|
||||
m_life = showDuration;
|
||||
m_level = level;
|
||||
m_power = power;
|
||||
|
||||
ADefaultPlayerController* pc = Cast<ADefaultPlayerController>(GetOwningPlayer());
|
||||
int32 slot;
|
||||
bool alt;
|
||||
if(pc && pc->GetAbilityButtonLocation(info, slot, alt))
|
||||
{
|
||||
SetButtonHint(slot, alt);
|
||||
}
|
||||
|
||||
int32 lastLevel = pc->GetCurrentAbilityLevel(m_ability);
|
||||
|
||||
OnSetAbility(info, lastLevel == 0);
|
||||
}
|
||||
|
||||
float USpellInfo::GetLifeTimeRate() const
|
||||
{
|
||||
return (float)m_life / (float)showDuration;
|
||||
}
|
||||
|
||||
int32 USpellInfo::GetLevel() const
|
||||
{
|
||||
return m_level;
|
||||
}
|
||||
float USpellInfo::GetPower() const
|
||||
{
|
||||
return m_power;
|
||||
}
|
||||
|
||||
void USpellInfo::SetButtonHint_Implementation(int32 buttonSlot, bool alt)
|
||||
{
|
||||
}
|
||||
|
||||
void USpellInfo::OnSetAbility_Implementation(class UAbilityInfo* info, bool isNew)
|
||||
{
|
||||
}
|
||||
42
Source/UnrealProject/GUI/SkillTree/SpellInfo.h
Normal file
42
Source/UnrealProject/GUI/SkillTree/SpellInfo.h
Normal file
@@ -0,0 +1,42 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "SpellInfo.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API USpellInfo : public UUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
USpellInfo(const FObjectInitializer& init);
|
||||
void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="GUI")
|
||||
void Set(class UAbilityInfo* info, int32 level, float power, class USpellInfoDisplay* parent);
|
||||
UFUNCTION(BlueprintCallable, Category = "GUI")
|
||||
float GetLifeTimeRate() const;
|
||||
UFUNCTION(BlueprintCallable, Category = "Ability")
|
||||
int32 GetLevel() const;
|
||||
UFUNCTION(BlueprintCallable, Category = "Ability")
|
||||
float GetPower() const;
|
||||
|
||||
UFUNCTION(BlueprintNativeEvent)
|
||||
void OnSetAbility(class UAbilityInfo* info, bool isNew);
|
||||
UFUNCTION(BlueprintNativeEvent)
|
||||
void SetButtonHint(int32 buttonSlot, bool alt);
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float showDuration;
|
||||
|
||||
private:
|
||||
UAbilityInfo* m_ability;
|
||||
class USpellInfoDisplay* m_parent;
|
||||
float m_life;
|
||||
int32 m_level;
|
||||
float m_power;
|
||||
};
|
||||
36
Source/UnrealProject/GUI/SkillTree/SpellInfoDisplay.cpp
Normal file
36
Source/UnrealProject/GUI/SkillTree/SpellInfoDisplay.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "SpellInfoDisplay.h"
|
||||
#include "BaseSkillObject.h"
|
||||
#include "SpellInfo.h"
|
||||
|
||||
void USpellInfoDisplay::NativeConstruct()
|
||||
{
|
||||
m_container = Cast<UPanelWidget>(WidgetTree->FindWidget("Container"));
|
||||
}
|
||||
|
||||
void USpellInfoDisplay::OnLevelUp(class ANetworkPlayer* _player, TArray<FIngameSkillTreeSkill> updatedSkills)
|
||||
{
|
||||
if (!m_container)
|
||||
return;
|
||||
|
||||
player = _player;
|
||||
|
||||
for (int32 i = 0; i < updatedSkills.Num(); i++)
|
||||
{
|
||||
USpellInfo* info = CreateWidget<USpellInfo>(GetWorld(), spellInfoClass);
|
||||
UPanelSlot* slot = m_container->AddChild(info);
|
||||
if (Cast<UHorizontalBoxSlot>(slot))
|
||||
{
|
||||
Cast<UHorizontalBoxSlot>(slot)->SetHorizontalAlignment(HAlign_Right);
|
||||
}
|
||||
else if(Cast<UVerticalBoxSlot>(slot))
|
||||
{
|
||||
UVerticalBoxSlot* vslot = Cast<UVerticalBoxSlot>(slot);
|
||||
vslot->SetHorizontalAlignment(HAlign_Left);
|
||||
Cast<UVerticalBoxSlot>(slot)->SetVerticalAlignment(VAlign_Fill);
|
||||
}
|
||||
info->Set(updatedSkills[i].selectedEffect, updatedSkills[i].level, updatedSkills[i].power, this);
|
||||
}
|
||||
}
|
||||
29
Source/UnrealProject/GUI/SkillTree/SpellInfoDisplay.h
Normal file
29
Source/UnrealProject/GUI/SkillTree/SpellInfoDisplay.h
Normal file
@@ -0,0 +1,29 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "IngameSkillTree.h"
|
||||
#include "SpellInfoDisplay.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API USpellInfoDisplay : public UUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
void NativeConstruct() override;
|
||||
void OnLevelUp(class ANetworkPlayer* player, TArray<FIngameSkillTreeSkill> updatedSkills);
|
||||
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
ANetworkPlayer* player;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TSubclassOf<class USpellInfo> spellInfoClass;
|
||||
|
||||
private:
|
||||
UPanelWidget* m_container;
|
||||
};
|
||||
Reference in New Issue
Block a user