diff --git a/components/NavigationComponent.cs b/components/NavigationComponent.cs
index 9323f65..fcd2ff9 100644
--- a/components/NavigationComponent.cs
+++ b/components/NavigationComponent.cs
@@ -7,8 +7,7 @@ using GodotComponentTest.utils;
///
///
-public class NavigationComponent : Spatial
-{
+public class NavigationComponent : Spatial {
public World World { set; get; }
public Vector3 CurrentGoalPositionWorld { get; private set; } = Vector3.Zero;
public float CurrentGoalAngleWorld { get; private set; }
@@ -21,39 +20,29 @@ public class NavigationComponent : Spatial
private List _planningPathWorldNavigationPoints = new();
private List _smoothedPathWorldNavigationPoints = new();
- public override void _Ready()
- {
+ public override void _Ready() {
base._Ready();
_pathWorldNavigationPoints = new List();
}
- public override void _Process(float delta)
- {
+ public override void _Process(float delta) {
Debug.Assert(World != null);
}
- public void PlanSmoothedPath(KinematicBody body, Transform fromTransformWorld, NavigationPoint navigationPoint)
- {
+ public void PlanSmoothedPath(Entity body, Transform fromTransformWorld, NavigationPoint navigationPoint) {
if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)
- && navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation))
- {
+ && navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation)) {
FindPath(body, fromTransformWorld.origin, navigationPoint);
- }
- else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position))
- {
+ } else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)) {
FindPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition);
- }
- else
- {
+ } else {
throw new NotImplementedException();
}
}
- public void FindPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld)
- {
- var fromCell = World.HexGrid.GetHexAt(new Vector2(fromPositionWorld.x, fromPositionWorld.z));
- if (World.HexGrid.GetHexCost(fromCell) == 0)
- {
+ public void FindPath(Entity entity, Vector3 fromPositionWorld, Vector3 toPositionWorld) {
+ HexCell fromCell = World.HexGrid.GetHexAt(new Vector2(fromPositionWorld.x, fromPositionWorld.z));
+ if (World.HexGrid.GetHexCost(fromCell) == 0) {
GD.Print("Invalid starting point for FindPath(): returning empty path.");
_planningPathWorldNavigationPoints = new List();
_planningPathWorldNavigationPoints.Add(new NavigationPoint(fromPositionWorld));
@@ -61,11 +50,10 @@ public class NavigationComponent : Spatial
return;
}
- var toCell = World.HexGrid.GetHexAt(new Vector2(toPositionWorld.x, toPositionWorld.z));
+ HexCell toCell = World.HexGrid.GetHexAt(new Vector2(toPositionWorld.x, toPositionWorld.z));
toCell = World.HexGrid.GetClosestWalkableCell(fromCell, toCell);
- if (World.HexGrid.GetHexCost(toCell) == 0)
- {
+ if (World.HexGrid.GetHexCost(toCell) == 0) {
GD.Print("Invalid target point for FindPath(): returning empty path.");
_planningPathWorldNavigationPoints = new List();
_planningPathWorldNavigationPoints.Add(new NavigationPoint(fromPositionWorld));
@@ -73,12 +61,11 @@ public class NavigationComponent : Spatial
return;
}
- var path = World.HexGrid.FindPath(fromCell, toCell);
+ List path = World.FindPath(entity, fromCell, toCell);
// Generate grid navigation points
_planningPathWorldNavigationPoints = new List();
- foreach (var index in Enumerable.Range(0, path.Count))
- {
+ foreach (int index in Enumerable.Range(0, path.Count)) {
_planningPathWorldNavigationPoints.Add(
new NavigationPoint(World.HexGrid.GetHexCenterVec3FromOffset(path[index].OffsetCoords)));
}
@@ -86,40 +73,38 @@ public class NavigationComponent : Spatial
// Ensure the last point coincides with the target position
if (_planningPathWorldNavigationPoints.Count > 0 &&
(_planningPathWorldNavigationPoints.Last().WorldPosition - toPositionWorld).LengthSquared() <
- 0.5f * 0.5f)
- {
+ 0.5f * 0.5f) {
_planningPathWorldNavigationPoints[_planningPathWorldNavigationPoints.Count - 1].WorldPosition =
toPositionWorld;
}
// Perform smoothing
- _planningPathSmoothedWorldNavigationPoints = SmoothPath(body, _planningPathWorldNavigationPoints);
+ _planningPathSmoothedWorldNavigationPoints = SmoothPath(entity, _planningPathWorldNavigationPoints);
// Ensure starting point is the current position
- if (_planningPathSmoothedWorldNavigationPoints.Count > 0)
- {
+ if (_planningPathSmoothedWorldNavigationPoints.Count > 0) {
_planningPathSmoothedWorldNavigationPoints[0] = new NavigationPoint(fromPositionWorld);
}
}
- public void FindPath(KinematicBody body, Vector3 fromPositionWorld, NavigationPoint navigationPoint)
- {
- FindPath(body, fromPositionWorld, navigationPoint.WorldPosition);
+ public void FindPath(Entity entity, Vector3 fromPositionWorld, NavigationPoint navigationPoint) {
+ FindPath(entity, fromPositionWorld, navigationPoint.WorldPosition);
- _planningPathWorldNavigationPoints[_planningPathWorldNavigationPoints.Count - 1] = navigationPoint;
- _planningPathSmoothedWorldNavigationPoints[_planningPathSmoothedWorldNavigationPoints.Count - 1] =
- navigationPoint;
+ if (_planningPathSmoothedWorldNavigationPoints.Count > 0) {
+ _planningPathWorldNavigationPoints[_planningPathWorldNavigationPoints.Count - 1] = navigationPoint;
+ _planningPathSmoothedWorldNavigationPoints[_planningPathSmoothedWorldNavigationPoints.Count - 1] =
+ navigationPoint;
+ }
}
- public void PlanGridPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld)
- {
- var fromPositionOffset = World.WorldToOffsetCoords(fromPositionWorld);
- var toPositionOffset = World.WorldToOffsetCoords(toPositionWorld);
+ public void PlanGridPath(Entity entity, Vector3 fromPositionWorld, Vector3 toPositionWorld) {
+ Vector2 fromPositionOffset = World.WorldToOffsetCoords(fromPositionWorld);
+ Vector2 toPositionOffset = World.WorldToOffsetCoords(toPositionWorld);
- var fromCell = new HexCell();
+ HexCell fromCell = new();
fromCell.OffsetCoords = fromPositionOffset;
- var toCell = new HexCell();
+ HexCell toCell = new();
toCell.OffsetCoords = toPositionOffset;
_path = fromCell.LineTo(toCell);
@@ -129,26 +114,23 @@ public class NavigationComponent : Spatial
_pathWorldNavigationPoints.Add(
new NavigationPoint(World.HexGrid.GetHexCenterVec3FromOffset(fromPositionOffset)));
- foreach (var index in Enumerable.Range(1, _path.Length - 1))
- {
+ foreach (int index in Enumerable.Range(1, _path.Length - 1)) {
_pathWorldNavigationPoints.Add(
new NavigationPoint(World.GetHexCenterFromOffset(_path[index].OffsetCoords)));
}
if ((fromPositionWorld - World.GetHexCenterFromOffset(toCell.OffsetCoords)).LengthSquared() >
Globals.EpsPositionSquared)
- {
// Remove the last one, because it is only the position rounded to HexGrid coordinates.
- if (_pathWorldNavigationPoints.Count > 0)
- {
+ {
+ if (_pathWorldNavigationPoints.Count > 0) {
_pathWorldNavigationPoints.RemoveAt(_pathWorldNavigationPoints.Count - 1);
}
}
_pathWorldNavigationPoints.Add(new NavigationPoint(toPositionWorld));
- if (_pathWorldNavigationPoints.Count > 2)
- {
- _smoothedPathWorldNavigationPoints = SmoothPath(body, _pathWorldNavigationPoints);
+ if (_pathWorldNavigationPoints.Count > 2) {
+ _smoothedPathWorldNavigationPoints = SmoothPath(entity, _pathWorldNavigationPoints);
_pathWorldNavigationPoints = _smoothedPathWorldNavigationPoints;
}
@@ -156,36 +138,28 @@ public class NavigationComponent : Spatial
}
- public void PlanGridPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld,
- Quat toWorldOrientation)
- {
- PlanGridPath(body, fromPositionWorld, toPositionWorld);
+ public void PlanGridPath(Entity entity, Vector3 fromPositionWorld, Vector3 toPositionWorld,
+ Quat toWorldOrientation) {
+ PlanGridPath(entity, fromPositionWorld, toPositionWorld);
_pathWorldNavigationPoints.Add(new NavigationPoint(toWorldOrientation));
}
- public void PlanGridPath(KinematicBody body, Transform fromTransformWorld, NavigationPoint navigationPoint)
- {
+ public void PlanGridPath(Entity entity, Transform fromTransformWorld, NavigationPoint navigationPoint) {
if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)
- && navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation))
- {
- PlanGridPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition,
+ && navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation)) {
+ PlanGridPath(entity, fromTransformWorld.origin, navigationPoint.WorldPosition,
navigationPoint.WorldOrientation);
- }
- else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position))
- {
- PlanGridPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition);
- }
- else
- {
+ } else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)) {
+ PlanGridPath(entity, fromTransformWorld.origin, navigationPoint.WorldPosition);
+ } else {
throw new NotImplementedException();
}
}
- public void PlanDirectPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld)
- {
+ public void PlanDirectPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld) {
_pathWorldNavigationPoints.Clear();
_pathWorldNavigationPoints.Add(new NavigationPoint(toPositionWorld));
@@ -194,23 +168,20 @@ public class NavigationComponent : Spatial
public void PlanDirectPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld,
- Quat toWorldOrientation)
- {
+ Quat toWorldOrientation) {
PlanDirectPath(body, fromPositionWorld, toPositionWorld);
_pathWorldNavigationPoints.Add(new NavigationPoint(toWorldOrientation));
}
- public bool HasPathCollision(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld)
- {
+ public bool HasPathCollision(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld) {
Vector3 fromPositionLocal = GlobalTransform.XformInv(fromPositionWorld);
Vector3 toPositionLocal = GlobalTransform.XformInv(toPositionWorld);
Vector3 relativeVelocity = GlobalTransform.basis.Xform(toPositionLocal - fromPositionLocal);
KinematicCollision moveCollision = body.MoveAndCollide(relativeVelocity, true, true, true);
- if (moveCollision != null)
- {
+ if (moveCollision != null) {
Spatial colliderSpatial = moveCollision.Collider as Spatial;
// GD.Print("Found collision: " + moveCollision.Collider + " (" + colliderSpatial.Name + ")");
return true;
@@ -220,37 +191,30 @@ public class NavigationComponent : Spatial
}
- public bool CheckSweptTriangleCellCollision(Vector3 startWorld, Vector3 endWorld, float radius)
- {
- Vector2 startPlane = new Vector2(startWorld.x, startWorld.z);
- Vector2 endPlane = new Vector2(endWorld.x, endWorld.z);
+ public bool CheckSweptTriangleCellCollision(Vector3 startWorld, Vector3 endWorld, float radius) {
+ Vector2 startPlane = new(startWorld.x, startWorld.z);
+ Vector2 endPlane = new(endWorld.x, endWorld.z);
Vector2 directionPlane = (endPlane - startPlane).Normalized();
Vector2 sidePlane = directionPlane.Rotated(Mathf.Pi * 0.5f);
List cells =
World.HexGrid.GetCellsForLine(startPlane + directionPlane * radius, endPlane + directionPlane * radius);
- foreach (HexCell cell in cells)
- {
- if (World.HexGrid.GetHexCost(cell) == 0)
- {
+ foreach (HexCell cell in cells) {
+ if (World.HexGrid.GetHexCost(cell) == 0) {
return true;
}
}
cells = World.HexGrid.GetCellsForLine(startPlane + sidePlane * radius, endPlane + sidePlane * radius);
- foreach (HexCell cell in cells)
- {
- if (World.HexGrid.GetHexCost(cell) == 0)
- {
+ foreach (HexCell cell in cells) {
+ if (World.HexGrid.GetHexCost(cell) == 0) {
return true;
}
}
cells = World.HexGrid.GetCellsForLine(startPlane - sidePlane * radius, endPlane - sidePlane * radius);
- foreach (HexCell cell in cells)
- {
- if (World.HexGrid.GetHexCost(cell) == 0)
- {
+ foreach (HexCell cell in cells) {
+ if (World.HexGrid.GetHexCost(cell) == 0) {
return true;
}
}
@@ -258,29 +222,24 @@ public class NavigationComponent : Spatial
return false;
}
- public List SmoothPath(KinematicBody body, List navigationPoints)
- {
- if (navigationPoints.Count <= 2)
- {
+ public List SmoothPath(KinematicBody body, List navigationPoints) {
+ if (navigationPoints.Count <= 2) {
return navigationPoints;
}
Vector3 bodyGlobalTranslation = body.GlobalTranslation;
- List smoothedPath = new List();
+ List smoothedPath = new();
int startIndex = 0;
int endIndex = navigationPoints.Count > 1 ? 1 : 0;
smoothedPath.Add(navigationPoints[startIndex]);
Vector3 startPoint = navigationPoints[startIndex].WorldPosition;
- while (endIndex != navigationPoints.Count)
- {
+ while (endIndex != navigationPoints.Count) {
Vector3 endPoint = navigationPoints[endIndex].WorldPosition;
- if (CheckSweptTriangleCellCollision(startPoint, endPoint, 0.27f))
- {
- if (endIndex - startIndex == 1)
- {
+ if (CheckSweptTriangleCellCollision(startPoint, endPoint, 0.27f)) {
+ if (endIndex - startIndex == 1) {
GD.Print("Aborting SmoothPath: input path passes through collision geometry.");
body.GlobalTranslation = bodyGlobalTranslation;
return smoothedPath;
@@ -294,8 +253,7 @@ public class NavigationComponent : Spatial
continue;
}
- if (endIndex == navigationPoints.Count - 1)
- {
+ if (endIndex == navigationPoints.Count - 1) {
break;
}
@@ -308,34 +266,25 @@ public class NavigationComponent : Spatial
return smoothedPath;
}
- public void PlanDirectPath(KinematicBody body, Transform fromTransformWorld, NavigationPoint navigationPoint)
- {
+ public void PlanDirectPath(KinematicBody body, Transform fromTransformWorld, NavigationPoint navigationPoint) {
if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)
- && navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation))
- {
+ && navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation)) {
PlanDirectPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition,
navigationPoint.WorldOrientation);
- }
- else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position))
- {
+ } else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)) {
PlanDirectPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition);
- }
- else
- {
+ } else {
throw new NotImplementedException();
}
}
- public void ActivatePlannedPath()
- {
+ public void ActivatePlannedPath() {
_pathWorldNavigationPoints = _planningPathSmoothedWorldNavigationPoints;
UpdateCurrentGoal();
}
- private void UpdateCurrentGoal()
- {
- if (_pathWorldNavigationPoints.Count == 0)
- {
+ private void UpdateCurrentGoal() {
+ if (_pathWorldNavigationPoints.Count == 0) {
return;
}
@@ -344,73 +293,56 @@ public class NavigationComponent : Spatial
CurrentGoalAngleWorld = _pathWorldNavigationPoints[0].WorldAngle;
}
- private void ApplyExistingTransform(Transform worldTransform)
- {
- if (_currentGoal.Flags == NavigationPoint.NavigationFlags.Orientation)
- {
+ private void ApplyExistingTransform(Transform worldTransform) {
+ if (_currentGoal.Flags == NavigationPoint.NavigationFlags.Orientation) {
CurrentGoalPositionWorld = worldTransform.origin;
- }
- else if (_currentGoal.Flags == NavigationPoint.NavigationFlags.Position)
- {
+ } else if (_currentGoal.Flags == NavigationPoint.NavigationFlags.Position) {
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(worldTransform);
}
}
- public void UpdateCurrentGoal(Transform currentTransformWorld)
- {
- if (_currentGoal == null)
- {
+ public void UpdateCurrentGoal(Transform currentTransformWorld) {
+ if (_currentGoal == null) {
_currentGoal = new NavigationPoint(currentTransformWorld);
}
- if (_pathWorldNavigationPoints.Count == 0)
- {
+ if (_pathWorldNavigationPoints.Count == 0) {
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
CurrentGoalPositionWorld = currentTransformWorld.origin;
return;
}
- if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Position))
- {
+ if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)) {
CurrentGoalPositionWorld = _pathWorldNavigationPoints[0].WorldPosition;
- }
- else
- {
+ } else {
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
}
- if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation))
- {
+ if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation)) {
CurrentGoalAngleWorld = _currentGoal.WorldAngle;
- }
- else
- {
+ } else {
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
}
- if (_currentGoal.IsReached(currentTransformWorld))
- {
+ if (_currentGoal.IsReached(currentTransformWorld)) {
_pathWorldNavigationPoints.RemoveAt(0);
UpdateCurrentGoal();
ApplyExistingTransform(currentTransformWorld);
}
- if (_pathWorldNavigationPoints.Count == 0)
- {
+ if (_pathWorldNavigationPoints.Count == 0) {
CurrentGoalPositionWorld = currentTransformWorld.origin;
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
}
}
- public bool IsGoalReached()
- {
+ public bool IsGoalReached() {
return _pathWorldNavigationPoints.Count == 0;
}
- public void DebugDraw(Spatial parentNode, DebugGeometry debugGeometry)
- {
+ public void DebugDraw(Spatial parentNode, DebugGeometry debugGeometry) {
Vector3 yOffset = Vector3.Up * 0.1f;
debugGeometry.GlobalTransform = Transform.Identity;
@@ -428,8 +360,7 @@ public class NavigationComponent : Spatial
debugGeometry.PopTransform();
Vector3 previousPoint = parentNode.GlobalTranslation;
- foreach (NavigationPoint point in _pathWorldNavigationPoints)
- {
+ foreach (NavigationPoint point in _pathWorldNavigationPoints) {
debugGeometry.AddVertex(previousPoint + yOffset);
debugGeometry.AddVertex(point.WorldPosition + yOffset);
@@ -437,8 +368,7 @@ public class NavigationComponent : Spatial
}
previousPoint = parentNode.GlobalTranslation;
- foreach (NavigationPoint point in _smoothedPathWorldNavigationPoints)
- {
+ foreach (NavigationPoint point in _smoothedPathWorldNavigationPoints) {
debugGeometry.SetColor(new Color(0, 0, 1));
debugGeometry.AddVertex(previousPoint + yOffset);
debugGeometry.AddVertex(point.WorldPosition + yOffset);
@@ -447,8 +377,7 @@ public class NavigationComponent : Spatial
}
previousPoint = parentNode.GlobalTranslation;
- foreach (NavigationPoint point in _planningPathWorldNavigationPoints)
- {
+ foreach (NavigationPoint point in _planningPathWorldNavigationPoints) {
debugGeometry.SetColor(new Color(1, 0, 1));
debugGeometry.AddVertex(previousPoint + yOffset);
debugGeometry.AddVertex(point.WorldPosition + yOffset);
@@ -457,8 +386,7 @@ public class NavigationComponent : Spatial
}
previousPoint = parentNode.GlobalTranslation;
- foreach (NavigationPoint point in _planningPathSmoothedWorldNavigationPoints)
- {
+ foreach (NavigationPoint point in _planningPathSmoothedWorldNavigationPoints) {
debugGeometry.SetColor(new Color(1, 1, 0));
debugGeometry.AddVertex(previousPoint + yOffset);
debugGeometry.AddVertex(point.WorldPosition + yOffset);
diff --git a/entities/Entity.cs b/entities/Entity.cs
index 3f13a0c..bda848f 100644
--- a/entities/Entity.cs
+++ b/entities/Entity.cs
@@ -1,30 +1,24 @@
using Godot;
-using System;
-public class Entity : KinematicBody
-{
+public class Entity : KinematicBody {
public Vector3 Velocity { get; set; } = Vector3.Zero;
public float RotationalVelocity { get; set; } = 0;
- /** Defines the angle in plane coordinates, 0 => pointing to the right/east, pi/2 pointing up/north, range [-pi,pi]. */
- public float PlaneAngle
- {
+ /**
+ * Defines the angle in plane coordinates, 0 => pointing to the right/east, pi/2 pointing up/north, range [-pi,pi].
+ */
+ public float PlaneAngle {
get => Globals.CalcPlaneAngle(GlobalTransform);
set => GlobalTransform = new Transform(new Basis(Vector3.Up, value + Mathf.Pi * 0.5f), GlobalTranslation);
}
-
- public float CalcShortestPlaneRotationToTargetDirection(Vector3 globalTargetDirection)
- {
+
+ public float CalcShortestPlaneRotationToTargetDirection(Vector3 globalTargetDirection) {
float angleToTarget = Vector3.Right.SignedAngleTo(globalTargetDirection, Vector3.Up);
float currentAngle = PlaneAngle;
float delta = angleToTarget - currentAngle;
-
- delta += (delta > Mathf.Pi) ? -Mathf.Pi * 2 : (delta < -Mathf.Pi) ? Mathf.Pi * 2 : 0;
+
+ delta += delta > Mathf.Pi ? -Mathf.Pi * 2 : delta < -Mathf.Pi ? Mathf.Pi * 2 : 0;
return delta;
}
-
- public override void _Ready()
- {
- }
}
\ No newline at end of file
diff --git a/entities/Tree.cs b/entities/Tree.cs
index 2c8c728..28c0283 100644
--- a/entities/Tree.cs
+++ b/entities/Tree.cs
@@ -4,8 +4,7 @@ using Godot;
using GodotComponentTest.components;
using GodotComponentTest.entities;
-public class Tree : StaticBody, IInteractionInterface
-{
+public class Tree : StaticBody, IInteractionInterface {
[Export] public float ChopDuration = 2;
public bool IsMouseOver;
public InteractionComponent InteractionComponent { get; set; }
@@ -18,9 +17,11 @@ public class Tree : StaticBody, IInteractionInterface
[Signal]
public delegate void EntityClicked(Entity entity);
+ [Signal]
+ public delegate void TreeChopped(Tree entity);
+
// Called when the node enters the scene tree for the first time.
- public override void _Ready()
- {
+ public override void _Ready() {
_geometry = GetNode("Geometry/tree");
Debug.Assert(_geometry != null);
_animationPlayer = GetNode("AnimationPlayer");
@@ -33,56 +34,43 @@ public class Tree : StaticBody, IInteractionInterface
Connect("mouse_exited", this, nameof(OnAreaMouseExited));
}
-
- public override void _Process(float delta)
- {
+ public override void _Process(float delta) {
base._Process(delta);
- if (_isBeingChopped)
- {
+ if (_isBeingChopped) {
_health = Math.Max(0, _health - delta * 100 / ChopDuration);
}
- if (_health == 0)
- {
+ if (_health == 0) {
InteractionComponent.EndInteraction();
InteractionComponent.TargetEntity = null;
- QueueFree();
+ EmitSignal("TreeChopped", this);
}
}
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
- int shapeIndex)
- {
- if (IsMouseOver && inputEvent is InputEventMouseButton)
- {
+ int shapeIndex) {
+ if (IsMouseOver && inputEvent is InputEventMouseButton) {
InputEventMouseButton mouseButtonEvent = (InputEventMouseButton)inputEvent;
- if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed)
- {
+ if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed) {
EmitSignal("EntityClicked", this);
}
}
}
-
- public void OnAreaMouseEntered()
- {
+ public void OnAreaMouseEntered() {
IsMouseOver = true;
- SpatialMaterial overrideMaterial = new SpatialMaterial();
+ SpatialMaterial overrideMaterial = new();
overrideMaterial.AlbedoColor = new Color(1, 0, 0);
_geometry.MaterialOverride = overrideMaterial;
}
-
- public void OnAreaMouseExited()
- {
+ public void OnAreaMouseExited() {
IsMouseOver = false;
_geometry.MaterialOverride = null;
}
-
- public void OnInteractionStart()
- {
+ public void OnInteractionStart() {
GD.Print("Starting tree animationplayer");
_animationPlayer.CurrentAnimation = "TreeShake";
_animationPlayer.Seek(0);
@@ -90,11 +78,10 @@ public class Tree : StaticBody, IInteractionInterface
_isBeingChopped = true;
}
- public void OnInteractionEnd()
- {
+ public void OnInteractionEnd() {
_animationPlayer.CurrentAnimation = "Idle";
_animationPlayer.Seek(0);
_animationPlayer.Stop();
_isBeingChopped = false;
}
-}
+}
\ No newline at end of file
diff --git a/export_presets.cfg b/export_presets.cfg
index 9ca3e63..08b8d15 100644
--- a/export_presets.cfg
+++ b/export_presets.cfg
@@ -30,7 +30,7 @@ keystore/release="/home/martin/projects/GodotComponentTest/android/keystore/debu
keystore/release_user="androiddebugkey"
keystore/release_password="android"
one_click_deploy/clear_previous_install=true
-version/code=1
+version/code=5
version/name="1.0"
package/unique_name="org.godotengine.$genname"
package/name=""
diff --git a/scenes/World.cs b/scenes/World.cs
index 3d65aca..66e4550 100644
--- a/scenes/World.cs
+++ b/scenes/World.cs
@@ -4,11 +4,10 @@ using System.Diagnostics;
using System.Linq;
using Godot;
using Godot.Collections;
+using Priority_Queue;
-public class World : Spatial
-{
- public enum GenerationState
- {
+public class World : Spatial {
+ public enum GenerationState {
Undefined,
Heightmap,
TileType,
@@ -17,7 +16,7 @@ public class World : Spatial
}
// constants
- public const int ChunkSize = 12;
+ public const int ChunkSize = 14;
public const int NumChunkRows = 3;
public const int NumChunkColumns = NumChunkRows;
private static readonly Color RockColor = new(0.5f, 0.5f, 0.4f);
@@ -27,17 +26,17 @@ public class World : Spatial
private readonly Godot.Collections.Dictionary _cachedWorldChunks;
private readonly List _addedChunkIndices = new();
- private readonly List _unusedWorldChunks = new();
+ private readonly List _deactivatedWorldChunks = new();
private readonly Image _heightmapImage = new();
private readonly List _removedChunkIndices = new();
private readonly Image _tileTypeMapImage = new();
- private int FrameCounter;
// referenced scenes
private readonly PackedScene _worldChunkScene = GD.Load("res://scenes/WorldChunk.tscn");
private List _activeChunkIndices = new();
private Rect2 _centerChunkRect;
+ private readonly List _removedSpatialNodes = new();
// delegate void OnCoordClicked(Vector2 world_pos);
@@ -93,16 +92,14 @@ public class World : Spatial
[Signal]
private delegate void TileHovered(HexTile3D tile3d);
- public World()
- {
+ public World() {
Debug.Assert(ChunkSize % 2 == 0);
_cachedWorldChunks = new Godot.Collections.Dictionary();
}
// Called when the node enters the scene tree for the first time.
- public override void _Ready()
- {
+ public override void _Ready() {
Chunks = (Spatial)FindNode("Chunks");
Debug.Assert(Chunks != null);
@@ -117,19 +114,24 @@ public class World : Spatial
GetNode("Assets").Visible = false;
_rockAssets = new Array();
- foreach (Spatial asset in GetNode("Assets/Rocks").GetChildren()) _rockAssets.Add(asset);
+ foreach (Spatial asset in GetNode("Assets/Rocks").GetChildren()) {
+ _rockAssets.Add(asset);
+ }
_grassAssets = new Array();
- foreach (Spatial asset in GetNode("Assets/Grass").GetChildren()) _grassAssets.Add(asset);
+ foreach (Spatial asset in GetNode("Assets/Grass").GetChildren()) {
+ _grassAssets.Add(asset);
+ }
_treeAssets = new Array();
- foreach (Spatial asset in GetNode("Assets/Trees").GetChildren()) _treeAssets.Add(asset);
+ foreach (Spatial asset in GetNode("Assets/Trees").GetChildren()) {
+ _treeAssets.Add(asset);
+ }
SetCenterPlaneCoord(Vector2.Zero);
}
- public void InitNoiseGenerator()
- {
+ public void InitNoiseGenerator() {
_noiseGenerator = new OpenSimplexNoise();
_noiseGenerator.Seed = Seed;
@@ -139,22 +141,17 @@ public class World : Spatial
_noiseGenerator.Lacunarity = 2;
}
- public WorldChunk GetOrCreateWorldChunk(Vector2 chunkIndex, Color debugColor)
- {
+ public WorldChunk GetOrCreateWorldChunk(Vector2 chunkIndex, Color debugColor) {
WorldChunk chunk;
- if (IsChunkCached(chunkIndex))
+ if (IsChunkCached(chunkIndex)) {
return _cachedWorldChunks[chunkIndex];
-
- if (_unusedWorldChunks.Count > 0)
- {
- chunk = _unusedWorldChunks.First();
- _unusedWorldChunks.RemoveAt(0);
-
- GD.Print("Reusing chunk from former index " + chunk.ChunkIndex + " at new index " + chunkIndex);
}
- else
- {
+
+ if (_deactivatedWorldChunks.Count > 0) {
+ chunk = _deactivatedWorldChunks.First();
+ _deactivatedWorldChunks.RemoveAt(0);
+ } else {
chunk = CreateWorldChunk(chunkIndex, debugColor);
}
@@ -163,14 +160,12 @@ public class World : Spatial
return chunk;
}
- private bool IsChunkCached(Vector2 chunkIndex)
- {
+ private bool IsChunkCached(Vector2 chunkIndex) {
return _cachedWorldChunks.ContainsKey(chunkIndex);
}
- private WorldChunk CreateWorldChunk(Vector2 chunkIndex, Color debugColor)
- {
+ private WorldChunk CreateWorldChunk(Vector2 chunkIndex, Color debugColor) {
WorldChunk result = (WorldChunk)_worldChunkScene.Instance();
Chunks.AddChild(result);
result.Connect("TileClicked", this, nameof(OnTileClicked));
@@ -191,15 +186,16 @@ public class World : Spatial
return result;
}
- private bool IsColorEqualApprox(Color colorA, Color colorB)
- {
+ private bool IsColorEqualApprox(Color colorA, Color colorB) {
Vector3 colorDifference = new(colorA.r - colorB.r, colorA.g - colorB.g, colorA.b - colorB.b);
return colorDifference.LengthSquared() < 0.1 * 0.1;
}
- private Spatial SelectAsset(Vector2 textureCoord, Array assets, Random randomGenerator, double probability)
- {
- if (randomGenerator.NextDouble() < 1.0 - probability) return null;
+ private Spatial SelectAsset(Vector2 textureCoord, Array assets, Random randomGenerator,
+ double probability) {
+ if (randomGenerator.NextDouble() < 1.0 - probability) {
+ return null;
+ }
int assetIndex = randomGenerator.Next(assets.Count);
Spatial assetInstance = (Spatial)assets[assetIndex].Duplicate();
@@ -214,41 +210,40 @@ public class World : Spatial
return assetInstance;
}
- private void PopulateChunk(WorldChunk chunk)
- {
+ private void PopulateChunk(WorldChunk chunk) {
Random environmentRandom = new(Seed);
- Image tileTypeImage = chunk.TileTypeOffscreenViewport.GetTexture().GetData();
- tileTypeImage.Lock();
+ chunk.CreateUnlockedTileTypeImage();
- foreach (int textureCoordU in Enumerable.Range(0, chunk.Size))
- foreach (int textureCoordV in Enumerable.Range(0, chunk.Size))
- {
- Color colorValue = tileTypeImage.GetPixel(textureCoordU, textureCoordV);
- Vector2 textureCoord = new(textureCoordU, textureCoordV);
- Vector2 offsetCoord = chunk.ChunkIndex * ChunkSize + textureCoord;
+ foreach (int textureCoordU in Enumerable.Range(0, chunk.Size)) {
+ foreach (int textureCoordV in Enumerable.Range(0, chunk.Size)) {
+ Color colorValue = chunk.TileTypeImage.GetPixel(textureCoordU, textureCoordV);
+ Vector2 textureCoord = new(textureCoordU, textureCoordV);
+ Vector2 offsetCoord = chunk.ChunkIndex * ChunkSize + textureCoord;
- if (IsColorEqualApprox(colorValue, RockColor))
- {
- Spatial rockAsset = SelectAsset(textureCoord, _rockAssets, environmentRandom, 0.15);
- if (rockAsset != null) chunk.Entities.AddChild(rockAsset);
- // TODO: MarkCellUnwalkable(cell);
- }
- else if (IsColorEqualApprox(colorValue, GrassColor) || IsColorEqualApprox(colorValue, DarkGrassColor))
- {
- Spatial grassAsset = SelectAsset(textureCoord, _grassAssets, environmentRandom, 0.15);
- if (grassAsset != null) chunk.Entities.AddChild(grassAsset);
+ if (IsColorEqualApprox(colorValue, RockColor)) {
+ Spatial rockAsset = SelectAsset(textureCoord, _rockAssets, environmentRandom, 0.15);
+ if (rockAsset != null) {
+ chunk.Entities.AddChild(rockAsset);
+ MarkCellUnwalkable(HexGrid.GetHexAtOffset(offsetCoord));
+ }
+ } else if (IsColorEqualApprox(colorValue, GrassColor) ||
+ IsColorEqualApprox(colorValue, DarkGrassColor)) {
+ Spatial grassAsset = SelectAsset(textureCoord, _grassAssets, environmentRandom, 0.15);
+ if (grassAsset != null) {
+ chunk.Entities.AddChild(grassAsset);
+ }
- Tree treeAsset = SelectAsset(textureCoord, _treeAssets, environmentRandom, 0.05) as Tree;
- if (treeAsset != null)
- {
- chunk.Entities.AddChild(treeAsset);
- treeAsset.Connect("EntityClicked", this, nameof(OnEntityClicked));
- }
+ Tree treeAsset = SelectAsset(textureCoord, _treeAssets, environmentRandom, 0.05) as Tree;
+ if (treeAsset != null) {
+ chunk.Entities.AddChild(treeAsset);
+ treeAsset.Connect("EntityClicked", this, nameof(OnEntityClicked));
+ treeAsset.Connect("TreeChopped", this, nameof(OnBlockingSpatialRemoved));
+ MarkCellUnwalkable(HexGrid.GetHexAtOffset(offsetCoord));
+ }
-
- // TODO: MarkCellUnwalkable(cell);
- // else if (environmentRandom.NextDouble() < 0.01)
+ // TODO: MarkCellUnwalkable(cell);
+ // else if (environmentRandom.NextDouble() < 0.01)
// {
// var chestAsset = (Chest)_chestScene.Instance();
// var assetTransform = Transform.Identity;
@@ -258,36 +253,29 @@ public class World : Spatial
// Entities.AddChild(chestAsset);
// MarkCellUnwalkable(cell);
// }
- }
+ }
// else if (IsColorWater(colorValue))
// {
// MarkCellUnwalkable(cell);
// }
+ }
}
-
- tileTypeImage.Unlock();
}
- public Vector2 WorldToOffsetCoords(Vector3 fromPositionWorld)
- {
+ public Vector2 WorldToOffsetCoords(Vector3 fromPositionWorld) {
return HexGrid.GetHexAt(new Vector2(fromPositionWorld.x, fromPositionWorld.z)).OffsetCoords;
}
- public Vector3 GetHexCenterFromOffset(Vector2 fromPositionOffset)
- {
+ public Vector3 GetHexCenterFromOffset(Vector2 fromPositionOffset) {
return HexGrid.GetHexCenterVec3FromOffset(fromPositionOffset);
}
- public void UpdateCenterChunkFromPlaneCoord(Vector2 planeCoord)
- {
- if (State != GenerationState.Done)
- {
+ public void UpdateCenterChunkFromPlaneCoord(Vector2 planeCoord) {
+ if (State != GenerationState.Done) {
GD.PrintErr("Cannot update chunk to new planeCoord " + planeCoord + ": Chunk generation not yet finished!");
return;
}
- GD.Print("Update Chunks: " + FrameCounter);
-
// mark all chunks as retired
Godot.Collections.Dictionary oldCachedChunks = new(_cachedWorldChunks);
@@ -319,15 +307,16 @@ public class World : Spatial
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(+1, +1));
// clear unused chunks
- _unusedWorldChunks.Clear();
+ _deactivatedWorldChunks.Clear();
_addedChunkIndices.Clear();
- foreach (Vector2 oldChunkIndex in oldCachedChunks.Keys)
- if (!_activeChunkIndices.Contains(oldChunkIndex))
+ foreach (Vector2 oldChunkIndex in oldCachedChunks.Keys) {
+ if (!_activeChunkIndices.Contains(oldChunkIndex)) {
DeactivateChunk(oldCachedChunks[oldChunkIndex]);
+ }
+ }
- foreach (Vector2 activeChunkIndex in _activeChunkIndices)
- {
+ foreach (Vector2 activeChunkIndex in _activeChunkIndices) {
WorldChunk chunk = GetOrCreateWorldChunk(activeChunkIndex,
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
_cachedWorldChunks[activeChunkIndex] = chunk;
@@ -335,34 +324,29 @@ public class World : Spatial
Debug.Assert(_activeChunkIndices.Count == NumChunkRows * NumChunkColumns);
- foreach (Vector2 chunkKey in _activeChunkIndices)
- if (!oldCachedChunks.ContainsKey(chunkKey))
- {
+ foreach (Vector2 chunkKey in _activeChunkIndices) {
+ if (!oldCachedChunks.ContainsKey(chunkKey)) {
ActivateChunk(_cachedWorldChunks[chunkKey], chunkKey);
State = GenerationState.Heightmap;
}
+ }
}
- private void ActivateChunk(WorldChunk chunk, Vector2 chunkIndex)
- {
+ private void ActivateChunk(WorldChunk chunk, Vector2 chunkIndex) {
chunk.SetChunkIndex(chunkIndex, HexGrid);
chunk.UpdateTileTransforms();
_addedChunkIndices.Add(chunk.ChunkIndex);
- GD.Print("Generating noise for chunk " + chunk.ChunkIndex);
GenerateChunkNoiseMap(chunk);
}
- private void DeactivateChunk(WorldChunk chunk)
- {
- GD.Print("Clearing chunk index: " + chunk.ChunkIndex);
+ private void DeactivateChunk(WorldChunk chunk) {
_cachedWorldChunks.Remove(chunk.ChunkIndex);
chunk.ClearContent();
- _unusedWorldChunks.Add(chunk);
+ _deactivatedWorldChunks.Add(chunk);
}
- private void GenerateChunkNoiseMap(WorldChunk chunk)
- {
+ private void GenerateChunkNoiseMap(WorldChunk chunk) {
Vector2 chunkIndex = chunk.ChunkIndex;
ImageTexture noiseImageTexture = new();
@@ -372,27 +356,29 @@ public class World : Spatial
chunk.SetNoisemap(noiseImageTexture);
}
- private void RemoveChunk(Vector2 cachedChunkKey)
- {
+ private void RemoveChunk(Vector2 cachedChunkKey) {
_cachedWorldChunks.Remove(cachedChunkKey);
_removedChunkIndices.Add(cachedChunkKey);
- foreach (WorldChunk chunk in Chunks.GetChildren())
- if (chunk.ChunkIndex == new Vector2(cachedChunkKey.x, cachedChunkKey.y))
+ foreach (WorldChunk chunk in Chunks.GetChildren()) {
+ if (chunk.ChunkIndex == new Vector2(cachedChunkKey.x, cachedChunkKey.y)) {
chunk.QueueFree();
+ }
+ }
}
- private Vector2 GetChunkTupleFromPlaneCoord(Vector2 planeCoord)
- {
- HexCell centerOffsetCoord = HexGrid.GetHexAt(planeCoord);
- return (centerOffsetCoord.OffsetCoords / ChunkSize).Floor();
+ private Vector2 GetChunkTupleFromPlaneCoord(Vector2 planeCoord) {
+ HexCell hexCell = HexGrid.GetHexAt(planeCoord);
+ return GetChunkIndexFromOffsetCoord(hexCell.OffsetCoords);
}
- public void SetCenterPlaneCoord(Vector2 centerPlaneCoord)
- {
- if (!_centerChunkRect.HasPoint(centerPlaneCoord))
- {
+ private Vector2 GetChunkIndexFromOffsetCoord(Vector2 offsetCoord) {
+ return (offsetCoord / ChunkSize).Floor();
+ }
+
+ public void SetCenterPlaneCoord(Vector2 centerPlaneCoord) {
+ if (!_centerChunkRect.HasPoint(centerPlaneCoord)) {
UpdateCenterChunkFromPlaneCoord(centerPlaneCoord);
UpdateChunkBounds();
@@ -401,8 +387,7 @@ public class World : Spatial
}
}
- private void UpdateWorldViewTexture()
- {
+ private void UpdateWorldViewTexture() {
int worldChunkSize = ChunkSize;
int numWorldChunkRows = NumChunkRows;
int numWorldChunkColumns = NumChunkColumns;
@@ -412,8 +397,7 @@ public class World : Spatial
_tileTypeMapImage.Create(worldChunkSize * numWorldChunkColumns, worldChunkSize * numWorldChunkRows, false,
Image.Format.Rgba8);
- foreach (Vector2 chunkIndex in _activeChunkIndices)
- {
+ foreach (Vector2 chunkIndex in _activeChunkIndices) {
WorldChunk worldChunk = GetOrCreateWorldChunk(chunkIndex, Colors.White);
_heightmapImage.BlendRect(
@@ -439,113 +423,207 @@ public class World : Spatial
EmitSignal("OnHeightmapImageChanged", _heightmapImage);
}
- private void UpdateChunkBounds()
- {
+ private void UpdateChunkBounds() {
_chunkIndexSouthWest = Vector2.Inf;
_chunkIndexNorthEast = -Vector2.Inf;
- foreach (Vector2 chunkIndex in _activeChunkIndices)
- {
- WorldChunk worldChunk = GetOrCreateWorldChunk(chunkIndex, Colors.White);
-
- if (chunkIndex.x <= _chunkIndexSouthWest.x && chunkIndex.y <= _chunkIndexSouthWest.y)
+ foreach (Vector2 chunkIndex in _activeChunkIndices) {
+ if (chunkIndex.x <= _chunkIndexSouthWest.x && chunkIndex.y <= _chunkIndexSouthWest.y) {
_chunkIndexSouthWest = chunkIndex;
- else if (chunkIndex.x >= _chunkIndexNorthEast.x && chunkIndex.y >= _chunkIndexNorthEast.y)
+ } else if (chunkIndex.x >= _chunkIndexNorthEast.x && chunkIndex.y >= _chunkIndexNorthEast.y) {
_chunkIndexNorthEast = chunkIndex;
+ }
}
}
- private void UpdateNavigationBounds()
- {
+ private void UpdateNavigationBounds() {
HexCell cellSouthWest = HexGrid.GetHexAtOffset(_chunkIndexSouthWest * ChunkSize);
- // Chunks have their cells ordered from south west (0,0) to north east (ChunkSize, ChunkSize). For the
- // north east cell we have to add the chunk size to get to the actual corner cell.
- HexCell cellNorthEast =
- HexGrid.GetHexAtOffset(_chunkIndexNorthEast * ChunkSize + Vector2.One * (ChunkSize - 1));
-
- HexCell centerCell =
- HexGrid.GetHexAtOffset(((cellNorthEast.OffsetCoords - cellSouthWest.OffsetCoords) / 2).Round());
- int numCells = ChunkSize * Math.Max(NumChunkColumns, NumChunkRows);
-
HexGrid.SetBoundsOffset(cellSouthWest, ChunkSize * new Vector2(NumChunkColumns, NumChunkRows));
}
- public override void _Process(float delta)
- {
+ public void MarkCellUnwalkable(HexCell cell) {
+ HexGrid.AddObstacle(cell);
+ }
+
+ public float GetHexCost(Entity entity, HexCell cell) {
+ float nextHexCost = HexGrid.GetHexCost(cell);
+ if (nextHexCost != 0) {
+ Vector2 nextOffset = cell.OffsetCoords;
+ Vector2 chunkIndex = GetChunkIndexFromOffsetCoord(nextOffset);
+ WorldChunk chunk = _cachedWorldChunks[chunkIndex];
+ Vector2 textureCoordinate = nextOffset - Vector2.One * ChunkSize * chunkIndex;
+
+ Color tileTypeColor = chunk.TileTypeImage.GetPixel((int)textureCoordinate.x, (int)textureCoordinate.y);
+ if (!IsColorEqualApprox(tileTypeColor, GrassColor) &&
+ !IsColorEqualApprox(tileTypeColor, DarkGrassColor)) {
+ nextHexCost = 0;
+ }
+ }
+
+ return nextHexCost;
+ }
+
+ public float GetMoveCost(Entity entity, HexCell currentHex, HexCell nextHex) {
+ if (GetHexCost(entity, nextHex) == 0) {
+ return 0;
+ }
+
+ return HexGrid.GetMoveCost(currentHex.AxialCoords,
+ new HexCell(nextHex.AxialCoords - currentHex.AxialCoords).CubeCoords);
+ }
+
+ public List FindPath(Entity entity, HexCell startHex, HexCell goalHex) {
+ if (State != GenerationState.Done) {
+ return new List();
+ }
+
+ Vector2 goalAxialCoords = goalHex.AxialCoords;
+
+ SimplePriorityQueue frontier = new();
+ frontier.Enqueue(startHex.AxialCoords, 0);
+ System.Collections.Generic.Dictionary cameFrom = new();
+ System.Collections.Generic.Dictionary costSoFar = new();
+
+ cameFrom.Add(startHex.AxialCoords, startHex.AxialCoords);
+ costSoFar.Add(startHex.AxialCoords, 0);
+
+ int FindPathCheckedCellCount = 0;
+
+ while (frontier.Any()) {
+ FindPathCheckedCellCount++;
+ HexCell currentHex = new(frontier.Dequeue());
+ Vector2 currentAxial = currentHex.AxialCoords;
+
+ if (currentHex == goalHex) {
+ break;
+ }
+
+ foreach (HexCell nextHex in currentHex.GetAllAdjacent()) {
+ Vector2 nextAxial = nextHex.AxialCoords;
+
+ float moveCost = GetMoveCost(entity, currentHex, nextHex);
+
+ if (nextHex == goalHex && moveCost == 0 && GetHexCost(entity, nextHex) == 0) {
+ // Goal ist an obstacle
+ cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
+ frontier.Clear();
+ break;
+ }
+
+ if (moveCost == 0) {
+ continue;
+ }
+
+ moveCost += costSoFar[currentHex.AxialCoords];
+ if (!costSoFar.ContainsKey(nextHex.AxialCoords) || moveCost < costSoFar[nextHex.AxialCoords]) {
+ costSoFar[nextHex.AxialCoords] = moveCost;
+ float priority = moveCost + nextHex.DistanceTo(goalHex);
+
+ frontier.Enqueue(nextHex.AxialCoords, priority);
+ cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
+ }
+ }
+ }
+
+ // GD.Print("Checked Cell Count: " + FindPathCheckedCellCount);
+
+ List result = new();
+ if (!cameFrom.ContainsKey(goalHex.AxialCoords)) {
+ GD.Print("Failed to find path from " + startHex + " to " + goalHex);
+ return result;
+ }
+
+ if (HexGrid.GetHexCost(goalAxialCoords) != 0) {
+ result.Add(goalHex);
+ }
+
+ HexCell pathHex = goalHex;
+ while (pathHex != startHex) {
+ pathHex = new HexCell(cameFrom[pathHex.AxialCoords]);
+ result.Insert(0, pathHex);
+ }
+
+ return result;
+ }
+
+ public override void _Process(float delta) {
GenerationState oldState = State;
UpdateGenerationState();
- if (oldState != GenerationState.Done && State == GenerationState.Done)
+ if (oldState != GenerationState.Done && State == GenerationState.Done) {
UpdateWorldViewTexture();
+ }
+
+ while (_removedSpatialNodes.Count > 0) {
+ GD.Print("Queueing deletion of " + _removedSpatialNodes[0]);
+ _removedSpatialNodes[0].QueueFree();
+ _removedSpatialNodes.RemoveAt(0);
+ }
}
- private void UpdateGenerationState()
- {
- FrameCounter++;
-
- if (State == GenerationState.Heightmap)
- {
+ private void UpdateGenerationState() {
+ if (State == GenerationState.Heightmap) {
int numChunksGeneratingHeightmap = 0;
- foreach (Vector2 chunkIndex in _addedChunkIndices)
- {
+ foreach (Vector2 chunkIndex in _addedChunkIndices) {
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
- if (chunk.HeightMapFrameCount > 0) numChunksGeneratingHeightmap++;
+ if (chunk.HeightMapFrameCount > 0) {
+ numChunksGeneratingHeightmap++;
+ }
}
- if (numChunksGeneratingHeightmap == 0)
- {
+ if (numChunksGeneratingHeightmap == 0) {
// assign height map images
- foreach (Vector2 chunkIndex in _addedChunkIndices)
- {
+ foreach (Vector2 chunkIndex in _addedChunkIndices) {
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
chunk.SetHeightmap(chunk.HeightmapOffscreenViewport.GetTexture());
}
- GD.Print("Switching to TileType Generation: " + FrameCounter);
State = GenerationState.TileType;
}
- }
- else if (State == GenerationState.TileType)
- {
+ } else if (State == GenerationState.TileType) {
int numChunksGeneratingTileType = 0;
- foreach (Vector2 chunkIndex in _addedChunkIndices)
- {
+ foreach (Vector2 chunkIndex in _addedChunkIndices) {
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
- if (chunk.TileTypeMapFrameCount > 0) numChunksGeneratingTileType++;
+ if (chunk.TileTypeMapFrameCount > 0) {
+ numChunksGeneratingTileType++;
+ }
}
- if (numChunksGeneratingTileType == 0)
- {
- GD.Print("Switching to Object Generation: " + FrameCounter);
+ if (numChunksGeneratingTileType == 0) {
State = GenerationState.Objects;
}
- }
- else if (State == GenerationState.Objects)
- {
+ } else if (State == GenerationState.Objects) {
// generate objects
- foreach (Vector2 chunkIndex in _addedChunkIndices)
+ foreach (Vector2 chunkIndex in _addedChunkIndices) {
PopulateChunk(_cachedWorldChunks[chunkIndex]);
+ }
_addedChunkIndices.Clear();
- GD.Print("Generation done: " + FrameCounter);
State = GenerationState.Done;
}
}
- private void OnEntityClicked(Entity entity)
- {
+ private void OnEntityClicked(Entity entity) {
EmitSignal("EntityClicked", entity);
}
- public void OnTileClicked(HexTile3D tile)
- {
+ public void OnTileClicked(HexTile3D tile) {
EmitSignal("TileClicked", tile);
}
- public void OnTileHovered(HexTile3D tile)
- {
+ public void OnTileHovered(HexTile3D tile) {
EmitSignal("TileHovered", tile);
}
+
+ public void OnBlockingSpatialRemoved(Spatial spatialNode) {
+ if (spatialNode.IsQueuedForDeletion()) {
+ return;
+ }
+
+ HexGrid.RemoveObstacle(HexGrid.GetHexAt(new Vector2(spatialNode.GlobalTranslation.x,
+ spatialNode.GlobalTranslation.z)));
+ _removedSpatialNodes.Add(spatialNode);
+ }
}
\ No newline at end of file
diff --git a/scenes/WorldChunk.cs b/scenes/WorldChunk.cs
index 7e06846..8dbcc42 100644
--- a/scenes/WorldChunk.cs
+++ b/scenes/WorldChunk.cs
@@ -3,8 +3,7 @@ using System.Linq;
using Godot;
using Godot.Collections;
-public class WorldChunk : Spatial
-{
+public class WorldChunk : Spatial {
private readonly PackedScene _hexTile3DScene = GD.Load("res://scenes/HexTile3D.tscn");
private MultiMeshInstance _multiMeshInstance;
private readonly Array _tileInstanceIndices = new();
@@ -28,6 +27,7 @@ public class WorldChunk : Spatial
[Export] public Texture HeightMap;
public int HeightMapFrameCount;
+ public Image TileTypeImage;
public Viewport HeightmapOffscreenViewport;
[Export] public Texture NavigationMap;
@@ -56,32 +56,30 @@ public class WorldChunk : Spatial
public int TileTypeMapFrameCount;
public Viewport TileTypeOffscreenViewport;
- public WorldChunk()
- {
- }
+ public WorldChunk() { }
- public WorldChunk(int size)
- {
+ public WorldChunk(int size) {
SetSize(size);
}
[Export]
- public bool ShowTextureOverlay
- {
+ public bool ShowTextureOverlay {
get => _showTextureOverlay;
- set
- {
- if (PlaneRectMesh != null) PlaneRectMesh.Visible = value;
+ set {
+ if (PlaneRectMesh != null) {
+ PlaneRectMesh.Visible = value;
+ }
}
}
// Called when the node enters the scene tree for the first time.
- public override void _Ready()
- {
+ public override void _Ready() {
PlaneRectMesh = (MeshInstance)FindNode("PlaneRectMesh");
Debug.Assert(PlaneRectMesh != null);
- if (PlaneRectMesh.Visible) _showTextureOverlay = true;
+ if (PlaneRectMesh.Visible) {
+ _showTextureOverlay = true;
+ }
Transform planeRectTransform = Transform.Identity;
planeRectTransform =
@@ -116,12 +114,10 @@ public class WorldChunk : Spatial
SetSize(World.ChunkSize);
}
- public void SetSize(int size)
- {
+ public void SetSize(int size) {
Size = size;
- if (TileTypeOffscreenViewport != null)
- {
+ if (TileTypeOffscreenViewport != null) {
TileTypeOffscreenViewport.Size = Vector2.One * size;
HeightmapOffscreenViewport.Size = Vector2.One * size;
_noiseMask.Transform = Transform2D.Identity.Scaled(Vector2.One * size / _noiseMask.Texture.GetSize().x);
@@ -131,8 +127,7 @@ public class WorldChunk : Spatial
}
}
- public void SetChunkIndex(Vector2 chunkIndex, HexGrid hexGrid)
- {
+ public void SetChunkIndex(Vector2 chunkIndex, HexGrid hexGrid) {
ChunkIndex = chunkIndex;
float chunkSize = World.ChunkSize;
@@ -148,49 +143,48 @@ public class WorldChunk : Spatial
new Vector2(localPlaneCoordSouthWest.x, localPlaneCoordNorthEast.y),
new Vector2(localPlaneCoordNorthEast.x - localPlaneCoordSouthWest.x,
localPlaneCoordSouthWest.y - localPlaneCoordNorthEast.y)
- );
+ );
}
public void InitializeTileInstances(Vector2 chunkIndex, MultiMeshInstance multiMeshInstance,
- int tileInstanceIndexStart)
- {
+ int tileInstanceIndexStart) {
_multiMeshInstance = multiMeshInstance;
_tileInstanceIndices.Clear();
int chunkSize = World.ChunkSize;
- foreach (Spatial node in Tiles.GetChildren())
+ foreach (Spatial node in Tiles.GetChildren()) {
node.QueueFree();
+ }
- foreach (int i in Enumerable.Range(0, chunkSize))
- foreach (int j in Enumerable.Range(0, chunkSize))
- {
- HexTile3D tile3D = (HexTile3D)_hexTile3DScene.Instance();
- tile3D.Connect("TileClicked", this, nameof(OnTileClicked));
- tile3D.Connect("TileHovered", this, nameof(OnTileHovered));
+ foreach (int i in Enumerable.Range(0, chunkSize)) {
+ foreach (int j in Enumerable.Range(0, chunkSize)) {
+ HexTile3D tile3D = (HexTile3D)_hexTile3DScene.Instance();
+ tile3D.Connect("TileClicked", this, nameof(OnTileClicked));
+ tile3D.Connect("TileHovered", this, nameof(OnTileHovered));
- tile3D.Cell.OffsetCoords = new Vector2(chunkIndex * World.ChunkSize + new Vector2(i, j));
- _tileInstanceIndices.Add(tileInstanceIndexStart + _tileInstanceIndices.Count);
+ tile3D.Cell.OffsetCoords = new Vector2(chunkIndex * World.ChunkSize + new Vector2(i, j));
+ _tileInstanceIndices.Add(tileInstanceIndexStart + _tileInstanceIndices.Count);
- Transform tileTransform = Transform.Identity;
- Vector2 centerPlaneCoord = _hexGrid.GetHexCenterFromOffset(new Vector2(i, j));
- tileTransform.origin = new Vector3(centerPlaneCoord.x, 0, centerPlaneCoord.y);
- tile3D.Transform = tileTransform;
+ Transform tileTransform = Transform.Identity;
+ Vector2 centerPlaneCoord = _hexGrid.GetHexCenterFromOffset(new Vector2(i, j));
+ tileTransform.origin = new Vector3(centerPlaneCoord.x, 0, centerPlaneCoord.y);
+ tile3D.Transform = tileTransform;
- Tiles.AddChild(tile3D);
+ Tiles.AddChild(tile3D);
+ }
}
_multiMeshInstance.Multimesh.VisibleInstanceCount = _multiMeshInstance.Multimesh.InstanceCount;
}
- public void ClearContent()
- {
- foreach (Spatial child in Entities.GetChildren())
+ public void ClearContent() {
+ foreach (Spatial child in Entities.GetChildren()) {
child.QueueFree();
+ }
}
- public void UpdateTileTransforms()
- {
+ public void UpdateTileTransforms() {
Transform chunkTransform = Transform.Identity;
Vector2 chunkOriginPlaneCoord = _hexGrid.GetHexCenterFromOffset(ChunkIndex * World.ChunkSize);
chunkTransform.origin = new Vector3(chunkOriginPlaneCoord.x, 0, chunkOriginPlaneCoord.y);
@@ -198,10 +192,7 @@ public class WorldChunk : Spatial
Basis tileOrientation = new(Vector3.Up, 90f * Mathf.Pi / 180f);
- GD.Print("Updating transforms for instances of chunk " + ChunkIndex + " origin: " + chunkTransform.origin);
-
- foreach (int i in Enumerable.Range(0, _tileInstanceIndices.Count))
- {
+ foreach (int i in Enumerable.Range(0, _tileInstanceIndices.Count)) {
int column = i % World.ChunkSize;
int row = i / World.ChunkSize;
@@ -211,17 +202,17 @@ public class WorldChunk : Spatial
Transform hexTransform = new(tileOrientation,
chunkTransform.origin + new Vector3(tilePlaneCoord.x, 0, tilePlaneCoord.y));
- if (_showHexTiles)
+ if (_showHexTiles) {
hexTransform = new Transform(tileOrientation.Scaled(Vector3.One * 0.95f),
hexTransform.origin);
+ }
_multiMeshInstance.Multimesh.SetInstanceTransform(_tileInstanceIndices[i], hexTransform);
}
}
// other members
- public void SaveToFile(string chunkName)
- {
+ public void SaveToFile(string chunkName) {
Image image = new();
image.CreateFromData(Size, Size, false, Image.Format.Rgba8, TileTypeMap.GetData().GetData());
@@ -234,13 +225,10 @@ public class WorldChunk : Spatial
image.SavePng(chunkName + "_heightMap.png");
}
- public void LoadFromFile(string chunkName)
- {
- }
+ public void LoadFromFile(string chunkName) { }
- public void SetNoisemap(Texture texture)
- {
+ public void SetNoisemap(Texture texture) {
_noiseSprite.Texture = texture;
_noiseSprite.Transform =
Transform2D.Identity.Scaled(HeightmapOffscreenViewport.Size / _noiseSprite.Texture.GetSize().x);
@@ -248,8 +236,7 @@ public class WorldChunk : Spatial
HeightMapFrameCount = 1;
}
- public void SetHeightmap(Texture texture)
- {
+ public void SetHeightmap(Texture texture) {
_heightmapSprite.Texture = texture;
_heightmapSprite.Transform =
Transform2D.Identity.Scaled(TileTypeOffscreenViewport.Size / _heightmapSprite.Texture.GetSize());
@@ -258,25 +245,29 @@ public class WorldChunk : Spatial
TileTypeMapFrameCount = 1;
}
- public override void _Process(float delta)
- {
+ public void CreateUnlockedTileTypeImage() {
+ TileTypeImage = TileTypeOffscreenViewport.GetTexture().GetData();
+ TileTypeImage.Lock();
+ }
+
+ public override void _Process(float delta) {
Texture tileTypeTexture = TileTypeOffscreenViewport.GetTexture();
- if (NoiseTextureCheckerboardOverlay)
- {
+ if (NoiseTextureCheckerboardOverlay) {
Image tileTypeImage = tileTypeTexture.GetData();
tileTypeImage.Lock();
- foreach (int i in Enumerable.Range(0, Size))
- foreach (int j in Enumerable.Range(0, Size))
- {
- Vector2 textureCoord = new(i, j);
- Color baseColor = tileTypeImage.GetPixelv(textureCoord);
+ foreach (int i in Enumerable.Range(0, Size)) {
+ foreach (int j in Enumerable.Range(0, Size)) {
+ Vector2 textureCoord = new(i, j);
+ Color baseColor = tileTypeImage.GetPixelv(textureCoord);
- if ((i + j) % 2 == 0)
- tileTypeImage.SetPixelv(textureCoord, baseColor);
- else
- tileTypeImage.SetPixelv(textureCoord, baseColor * 0.6f);
+ if ((i + j) % 2 == 0) {
+ tileTypeImage.SetPixelv(textureCoord, baseColor);
+ } else {
+ tileTypeImage.SetPixelv(textureCoord, baseColor * 0.6f);
+ }
+ }
}
tileTypeImage.Unlock();
@@ -295,24 +286,26 @@ public class WorldChunk : Spatial
//RectMaterial.Uv1Triplanar = true;
PlaneRectMesh.SetSurfaceMaterial(0, _rectMaterial);
- if (HeightMapFrameCount == 0) HeightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
+ if (HeightMapFrameCount == 0) {
+ HeightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
+ }
HeightMapFrameCount = HeightMapFrameCount > 0 ? HeightMapFrameCount - 1 : 0;
- if (TileTypeMapFrameCount == 0) TileTypeOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
+ if (TileTypeMapFrameCount == 0) {
+ TileTypeOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
+ }
TileTypeMapFrameCount = TileTypeMapFrameCount > 0 ? TileTypeMapFrameCount - 1 : 0;
PlaneRectMesh.MaterialOverride = null;
}
- public void OnTileClicked(HexTile3D tile)
- {
+ public void OnTileClicked(HexTile3D tile) {
EmitSignal("TileClicked", tile);
}
- public void OnTileHovered(HexTile3D tile)
- {
+ public void OnTileHovered(HexTile3D tile) {
EmitSignal("TileHovered", tile);
}
}
\ No newline at end of file
diff --git a/systems/InteractionSystem.cs b/systems/InteractionSystem.cs
index 01b2710..aa186f8 100644
--- a/systems/InteractionSystem.cs
+++ b/systems/InteractionSystem.cs
@@ -1,84 +1,68 @@
-using Godot;
-using System;
using System.Collections.Generic;
-using Godot.Collections;
+using Godot;
using GodotComponentTest.components;
using GodotComponentTest.entities;
-using Array = System.Array;
using NodePair = System.Tuple;
-public class InteractionSystem : Node
-{
+public class InteractionSystem : Node {
private List _activeInteractions;
// Called when the node enters the scene tree for the first time.
- public override void _Ready()
- {
+ public override void _Ready() {
_activeInteractions = new List();
}
- public override void _Process(float delta)
- {
+ public override void _Process(float delta) {
base._Process(delta);
- List invalidInteractionPairs = new List();
- List endedInteractions = new List();
+ List endedInteractions = new();
- foreach (InteractionComponent interaction in _activeInteractions)
- {
+ foreach (InteractionComponent interaction in _activeInteractions) {
Spatial owningEntity = interaction.OwningEntity;
Spatial targetEntity = interaction.TargetEntity;
- if (owningEntity == null || owningEntity.IsQueuedForDeletion() || targetEntity == null || targetEntity.IsQueuedForDeletion())
- {
+ if (owningEntity == null || owningEntity.IsQueuedForDeletion() || targetEntity == null ||
+ targetEntity.IsQueuedForDeletion()) {
interaction.hasStopped = true;
}
-
- if (interaction.hasStopped)
- {
+
+ if (interaction.hasStopped) {
IInteractionInterface interactableA = owningEntity as IInteractionInterface;
- if (interactableA != null)
- {
+ if (interactableA != null) {
interactableA.OnInteractionEnd();
interactableA.InteractionComponent = null;
}
-
+
IInteractionInterface interactableB = targetEntity as IInteractionInterface;
- if (interactableB != null)
- {
+ if (interactableB != null) {
interactableB.OnInteractionEnd();
interactableB.InteractionComponent = null;
}
-
+
endedInteractions.Add(interaction);
}
}
-
+
foreach (InteractionComponent interaction in endedInteractions)
- {
_activeInteractions.Remove(interaction);
- }
}
- public void OnStartInteraction(Entity owningEntity, Entity targetEntity)
- {
- InteractionComponent interactionComponent = new InteractionComponent();
+ public void OnStartInteraction(Entity owningEntity, Entity targetEntity) {
+ InteractionComponent interactionComponent = new();
interactionComponent.OwningEntity = owningEntity;
interactionComponent.TargetEntity = targetEntity;
-
+
ConnectInteractionSignals(owningEntity, interactionComponent);
ConnectInteractionSignals(targetEntity, interactionComponent);
-
+
interactionComponent.EmitSignal("InteractionStart");
_activeInteractions.Add(interactionComponent);
}
- private static void ConnectInteractionSignals(Entity entity, InteractionComponent interactionComponent)
- {
+ private static void ConnectInteractionSignals(Entity entity, InteractionComponent interactionComponent) {
IInteractionInterface interactable = entity as IInteractionInterface;
- if (interactable != null)
- {
+ if (interactable != null) {
interactable.InteractionComponent = interactionComponent;
interactionComponent.Connect("InteractionStart", entity, nameof(interactable.OnInteractionStart));
interactionComponent.Connect("InteractionEnd", entity, nameof(interactable.OnInteractionEnd));