HAxis sos

This commit is contained in:
guus
2018-08-11 16:46:35 +02:00
commit 510654f8a1
480 changed files with 54126 additions and 0 deletions

View 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");
}
}

View 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;
};

View 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);
}

View 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;
};

View 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;
}
}
}

View 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;
};

View 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;
}
};

View 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);
}
}
*/

View 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;
};

View 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();
}

View 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;
};

View 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)
{
}

View 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;
};

View 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);
}
}

View 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;
};