// 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 widgets; WidgetTree->GetAllWidgets( widgets ); UCanvasPanel* canvasPanel = NULL; FLinearColor color = GetShapeTypeColor(); for ( int32 i = 0; i < widgets.Num(); i++ ) { UHexagonTile* tmp = Cast( widgets[i] ); UCanvasPanel* tmpPanel = Cast( 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( 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("Main_Canvas"); if ( m_dragable ) { //m_spacer->SetVisibility( ESlateVisibility::Hidden ); SetRenderScale( parent->WidgetTree->FindWidget("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( 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("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 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( 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* points) { bool result = true; TArray 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::ConnectedSkills(TArray& points) { //Check if surrounding positions contain another skill. //if ( !PointsCointainsRoot(localPoints)) //{ TArray 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& points) { return PointsCointainsRoot(points); } TArray USkillWidget::GetPoints() { TArray points; CheckPosition(m_lastGridIndex, &points); return points; } bool USkillWidget::PointsCointainsRoot( TArray& 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( 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(); }