Mass reformatting.
parent
2109c6b6ec
commit
bfd5eef2f5
|
@ -1,14 +1,12 @@
|
|||
using Godot;
|
||||
|
||||
public static class Globals
|
||||
{
|
||||
public static class Globals {
|
||||
public const float EpsPosition = 0.01f;
|
||||
public const float EpsPositionSquared = EpsPosition * EpsPosition;
|
||||
public const float EpsRadians = 0.1f * Mathf.Pi / 180f;
|
||||
public const float EpsRadiansSquared = EpsRadians * EpsRadians;
|
||||
|
||||
public static float CalcPlaneAngle(Transform worldTransform)
|
||||
{
|
||||
public static float CalcPlaneAngle(Transform worldTransform) {
|
||||
return worldTransform.basis.x.SignedAngleTo(Vector3.Right.Rotated(Vector3.Up, Mathf.Pi * 0.5f), -Vector3.Up);
|
||||
}
|
||||
}
|
188
HexCell.cs
188
HexCell.cs
|
@ -3,18 +3,24 @@ using System.Linq;
|
|||
using Godot;
|
||||
using GodotComponentTest.utils;
|
||||
|
||||
public class HexCell : IEquatable<HexCell>
|
||||
{
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
public class HexCell : IEquatable<HexCell> {
|
||||
public override bool Equals(object obj) {
|
||||
if (ReferenceEquals(null, obj)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, obj)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj.GetType() != GetType()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Equals((HexCell)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
public override int GetHashCode() {
|
||||
return _cubeCoords.GetHashCode();
|
||||
}
|
||||
|
||||
|
@ -29,8 +35,7 @@ public class HexCell : IEquatable<HexCell>
|
|||
public static readonly Vector3 DIR_SW = new(-1, 0, 1);
|
||||
public static readonly Vector3 DIR_NW = new(-1, 1, 0);
|
||||
|
||||
public static readonly Vector3[] NeighborDirections =
|
||||
{
|
||||
public static readonly Vector3[] NeighborDirections = {
|
||||
DIR_N,
|
||||
DIR_NW,
|
||||
DIR_SW,
|
||||
|
@ -39,13 +44,13 @@ public class HexCell : IEquatable<HexCell>
|
|||
DIR_NE
|
||||
};
|
||||
|
||||
private static readonly Vector2 CornerNW = new Vector2(-Width / 4, -Height / 2);
|
||||
private static readonly Vector2 CornerNE = new Vector2(Width / 4, -Height / 2);
|
||||
private static readonly Vector2 CornerE = new Vector2(Width / 2, 0);
|
||||
private static readonly Vector2 CornerSE = new Vector2(Width / 4, Height / 2);
|
||||
private static readonly Vector2 CornerSW = new Vector2(-Width / 4, Height / 2);
|
||||
private static readonly Vector2 CornerW = new Vector2(-Width / 2, 0);
|
||||
private static readonly Vector2 PlaneNormalN = new Vector2(0, 1);
|
||||
private static readonly Vector2 CornerNW = new(-Width / 4, -Height / 2);
|
||||
private static readonly Vector2 CornerNE = new(Width / 4, -Height / 2);
|
||||
private static readonly Vector2 CornerE = new(Width / 2, 0);
|
||||
private static readonly Vector2 CornerSE = new(Width / 4, Height / 2);
|
||||
private static readonly Vector2 CornerSW = new(-Width / 4, Height / 2);
|
||||
private static readonly Vector2 CornerW = new(-Width / 2, 0);
|
||||
private static readonly Vector2 PlaneNormalN = new(0, 1);
|
||||
|
||||
private static readonly Vector2 PlaneNormalNE =
|
||||
-new Vector2(Mathf.Cos(Mathf.Deg2Rad(30)), -Mathf.Sin(Mathf.Deg2Rad(30)));
|
||||
|
@ -53,76 +58,61 @@ public class HexCell : IEquatable<HexCell>
|
|||
private static readonly Vector2 PlaneNormalSE =
|
||||
-new Vector2(Mathf.Cos(Mathf.Deg2Rad(-30)), -Mathf.Sin(Mathf.Deg2Rad(-30)));
|
||||
|
||||
private static readonly Vector2 PlaneNormalS = new Vector2(0, -1);
|
||||
private static readonly Vector2 PlaneNormalS = new(0, -1);
|
||||
|
||||
private static readonly Vector2 PlaneNormalSW =
|
||||
new Vector2(Mathf.Cos(Mathf.Deg2Rad(30)), -Mathf.Sin(Mathf.Deg2Rad(30)));
|
||||
private static readonly Vector2 PlaneNormalSW = new(Mathf.Cos(Mathf.Deg2Rad(30)), -Mathf.Sin(Mathf.Deg2Rad(30)));
|
||||
|
||||
private static readonly Vector2 PlaneNormalNW =
|
||||
new Vector2(Mathf.Cos(Mathf.Deg2Rad(-30)), -Mathf.Sin(Mathf.Deg2Rad(-30)));
|
||||
private static readonly Vector2 PlaneNormalNW = new(Mathf.Cos(Mathf.Deg2Rad(-30)), -Mathf.Sin(Mathf.Deg2Rad(-30)));
|
||||
|
||||
private static readonly Plane2D[] BoundaryPlanes =
|
||||
{
|
||||
new Plane2D(CornerNE, PlaneNormalN),
|
||||
new Plane2D(CornerNW, PlaneNormalNW),
|
||||
new Plane2D(CornerW, PlaneNormalSW),
|
||||
new Plane2D(CornerSW, PlaneNormalS),
|
||||
new Plane2D(CornerSE, PlaneNormalSE),
|
||||
new Plane2D(CornerE, PlaneNormalNE),
|
||||
private static readonly Plane2D[] BoundaryPlanes = {
|
||||
new(CornerNE, PlaneNormalN),
|
||||
new(CornerNW, PlaneNormalNW),
|
||||
new(CornerW, PlaneNormalSW),
|
||||
new(CornerSW, PlaneNormalS),
|
||||
new(CornerSE, PlaneNormalSE),
|
||||
new(CornerE, PlaneNormalNE)
|
||||
};
|
||||
|
||||
public HexCell()
|
||||
{
|
||||
}
|
||||
public HexCell() { }
|
||||
|
||||
public HexCell(float cubeX, float cubeY, float cubeZ)
|
||||
{
|
||||
public HexCell(float cubeX, float cubeY, float cubeZ) {
|
||||
CubeCoords = RoundCoords(new Vector3(cubeX, cubeY, cubeZ));
|
||||
}
|
||||
|
||||
public virtual bool Equals(HexCell other)
|
||||
{
|
||||
if (other == null)
|
||||
{
|
||||
public virtual bool Equals(HexCell other) {
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return CubeCoords == other.CubeCoords;
|
||||
}
|
||||
|
||||
public static bool operator ==(HexCell cellA, HexCell cellB)
|
||||
{
|
||||
public static bool operator ==(HexCell cellA, HexCell cellB) {
|
||||
return Equals(cellA, cellB);
|
||||
}
|
||||
|
||||
public static bool operator !=(HexCell cellA, HexCell cellB)
|
||||
{
|
||||
public static bool operator !=(HexCell cellA, HexCell cellB) {
|
||||
return !(cellA == cellB);
|
||||
}
|
||||
|
||||
public HexCell(Vector3 cubeCoords)
|
||||
{
|
||||
public HexCell(Vector3 cubeCoords) {
|
||||
CubeCoords = cubeCoords;
|
||||
}
|
||||
|
||||
public HexCell(float axialX, float axialY)
|
||||
{
|
||||
public HexCell(float axialX, float axialY) {
|
||||
AxialCoords = new Vector2(axialX, axialY);
|
||||
}
|
||||
|
||||
public HexCell(Vector2 axialCoords)
|
||||
{
|
||||
public HexCell(Vector2 axialCoords) {
|
||||
AxialCoords = axialCoords;
|
||||
}
|
||||
|
||||
public HexCell(HexCell other)
|
||||
{
|
||||
public HexCell(HexCell other) {
|
||||
CubeCoords = other.CubeCoords;
|
||||
}
|
||||
|
||||
public static HexCell FromOffsetCoords(Vector2 offsetCoords)
|
||||
{
|
||||
HexCell result = new HexCell();
|
||||
public static HexCell FromOffsetCoords(Vector2 offsetCoords) {
|
||||
HexCell result = new();
|
||||
result.OffsetCoords = offsetCoords;
|
||||
|
||||
return result;
|
||||
|
@ -130,13 +120,10 @@ public class HexCell : IEquatable<HexCell>
|
|||
|
||||
private Vector3 _cubeCoords;
|
||||
|
||||
public Vector3 CubeCoords
|
||||
{
|
||||
get { return _cubeCoords; }
|
||||
set
|
||||
{
|
||||
if (Mathf.Abs(value.x + value.y + value.z) > 0.0001)
|
||||
{
|
||||
public Vector3 CubeCoords {
|
||||
get => _cubeCoords;
|
||||
set {
|
||||
if (Mathf.Abs(value.x + value.y + value.z) > 0.0001) {
|
||||
GD.Print("Warning: Invalid cube coordinates for hex (x + y + z != 0): ", value.ToString());
|
||||
}
|
||||
|
||||
|
@ -144,25 +131,21 @@ public class HexCell : IEquatable<HexCell>
|
|||
}
|
||||
}
|
||||
|
||||
public Vector2 AxialCoords
|
||||
{
|
||||
get => new Vector2(CubeCoords.x, CubeCoords.y);
|
||||
public Vector2 AxialCoords {
|
||||
get => new(CubeCoords.x, CubeCoords.y);
|
||||
|
||||
set { CubeCoords = AxialToCubeCoords(value); }
|
||||
set => CubeCoords = AxialToCubeCoords(value);
|
||||
}
|
||||
|
||||
public Vector2 OffsetCoords
|
||||
{
|
||||
get
|
||||
{
|
||||
public Vector2 OffsetCoords {
|
||||
get {
|
||||
int x = (int)CubeCoords.x;
|
||||
int y = (int)CubeCoords.y;
|
||||
int offY = y + (x - (x & 1)) / 2;
|
||||
return new Vector2(x, offY);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
set {
|
||||
int x = (int)value.x;
|
||||
int y = (int)value.y;
|
||||
int cubeY = y - (x - (x & 1)) / 2;
|
||||
|
@ -170,51 +153,40 @@ public class HexCell : IEquatable<HexCell>
|
|||
}
|
||||
}
|
||||
|
||||
public Vector3 AxialToCubeCoords(Vector2 axialCoords)
|
||||
{
|
||||
public Vector3 AxialToCubeCoords(Vector2 axialCoords) {
|
||||
return new Vector3(axialCoords.x, axialCoords.y, -axialCoords.x - axialCoords.y);
|
||||
}
|
||||
|
||||
public Vector3 RoundCoords(Vector2 coords)
|
||||
{
|
||||
public Vector3 RoundCoords(Vector2 coords) {
|
||||
Vector3 cubeCoords = AxialToCubeCoords(coords);
|
||||
|
||||
return RoundCoords(cubeCoords);
|
||||
}
|
||||
|
||||
public Vector3 RoundCoords(Vector3 cubeCoords)
|
||||
{
|
||||
Vector3 rounded = new Vector3(
|
||||
public Vector3 RoundCoords(Vector3 cubeCoords) {
|
||||
Vector3 rounded = new(
|
||||
Mathf.Round(cubeCoords.x),
|
||||
Mathf.Round(cubeCoords.y),
|
||||
Mathf.Round(cubeCoords.z));
|
||||
|
||||
Vector3 diffs = (rounded - cubeCoords).Abs();
|
||||
if (diffs.x > diffs.y && diffs.x > diffs.z)
|
||||
{
|
||||
if (diffs.x > diffs.y && diffs.x > diffs.z) {
|
||||
rounded.x = -rounded.y - rounded.z;
|
||||
}
|
||||
else if (diffs.y > diffs.z)
|
||||
{
|
||||
} else if (diffs.y > diffs.z) {
|
||||
rounded.y = -rounded.x - rounded.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
rounded.z = -rounded.x - rounded.y;
|
||||
}
|
||||
|
||||
return rounded;
|
||||
}
|
||||
|
||||
public HexCell GetAdjacent(Vector3 dir)
|
||||
{
|
||||
return new HexCell(this.CubeCoords + dir);
|
||||
public HexCell GetAdjacent(Vector3 dir) {
|
||||
return new HexCell(CubeCoords + dir);
|
||||
}
|
||||
|
||||
public HexCell[] GetAllAdjacent()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
public HexCell[] GetAllAdjacent() {
|
||||
return new[] {
|
||||
GetAdjacent(DIR_NE),
|
||||
GetAdjacent(DIR_SE),
|
||||
GetAdjacent(DIR_S),
|
||||
|
@ -224,8 +196,7 @@ public class HexCell : IEquatable<HexCell>
|
|||
};
|
||||
}
|
||||
|
||||
public int DistanceTo(HexCell target)
|
||||
{
|
||||
public int DistanceTo(HexCell target) {
|
||||
return (int)(
|
||||
Mathf.Abs(_cubeCoords.x - target.CubeCoords.x)
|
||||
+ Mathf.Abs(_cubeCoords.y - target.CubeCoords.y)
|
||||
|
@ -233,16 +204,14 @@ public class HexCell : IEquatable<HexCell>
|
|||
) / 2;
|
||||
}
|
||||
|
||||
public HexCell[] LineTo(HexCell target)
|
||||
{
|
||||
HexCell nudgedTarget = new HexCell();
|
||||
public HexCell[] LineTo(HexCell target) {
|
||||
HexCell nudgedTarget = new();
|
||||
nudgedTarget.CubeCoords = target.CubeCoords + new Vector3(1.0e-6f, 2.0e-6f, -3.0e-6f);
|
||||
int steps = DistanceTo(target);
|
||||
|
||||
HexCell[] path = new HexCell[steps + 1];
|
||||
|
||||
foreach (int dist in Enumerable.Range(0, steps))
|
||||
{
|
||||
foreach (int dist in Enumerable.Range(0, steps)) {
|
||||
path[dist] = new HexCell();
|
||||
path[dist].CubeCoords = CubeCoords.LinearInterpolate(nudgedTarget.CubeCoords, (float)dist / steps);
|
||||
}
|
||||
|
@ -252,28 +221,23 @@ public class HexCell : IEquatable<HexCell>
|
|||
return path;
|
||||
}
|
||||
|
||||
public void QueryClosestCellBoundary(Vector2 pointLocal, Vector2 dir, out int neighbourIndex, out float distance)
|
||||
{
|
||||
distance = Single.PositiveInfinity;
|
||||
public void QueryClosestCellBoundary(Vector2 pointLocal, Vector2 dir, out int neighbourIndex, out float distance) {
|
||||
distance = float.PositiveInfinity;
|
||||
neighbourIndex = 0;
|
||||
foreach (int i in Enumerable.Range(0, 6))
|
||||
{
|
||||
if (BoundaryPlanes[i].Normal.Dot(dir) >= Plane2D.DistancePrecision)
|
||||
{
|
||||
foreach (int i in Enumerable.Range(0, 6)) {
|
||||
if (BoundaryPlanes[i].Normal.Dot(dir) >= Plane2D.DistancePrecision) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float planeDistance = BoundaryPlanes[i].DistanceToLineSegment(pointLocal, dir);
|
||||
if (planeDistance > Single.NegativeInfinity && planeDistance < distance)
|
||||
{
|
||||
if (planeDistance > float.NegativeInfinity && planeDistance < distance) {
|
||||
distance = planeDistance;
|
||||
neighbourIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public HexCell NextCellAlongLine(Vector2 pointLocal, Vector2 dir)
|
||||
{
|
||||
public HexCell NextCellAlongLine(Vector2 pointLocal, Vector2 dir) {
|
||||
int planeIndex;
|
||||
|
||||
QueryClosestCellBoundary(pointLocal, dir, out planeIndex, out _);
|
||||
|
|
205
HexGrid.cs
205
HexGrid.cs
|
@ -4,8 +4,7 @@ using Godot;
|
|||
using Priority_Queue;
|
||||
using AxialCoordDirectionPair = System.Tuple<Godot.Vector2, Godot.Vector3>;
|
||||
|
||||
public class HexGrid : Resource
|
||||
{
|
||||
public class HexGrid : Resource {
|
||||
private readonly Vector2 _baseHexSize = new(1, Mathf.Sqrt(3) / 2);
|
||||
private Rect2 _boundsAxialCoords = new(-Vector2.Inf, Vector2.Inf);
|
||||
private Rect2 _boundsOffsetCoords = new(-Vector2.Inf, Vector2.Inf);
|
||||
|
@ -24,18 +23,15 @@ public class HexGrid : Resource
|
|||
|
||||
public float PathCostDefault = 1;
|
||||
|
||||
public HexGrid()
|
||||
{
|
||||
public HexGrid() {
|
||||
HexScale = new Vector2(1, 1);
|
||||
}
|
||||
|
||||
public Vector2 HexSize => _hexSize;
|
||||
|
||||
public Vector2 HexScale
|
||||
{
|
||||
public Vector2 HexScale {
|
||||
get => _hexScale;
|
||||
set
|
||||
{
|
||||
set {
|
||||
_hexScale = value;
|
||||
_hexSize = _baseHexSize * _hexScale;
|
||||
_hexTransform = new Transform2D(
|
||||
|
@ -48,135 +44,129 @@ public class HexGrid : Resource
|
|||
}
|
||||
}
|
||||
|
||||
public Vector2 GetHexCenter(HexCell cell)
|
||||
{
|
||||
public Vector2 GetHexCenter(HexCell cell) {
|
||||
return _hexTransform * cell.AxialCoords;
|
||||
}
|
||||
|
||||
public Vector2 GetHexCenterFromOffset(Vector2 offsetCoord)
|
||||
{
|
||||
var cell = new HexCell();
|
||||
public Vector2 GetHexCenterFromOffset(Vector2 offsetCoord) {
|
||||
HexCell cell = new HexCell();
|
||||
cell.OffsetCoords = offsetCoord;
|
||||
return GetHexCenter(cell);
|
||||
}
|
||||
|
||||
public Vector3 GetHexCenterVec3FromOffset(Vector2 offsetCoord)
|
||||
{
|
||||
var cell = new HexCell();
|
||||
public Vector3 GetHexCenterVec3FromOffset(Vector2 offsetCoord) {
|
||||
HexCell cell = new HexCell();
|
||||
cell.OffsetCoords = offsetCoord;
|
||||
var hexCenter = GetHexCenter(cell);
|
||||
Vector2 hexCenter = GetHexCenter(cell);
|
||||
return new Vector3(hexCenter.x, 0, hexCenter.y);
|
||||
}
|
||||
|
||||
public HexCell GetHexAtOffset(Vector2 offsetCoord)
|
||||
{
|
||||
var cell = new HexCell();
|
||||
public HexCell GetHexAtOffset(Vector2 offsetCoord) {
|
||||
HexCell cell = new HexCell();
|
||||
cell.OffsetCoords = offsetCoord;
|
||||
return cell;
|
||||
}
|
||||
|
||||
public HexCell GetHexAt(Vector2 planeCoord)
|
||||
{
|
||||
var result = new HexCell(_hexTransformInv * planeCoord);
|
||||
public HexCell GetHexAt(Vector2 planeCoord) {
|
||||
HexCell result = new HexCell(_hexTransformInv * planeCoord);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SetBounds(Vector2 minAxial, Vector2 maxAxial)
|
||||
{
|
||||
public void SetBounds(Vector2 minAxial, Vector2 maxAxial) {
|
||||
SetBounds(new HexCell(minAxial), new HexCell(maxAxial));
|
||||
}
|
||||
|
||||
public void SetBounds(HexCell minCell, HexCell maxCell)
|
||||
{
|
||||
public void SetBounds(HexCell minCell, HexCell maxCell) {
|
||||
_minCoords = minCell;
|
||||
_maxCoords = maxCell;
|
||||
_boundsAxialCoords = new Rect2(_minCoords.AxialCoords,
|
||||
_maxCoords.AxialCoords - _minCoords.AxialCoords + Vector2.One);
|
||||
}
|
||||
|
||||
public void SetBounds(HexCell center, int size)
|
||||
{
|
||||
var centerOffset = center.OffsetCoords;
|
||||
public void SetBounds(HexCell center, int size) {
|
||||
Vector2 centerOffset = center.OffsetCoords;
|
||||
SetBounds(GetHexAtOffset(centerOffset - Vector2.One * size / 2),
|
||||
GetHexAtOffset(centerOffset + Vector2.One * size / 2));
|
||||
}
|
||||
|
||||
public void SetBoundsOffset(HexCell cellSouthEast, Vector2 size)
|
||||
{
|
||||
public void SetBoundsOffset(HexCell cellSouthEast, Vector2 size) {
|
||||
_boundsOffsetCoords = new Rect2(cellSouthEast.OffsetCoords, size);
|
||||
_boundsAxialCoords = new Rect2(-Vector2.Inf, Vector2.Inf);
|
||||
}
|
||||
|
||||
public void AddObstacle(Vector2 axialCoords, float cost = 0)
|
||||
{
|
||||
public void AddObstacle(Vector2 axialCoords, float cost = 0) {
|
||||
AddObstacle(new HexCell(axialCoords), cost);
|
||||
}
|
||||
|
||||
public void AddObstacle(HexCell cell, float cost = 0)
|
||||
{
|
||||
public void AddObstacle(HexCell cell, float cost = 0) {
|
||||
Obstacles[cell.AxialCoords] = cost;
|
||||
}
|
||||
|
||||
public void RemoveObstacle(HexCell cell)
|
||||
{
|
||||
public void RemoveObstacle(HexCell cell) {
|
||||
Obstacles.Remove(cell.AxialCoords);
|
||||
}
|
||||
|
||||
|
||||
public void AddBarrier(Vector2 axialCoords, Vector3 directionCube, float cost = 0)
|
||||
{
|
||||
public void AddBarrier(Vector2 axialCoords, Vector3 directionCube, float cost = 0) {
|
||||
AddBarrier(new HexCell(axialCoords), directionCube, cost);
|
||||
}
|
||||
|
||||
public void AddBarrier(HexCell cell, Vector3 directionCube, float cost = 0)
|
||||
{
|
||||
public void AddBarrier(HexCell cell, Vector3 directionCube, float cost = 0) {
|
||||
Barriers.Add((cell.AxialCoords, directionCube), cost);
|
||||
}
|
||||
|
||||
public void RemoveBarrier(HexCell cell, Vector3 directionCube)
|
||||
{
|
||||
if (Barriers.ContainsKey((cell.AxialCoords, directionCube))) Barriers.Remove((cell.AxialCoords, directionCube));
|
||||
public void RemoveBarrier(HexCell cell, Vector3 directionCube) {
|
||||
if (Barriers.ContainsKey((cell.AxialCoords, directionCube))) {
|
||||
Barriers.Remove((cell.AxialCoords, directionCube));
|
||||
}
|
||||
}
|
||||
|
||||
public float GetHexCost(HexCell cell)
|
||||
{
|
||||
public float GetHexCost(HexCell cell) {
|
||||
return GetHexCost(cell.AxialCoords);
|
||||
}
|
||||
|
||||
public float GetHexCost(Vector2 axialCoords)
|
||||
{
|
||||
if (!_boundsAxialCoords.HasPoint(axialCoords)) return 0;
|
||||
public float GetHexCost(Vector2 axialCoords) {
|
||||
if (!_boundsAxialCoords.HasPoint(axialCoords)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_boundsOffsetCoords.HasPoint(new HexCell(axialCoords).OffsetCoords)) return 0;
|
||||
if (!_boundsOffsetCoords.HasPoint(new HexCell(axialCoords).OffsetCoords)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float value;
|
||||
return Obstacles.TryGetValue(axialCoords, out value) ? value : PathCostDefault;
|
||||
}
|
||||
|
||||
public float GetMoveCost(Vector2 axialCoords, Vector3 directionCube)
|
||||
{
|
||||
var startCell = new HexCell(axialCoords);
|
||||
var targetCell = new HexCell(startCell.CubeCoords + directionCube);
|
||||
public float GetMoveCost(Vector2 axialCoords, Vector3 directionCube) {
|
||||
HexCell startCell = new HexCell(axialCoords);
|
||||
HexCell targetCell = new HexCell(startCell.CubeCoords + directionCube);
|
||||
|
||||
var cost = GetHexCost(axialCoords);
|
||||
if (cost == 0) return 0;
|
||||
float cost = GetHexCost(axialCoords);
|
||||
if (cost == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cost = GetHexCost(targetCell.AxialCoords);
|
||||
if (cost == 0) return 0;
|
||||
if (cost == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float barrierCost;
|
||||
if (Barriers.ContainsKey((axialCoords, directionCube)))
|
||||
{
|
||||
if (Barriers.ContainsKey((axialCoords, directionCube))) {
|
||||
barrierCost = Barriers[(axialCoords, directionCube)];
|
||||
if (barrierCost == 0) return 0;
|
||||
if (barrierCost == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cost += barrierCost;
|
||||
}
|
||||
|
||||
if (Barriers.ContainsKey((targetCell.AxialCoords, -directionCube)))
|
||||
{
|
||||
if (Barriers.ContainsKey((targetCell.AxialCoords, -directionCube))) {
|
||||
barrierCost = Barriers[(targetCell.AxialCoords, -directionCube)];
|
||||
if (barrierCost == 0) return 0;
|
||||
if (barrierCost == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cost += barrierCost;
|
||||
}
|
||||
|
@ -185,32 +175,29 @@ public class HexGrid : Resource
|
|||
}
|
||||
|
||||
|
||||
public HexCell GetClosestWalkableCell(HexCell fromCell, HexCell toCell)
|
||||
{
|
||||
if (GetHexCost(toCell) == 0)
|
||||
{
|
||||
var line = fromCell.LineTo(toCell);
|
||||
public HexCell GetClosestWalkableCell(HexCell fromCell, HexCell toCell) {
|
||||
if (GetHexCost(toCell) == 0) {
|
||||
HexCell[] line = fromCell.LineTo(toCell);
|
||||
|
||||
foreach (var i in Enumerable.Range(1, line.Length))
|
||||
if (GetHexCost(line[i]) == 0)
|
||||
{
|
||||
foreach (int i in Enumerable.Range(1, line.Length)) {
|
||||
if (GetHexCost(line[i]) == 0) {
|
||||
toCell = line[i - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return toCell;
|
||||
}
|
||||
|
||||
public List<HexCell> FindPath(HexCell startHex, HexCell goalHex)
|
||||
{
|
||||
var goalAxialCoords = goalHex.AxialCoords;
|
||||
public List<HexCell> FindPath(HexCell startHex, HexCell goalHex) {
|
||||
Vector2 goalAxialCoords = goalHex.AxialCoords;
|
||||
|
||||
var frontier = new SimplePriorityQueue<Vector2, float>();
|
||||
SimplePriorityQueue<Vector2, float> frontier = new SimplePriorityQueue<Vector2, float>();
|
||||
frontier.Enqueue(startHex.AxialCoords, 0);
|
||||
var cameFrom =
|
||||
Dictionary<Vector2, Vector2> cameFrom =
|
||||
new Dictionary<Vector2, Vector2>();
|
||||
var costSoFar =
|
||||
Dictionary<Vector2, float> costSoFar =
|
||||
new Dictionary<Vector2, float>();
|
||||
|
||||
cameFrom.Add(startHex.AxialCoords, startHex.AxialCoords);
|
||||
|
@ -218,34 +205,34 @@ public class HexGrid : Resource
|
|||
|
||||
FindPathCheckedCellCount = 0;
|
||||
|
||||
while (frontier.Any())
|
||||
{
|
||||
while (frontier.Any()) {
|
||||
FindPathCheckedCellCount++;
|
||||
var currentHex = new HexCell(frontier.Dequeue());
|
||||
var currentAxial = currentHex.AxialCoords;
|
||||
HexCell currentHex = new HexCell(frontier.Dequeue());
|
||||
Vector2 currentAxial = currentHex.AxialCoords;
|
||||
|
||||
if (currentHex == goalHex) break;
|
||||
if (currentHex == goalHex) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var nextHex in currentHex.GetAllAdjacent())
|
||||
{
|
||||
var nextAxial = nextHex.AxialCoords;
|
||||
var nextCost = GetMoveCost(currentAxial, new HexCell(nextAxial - currentHex.AxialCoords).CubeCoords);
|
||||
foreach (HexCell nextHex in currentHex.GetAllAdjacent()) {
|
||||
Vector2 nextAxial = nextHex.AxialCoords;
|
||||
float nextCost = GetMoveCost(currentAxial, new HexCell(nextAxial - currentHex.AxialCoords).CubeCoords);
|
||||
|
||||
if (nextHex == goalHex && GetHexCost(nextAxial) == 0)
|
||||
{
|
||||
if (nextHex == goalHex && GetHexCost(nextAxial) == 0) {
|
||||
// Goal ist an obstacle
|
||||
cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
|
||||
frontier.Clear();
|
||||
break;
|
||||
}
|
||||
|
||||
if (nextCost == 0) continue;
|
||||
if (nextCost == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nextCost += costSoFar[currentHex.AxialCoords];
|
||||
if (!costSoFar.ContainsKey(nextHex.AxialCoords) || nextCost < costSoFar[nextHex.AxialCoords])
|
||||
{
|
||||
if (!costSoFar.ContainsKey(nextHex.AxialCoords) || nextCost < costSoFar[nextHex.AxialCoords]) {
|
||||
costSoFar[nextHex.AxialCoords] = nextCost;
|
||||
var priority = nextCost + nextHex.DistanceTo(goalHex);
|
||||
float priority = nextCost + nextHex.DistanceTo(goalHex);
|
||||
|
||||
frontier.Enqueue(nextHex.AxialCoords, priority);
|
||||
cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
|
||||
|
@ -255,18 +242,18 @@ public class HexGrid : Resource
|
|||
|
||||
// GD.Print("Checked Cell Count: " + FindPathCheckedCellCount);
|
||||
|
||||
var result = new List<HexCell>();
|
||||
if (!cameFrom.ContainsKey(goalHex.AxialCoords))
|
||||
{
|
||||
List<HexCell> result = new List<HexCell>();
|
||||
if (!cameFrom.ContainsKey(goalHex.AxialCoords)) {
|
||||
GD.Print("Failed to find path from " + startHex + " to " + goalHex);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (GetHexCost(goalAxialCoords) != 0) result.Add(goalHex);
|
||||
if (GetHexCost(goalAxialCoords) != 0) {
|
||||
result.Add(goalHex);
|
||||
}
|
||||
|
||||
var pathHex = goalHex;
|
||||
while (pathHex != startHex)
|
||||
{
|
||||
HexCell pathHex = goalHex;
|
||||
while (pathHex != startHex) {
|
||||
pathHex = new HexCell(cameFrom[pathHex.AxialCoords]);
|
||||
result.Insert(0, pathHex);
|
||||
}
|
||||
|
@ -275,22 +262,20 @@ public class HexGrid : Resource
|
|||
}
|
||||
|
||||
|
||||
public List<HexCell> GetCellsForLine(Vector2 fromPlane, Vector2 toPlane)
|
||||
{
|
||||
var result = new List<HexCell>();
|
||||
public List<HexCell> GetCellsForLine(Vector2 fromPlane, Vector2 toPlane) {
|
||||
List<HexCell> result = new List<HexCell>();
|
||||
|
||||
var distance = (toPlane - fromPlane).Length();
|
||||
var direction = (toPlane - fromPlane) / distance;
|
||||
float distance = (toPlane - fromPlane).Length();
|
||||
Vector2 direction = (toPlane - fromPlane) / distance;
|
||||
|
||||
var currentPointPlane = fromPlane;
|
||||
var currentCell = GetHexAt(currentPointPlane);
|
||||
Vector2 currentPointPlane = fromPlane;
|
||||
HexCell currentCell = GetHexAt(currentPointPlane);
|
||||
float currentDistance = 0;
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
result.Add(currentCell);
|
||||
GetHexCenter(currentCell);
|
||||
var currentPointLocal = currentPointPlane - GetHexCenter(currentCell);
|
||||
Vector2 currentPointLocal = currentPointPlane - GetHexCenter(currentCell);
|
||||
|
||||
int neighbourIndex;
|
||||
float boundaryPlaneDistance;
|
||||
|
|
|
@ -2,24 +2,21 @@ using System;
|
|||
using Godot;
|
||||
using GoDotLog;
|
||||
|
||||
public class ClickableComponent : Spatial
|
||||
{
|
||||
public class ClickableComponent : Spatial {
|
||||
[Export] public string ClickName = "ClickName";
|
||||
|
||||
[Signal]
|
||||
delegate void Clicked();
|
||||
|
||||
|
||||
public bool IsMouseOver = false;
|
||||
|
||||
// private members
|
||||
private CollisionObject _collisionObject;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_collisionObject = (CollisionObject)FindNode("Area", false);
|
||||
if (_collisionObject == null)
|
||||
{
|
||||
if (_collisionObject == null) {
|
||||
GD.PrintErr("Error: could not find Area for Clickable Component!");
|
||||
return;
|
||||
}
|
||||
|
@ -30,26 +27,21 @@ public class ClickableComponent : Spatial
|
|||
}
|
||||
|
||||
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) {
|
||||
GD.Print("Clicked on Clickable Component!");
|
||||
EmitSignal("Clicked", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAreaMouseEntered()
|
||||
{
|
||||
public void OnAreaMouseEntered() {
|
||||
IsMouseOver = true;
|
||||
}
|
||||
|
||||
public void OnAreaMouseExited()
|
||||
{
|
||||
public void OnAreaMouseExited() {
|
||||
IsMouseOver = false;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,3 @@
|
|||
using Godot;
|
||||
|
||||
public class Component : Node
|
||||
{
|
||||
|
||||
}
|
||||
public class Component : Node { }
|
|
@ -2,8 +2,7 @@ using Godot;
|
|||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public class GroundMotionComponent : Component
|
||||
{
|
||||
public class GroundMotionComponent : Component {
|
||||
public float Accel = 50;
|
||||
public float Damping = 0.2f;
|
||||
public Vector3 DirectionToTarget = Vector3.Zero;
|
||||
|
@ -14,29 +13,21 @@ public class GroundMotionComponent : Component
|
|||
public float TargetAngle;
|
||||
public float TargetDeltaAngle;
|
||||
|
||||
private void CalcAndApplyOrientation(float delta, Entity entity, Vector3 targetPosition, float targetAngle)
|
||||
{
|
||||
private void CalcAndApplyOrientation(float delta, Entity entity, Vector3 targetPosition, float targetAngle) {
|
||||
float deltaAngleAbsolute = Mathf.Abs(TargetDeltaAngle);
|
||||
if (deltaAngleAbsolute > 0.001)
|
||||
{
|
||||
if (RotationSpeedRadPerSecond * delta >= deltaAngleAbsolute)
|
||||
{
|
||||
if (deltaAngleAbsolute > 0.001) {
|
||||
if (RotationSpeedRadPerSecond * delta >= deltaAngleAbsolute) {
|
||||
entity.PlaneAngle = TargetAngle;
|
||||
TargetDeltaAngle = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
entity.PlaneAngle += Mathf.Sign(TargetDeltaAngle) * RotationSpeedRadPerSecond * delta;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
TargetDeltaAngle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void CalcPlaneVelocity(float delta, Entity entity, Vector3 targetPosition)
|
||||
{
|
||||
private void CalcPlaneVelocity(float delta, Entity entity, Vector3 targetPosition) {
|
||||
Vector2 planeTargetDirection = new(DirectionToTarget.x, DirectionToTarget.z);
|
||||
|
||||
Vector2 planeVelocity = new(entity.Velocity.x, entity.Velocity.z);
|
||||
|
@ -44,29 +35,25 @@ public class GroundMotionComponent : Component
|
|||
planeVelocity -= planeVelocity * Damping;
|
||||
// GD.Print(" damp : speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
||||
|
||||
if (DistanceToTarget < 0.01)
|
||||
{
|
||||
if (DistanceToTarget < 0.01) {
|
||||
planeVelocity = Vector2.Zero;
|
||||
}
|
||||
else if (TargetDeltaAngle == 0.0)
|
||||
{
|
||||
} else if (TargetDeltaAngle == 0.0) {
|
||||
planeVelocity = planeVelocity.Length() * planeTargetDirection + planeTargetDirection * Accel * delta;
|
||||
// GD.Print(" accel: speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
||||
|
||||
float projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
|
||||
// GD.Print(" Projected step: " + projectedStep + " Speed: " + planeVelocity.Length() + " delta: " + delta);
|
||||
if (projectedStep > DistanceToTarget)
|
||||
{
|
||||
if (projectedStep > DistanceToTarget) {
|
||||
planeVelocity *= DistanceToTarget / projectedStep;
|
||||
projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
|
||||
// GD.Print(" corr speed: " + planeVelocity.Length() + " step: " + projectedStep);
|
||||
}
|
||||
|
||||
float planeSpeed = planeVelocity.Length();
|
||||
if (planeSpeed > MaxSpeed) planeVelocity *= MaxSpeed / planeSpeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (planeSpeed > MaxSpeed) {
|
||||
planeVelocity *= MaxSpeed / planeSpeed;
|
||||
}
|
||||
} else {
|
||||
planeVelocity = Vector2.Zero;
|
||||
}
|
||||
|
||||
|
@ -74,22 +61,19 @@ public class GroundMotionComponent : Component
|
|||
}
|
||||
|
||||
|
||||
private void CalcVerticalVelocity(float delta, Entity entity, TileWorld tileWorld)
|
||||
{
|
||||
private void CalcVerticalVelocity(float delta, Entity entity, TileWorld tileWorld) {
|
||||
Vector3 entityVelocity = entity.Velocity;
|
||||
|
||||
Vector2 currentTile = tileWorld.WorldToOffsetCoords(entity.GlobalTransform.origin);
|
||||
Vector2 nextTile = tileWorld.WorldToOffsetCoords(entity.GlobalTransform.origin + entityVelocity * delta);
|
||||
|
||||
if (nextTile != currentTile)
|
||||
{
|
||||
if (nextTile != currentTile) {
|
||||
float currentHeight = tileWorld.GetHeightAtOffset(currentTile);
|
||||
float nextHeight = tileWorld.GetHeightAtOffset(nextTile);
|
||||
|
||||
bool isOnFloor = entity.IsOnFloor();
|
||||
|
||||
if (nextHeight - entity.GlobalTransform.origin.y > 0.1)
|
||||
{
|
||||
if (nextHeight - entity.GlobalTransform.origin.y > 0.1) {
|
||||
GD.Print("Jump!");
|
||||
entityVelocity.y = 10;
|
||||
|
||||
|
@ -105,32 +89,26 @@ public class GroundMotionComponent : Component
|
|||
}
|
||||
|
||||
public void PhysicsProcess(float delta, Entity entity, Vector3 targetPosition, float targetAngle,
|
||||
World world)
|
||||
{
|
||||
World world) {
|
||||
DirectionToTarget = targetPosition - entity.GlobalTranslation;
|
||||
DirectionToTarget.y = 0;
|
||||
DistanceToTarget = DirectionToTarget.Length();
|
||||
|
||||
if (DistanceToTarget >= Globals.EpsPosition)
|
||||
{
|
||||
if (DistanceToTarget >= Globals.EpsPosition) {
|
||||
DirectionToTarget = DirectionToTarget.Normalized();
|
||||
TargetAngle = Vector3.Right.SignedAngleTo(DirectionToTarget, Vector3.Up);
|
||||
TargetDeltaAngle = entity.CalcShortestPlaneRotationToTargetDirection(DirectionToTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
DirectionToTarget = Vector3.Right;
|
||||
entity.GlobalTranslation = targetPosition;
|
||||
entity.Velocity = new Vector3(0, entity.Velocity.y, 0);
|
||||
|
||||
if (entity.PlaneAngle != targetAngle)
|
||||
{
|
||||
if (entity.PlaneAngle != targetAngle) {
|
||||
Vector3 directionToTarget = Vector3.Right.Rotated(Vector3.Up, targetAngle);
|
||||
TargetAngle = targetAngle;
|
||||
TargetDeltaAngle = entity.CalcShortestPlaneRotationToTargetDirection(directionToTarget);
|
||||
|
||||
if (Mathf.Abs(TargetDeltaAngle) < Globals.EpsRadians)
|
||||
{
|
||||
if (Mathf.Abs(TargetDeltaAngle) < Globals.EpsRadians) {
|
||||
TargetAngle = entity.PlaneAngle;
|
||||
TargetDeltaAngle = 0;
|
||||
|
||||
|
|
|
@ -2,20 +2,18 @@ using Godot;
|
|||
|
||||
namespace GodotComponentTest.components;
|
||||
|
||||
public class InteractionComponent: Component
|
||||
{
|
||||
public class InteractionComponent : Component {
|
||||
[Signal]
|
||||
delegate void InteractionStart(Spatial owningEntity, Spatial targetEntity);
|
||||
|
||||
[Signal]
|
||||
delegate void InteractionEnd(Spatial owningEntity, Spatial targetEntity);
|
||||
private delegate void InteractionStart(Spatial owningEntity, Spatial targetEntity);
|
||||
|
||||
public void EndInteraction()
|
||||
{
|
||||
[Signal]
|
||||
private delegate void InteractionEnd(Spatial owningEntity, Spatial targetEntity);
|
||||
|
||||
public void EndInteraction() {
|
||||
hasStopped = true;
|
||||
}
|
||||
|
||||
public bool hasStopped = false;
|
||||
public bool hasStopped;
|
||||
public Spatial OwningEntity;
|
||||
public Spatial TargetEntity;
|
||||
}
|
|
@ -1,15 +1,13 @@
|
|||
using Godot;
|
||||
using System;
|
||||
|
||||
public class MovableComponent : Component
|
||||
{
|
||||
public class MovableComponent : Component {
|
||||
public Vector3 targetPosition = Vector3.Zero;
|
||||
public Vector3 currentPosition = Vector3.Zero;
|
||||
public Vector3 currentVelocity = Vector3.Zero;
|
||||
|
||||
public float targetAngle = 0;
|
||||
public float currentAngle = 0;
|
||||
public float currentAngularVelocity = 0;
|
||||
public float targetAngle;
|
||||
public float currentAngle;
|
||||
public float currentAngularVelocity;
|
||||
|
||||
[Export] public float maxSpeed = 3;
|
||||
|
||||
|
@ -17,62 +15,55 @@ public class MovableComponent : Component
|
|||
private SpringDamper _angleSpringDamper;
|
||||
|
||||
[Signal]
|
||||
delegate void PositionUpdated(Vector3 newPosition);
|
||||
private delegate void PositionUpdated(Vector3 newPosition);
|
||||
|
||||
[Signal]
|
||||
delegate void OrientationUpdated(float newAngle);
|
||||
private delegate void OrientationUpdated(float newAngle);
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_positionSpringDamper = new SpringDamper(4, 0.99f, 0.5f);
|
||||
_angleSpringDamper = new SpringDamper(4, 0.99f, 0.5f);
|
||||
}
|
||||
|
||||
// Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
public override void _Process(float delta) {
|
||||
Vector3 targetError = targetPosition - currentPosition;
|
||||
|
||||
if (targetError.LengthSquared() > 0.01)
|
||||
{
|
||||
if (targetError.LengthSquared() > 0.01) {
|
||||
Vector3 targetDir = targetError.Normalized();
|
||||
targetAngle = new Vector3(0, 0, 1).SignedAngleTo(targetDir, Vector3.Up);
|
||||
|
||||
if (targetAngle - currentAngle > Mathf.Pi)
|
||||
{
|
||||
if (targetAngle - currentAngle > Mathf.Pi) {
|
||||
currentAngle += 2 * Mathf.Pi;
|
||||
}
|
||||
else if (targetAngle - currentAngle < -Mathf.Pi)
|
||||
{
|
||||
} else if (targetAngle - currentAngle < -Mathf.Pi) {
|
||||
currentAngle -= 2 * Mathf.Pi;
|
||||
}
|
||||
}
|
||||
|
||||
if (Mathf.Abs(currentAngularVelocity) > 0.1 || Mathf.Abs(targetAngle - currentAngle) > 0.01)
|
||||
{
|
||||
var springDamperResult =
|
||||
if (Mathf.Abs(currentAngularVelocity) > 0.1 || Mathf.Abs(targetAngle - currentAngle) > 0.01) {
|
||||
(float, float) springDamperResult =
|
||||
_angleSpringDamper.Calc(currentAngle, currentAngularVelocity, targetAngle, delta);
|
||||
|
||||
currentAngle = springDamperResult.Item1;
|
||||
currentAngularVelocity = springDamperResult.Item2;
|
||||
|
||||
EmitSignal("OrientationUpdated", this.currentAngle);
|
||||
EmitSignal("OrientationUpdated", currentAngle);
|
||||
}
|
||||
|
||||
if ((Mathf.Abs(currentAngularVelocity) < 5 && Mathf.Abs(targetAngle - currentAngle) < 0.3)
|
||||
&& (targetPosition - currentPosition).LengthSquared() > 0.01)
|
||||
{
|
||||
var springDamperResult =
|
||||
if (Mathf.Abs(currentAngularVelocity) < 5 && Mathf.Abs(targetAngle - currentAngle) < 0.3
|
||||
&& (targetPosition - currentPosition).LengthSquared() > 0.01) {
|
||||
(Vector3, Vector3) springDamperResult =
|
||||
_positionSpringDamper.CalcClampedSpeedXZ(currentPosition, currentVelocity, targetPosition, delta,
|
||||
maxSpeed);
|
||||
|
||||
currentPosition = springDamperResult.Item1;
|
||||
currentVelocity = springDamperResult.Item2;
|
||||
}
|
||||
|
||||
currentVelocity.y = currentVelocity.y - 9.81f * delta;
|
||||
currentPosition.y = currentPosition.y + currentVelocity.y * delta;
|
||||
|
||||
|
||||
EmitSignal("PositionUpdated", currentPosition);
|
||||
}
|
||||
}
|
|
@ -1,42 +1,39 @@
|
|||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
public class TaskQueueComponent : Component
|
||||
{
|
||||
public class TaskQueueComponent : Component {
|
||||
[Signal]
|
||||
private delegate void StartInteraction(Entity entity, Entity targetEntity);
|
||||
|
||||
public Queue<Task> Queue;
|
||||
|
||||
public TaskQueueComponent()
|
||||
{
|
||||
public TaskQueueComponent() {
|
||||
Queue = new Queue<Task>();
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
public void Reset() {
|
||||
Queue.Clear();
|
||||
}
|
||||
|
||||
public void Process(Entity entity, float delta)
|
||||
{
|
||||
if (Queue.Count == 0) return;
|
||||
public void Process(Entity entity, float delta) {
|
||||
if (Queue.Count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
var currentTask = Queue.Peek();
|
||||
do {
|
||||
Task currentTask = Queue.Peek();
|
||||
|
||||
if (currentTask.PerformTask(entity, this, delta))
|
||||
if (currentTask.PerformTask(entity, this, delta)) {
|
||||
Queue.Dequeue();
|
||||
else
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (Queue.Count > 0);
|
||||
}
|
||||
|
||||
public abstract class Task : Object
|
||||
{
|
||||
public abstract class Task : Object {
|
||||
/// <summary>
|
||||
/// Executes a Task on the specified entity.
|
||||
/// </summary>
|
||||
|
@ -47,33 +44,27 @@ public class TaskQueueComponent : Component
|
|||
/// <summary>
|
||||
/// Makes an entity move towards a target (translation and or orientation).
|
||||
/// </summary>
|
||||
public class NavigationTask : Task
|
||||
{
|
||||
public class NavigationTask : Task {
|
||||
public NavigationPoint NavigationPoint;
|
||||
public bool PlanningComplete = false;
|
||||
|
||||
public NavigationTask(NavigationPoint navigationPoint)
|
||||
{
|
||||
public NavigationTask(NavigationPoint navigationPoint) {
|
||||
NavigationPoint = navigationPoint;
|
||||
}
|
||||
|
||||
public override bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta)
|
||||
{
|
||||
public override bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta) {
|
||||
return NavigationPoint.IsReached(entity.GlobalTransform);
|
||||
}
|
||||
}
|
||||
|
||||
public class InteractionTask : Task
|
||||
{
|
||||
public class InteractionTask : Task {
|
||||
public Entity TargetEntity;
|
||||
|
||||
public InteractionTask(Entity entity)
|
||||
{
|
||||
public InteractionTask(Entity entity) {
|
||||
TargetEntity = entity;
|
||||
}
|
||||
|
||||
public override bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta)
|
||||
{
|
||||
public override bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta) {
|
||||
taskQueueComponent.EmitSignal("StartInteraction", entity, TargetEntity);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
using Godot;
|
||||
|
||||
public class WorldInfoComponent : Component
|
||||
{
|
||||
public class WorldInfoComponent : Component {
|
||||
[Export] public NodePath WorldPath;
|
||||
public World World;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
World = GetNode<World>(WorldPath);
|
||||
}
|
||||
|
||||
public void SetWorld(World world)
|
||||
{
|
||||
public void SetWorld(World world) {
|
||||
World = world;
|
||||
}
|
||||
}
|
|
@ -1,11 +1,6 @@
|
|||
using Godot;
|
||||
using System;
|
||||
|
||||
public class Axe : StaticBody
|
||||
{
|
||||
public class Axe : StaticBody {
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
public override void _Ready() { }
|
||||
}
|
|
@ -3,13 +3,11 @@ using Godot;
|
|||
using GodotComponentTest.components;
|
||||
using GodotComponentTest.entities;
|
||||
|
||||
public class Chest : Entity, IInteractionInterface
|
||||
{
|
||||
public class Chest : Entity, IInteractionInterface {
|
||||
// resources
|
||||
private readonly PackedScene _goldBarScene = GD.Load<PackedScene>("res://entities/GoldBar.tscn");
|
||||
|
||||
public enum LidState
|
||||
{
|
||||
public enum LidState {
|
||||
Closed,
|
||||
Open
|
||||
}
|
||||
|
@ -29,8 +27,7 @@ public class Chest : Entity, IInteractionInterface
|
|||
private delegate void ChestOpened(Entity entity);
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_mesh = GetNode<MeshInstance>("Geometry/Skeleton/Chest");
|
||||
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
|
||||
|
||||
|
@ -42,64 +39,51 @@ public class Chest : Entity, IInteractionInterface
|
|||
|
||||
|
||||
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);
|
||||
_mesh.MaterialOverride = overrideMaterial;
|
||||
}
|
||||
|
||||
|
||||
public void OnAreaMouseExited()
|
||||
{
|
||||
public void OnAreaMouseExited() {
|
||||
IsMouseOver = false;
|
||||
_mesh.MaterialOverride = null;
|
||||
}
|
||||
|
||||
|
||||
public void OnInteractionStart()
|
||||
{
|
||||
public void OnInteractionStart() {
|
||||
_animationPlayer.Stop();
|
||||
|
||||
if (State == LidState.Closed)
|
||||
{
|
||||
if (State == LidState.Closed) {
|
||||
State = LidState.Open;
|
||||
_animationPlayer.Play("ChestOpen");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_animationPlayer.PlayBackwards("ChestOpen");
|
||||
State = LidState.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnInteractionEnd()
|
||||
{
|
||||
|
||||
}
|
||||
public void OnInteractionEnd() { }
|
||||
|
||||
public void OnChestOpened()
|
||||
{
|
||||
public void OnChestOpened() {
|
||||
GD.Print("Chest now opened!");
|
||||
foreach (int i in Enumerable.Range(0, 10))
|
||||
{
|
||||
foreach (int i in Enumerable.Range(0, 10)) {
|
||||
GoldBar bar = (GoldBar)_goldBarScene.Instance();
|
||||
bar.Transform = new Transform(Transform.basis.Rotated(Vector3.Up, GD.Randf() * 2 * Mathf.Pi), Transform.origin + Vector3.Up * 0.8f);
|
||||
bar.Transform = new Transform(Transform.basis.Rotated(Vector3.Up, GD.Randf() * 2 * Mathf.Pi),
|
||||
Transform.origin + Vector3.Up * 0.8f);
|
||||
bar.velocity = new Vector3(
|
||||
(GD.Randf() * 2f - 1f) * 2,
|
||||
5 + GD.Randf() * 0.3f,
|
||||
|
@ -108,8 +92,7 @@ public class Chest : Entity, IInteractionInterface
|
|||
GetParent().AddChild(bar);
|
||||
}
|
||||
|
||||
if (InteractionComponent != null)
|
||||
{
|
||||
if (InteractionComponent != null) {
|
||||
InteractionComponent.EndInteraction();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,61 +1,49 @@
|
|||
using Godot;
|
||||
using System;
|
||||
|
||||
public class GoldBar : KinematicBody
|
||||
{
|
||||
public class GoldBar : KinematicBody {
|
||||
private Vector3 targetPosition;
|
||||
private bool hasTarget = false;
|
||||
private bool hasTarget;
|
||||
public Vector3 velocity;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
targetPosition = GlobalTransform.origin;
|
||||
}
|
||||
|
||||
public void SetTarget(Vector3 target)
|
||||
{
|
||||
public void SetTarget(Vector3 target) {
|
||||
targetPosition = target;
|
||||
hasTarget = true;
|
||||
}
|
||||
|
||||
public void UnsetTarget()
|
||||
{
|
||||
public void UnsetTarget() {
|
||||
hasTarget = false;
|
||||
}
|
||||
|
||||
// Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
public override void _PhysicsProcess(float delta)
|
||||
{
|
||||
if (hasTarget)
|
||||
{
|
||||
if (targetPosition.IsEqualApprox(GlobalTransform.origin))
|
||||
{
|
||||
public override void _PhysicsProcess(float delta) {
|
||||
if (hasTarget) {
|
||||
if (targetPosition.IsEqualApprox(GlobalTransform.origin)) {
|
||||
targetPosition = GlobalTransform.origin;
|
||||
velocity = Vector3.Zero;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector3 targetDirection = (targetPosition - GlobalTransform.origin).Normalized();
|
||||
velocity = targetDirection * (velocity.Length() + 10 * delta);
|
||||
Transform = new Transform(this.Transform.basis.Rotated(Vector3.Up, delta * 2.0f), Transform.origin);
|
||||
}
|
||||
else
|
||||
{
|
||||
Transform = new Transform(Transform.basis.Rotated(Vector3.Up, delta * 2.0f), Transform.origin);
|
||||
} else {
|
||||
velocity.y = velocity.y - 9.81f * delta;
|
||||
}
|
||||
|
||||
velocity = MoveAndSlide(velocity, Vector3.Up);
|
||||
|
||||
if (IsOnFloor() || Mathf.Abs(Transform.origin.y) < 0.01)
|
||||
{
|
||||
if (IsOnFloor() || Mathf.Abs(Transform.origin.y) < 0.01) {
|
||||
// apply damping when on ground
|
||||
velocity = velocity - velocity.Normalized() * 0.9f * delta;
|
||||
}
|
||||
|
||||
if (velocity.LengthSquared() < 0.01)
|
||||
{
|
||||
|
||||
if (velocity.LengthSquared() < 0.01) {
|
||||
velocity = Vector3.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,14 +2,9 @@ using GodotComponentTest.components;
|
|||
|
||||
namespace GodotComponentTest.entities;
|
||||
|
||||
public interface IInteractionInterface
|
||||
{
|
||||
public interface IInteractionInterface {
|
||||
void OnInteractionStart();
|
||||
void OnInteractionEnd();
|
||||
|
||||
InteractionComponent InteractionComponent
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
InteractionComponent InteractionComponent { get; set; }
|
||||
}
|
|
@ -5,8 +5,7 @@ using GodotComponentTest.components;
|
|||
using GodotComponentTest.entities;
|
||||
using GodotComponentTest.utils;
|
||||
|
||||
public class Player : Entity, IInteractionInterface
|
||||
{
|
||||
public class Player : Entity, IInteractionInterface {
|
||||
// public members
|
||||
[Export] public NodePath WorldNode;
|
||||
|
||||
|
@ -30,8 +29,7 @@ public class Player : Entity, IInteractionInterface
|
|||
private BoneAttachment _toolAttachement;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_groundMotion = new GroundMotionComponent();
|
||||
_worldInfo = (WorldInfoComponent)FindNode("WorldInfo", false);
|
||||
NavigationComponent = (NavigationComponent)FindNode("Navigation", false);
|
||||
|
@ -39,33 +37,30 @@ public class Player : Entity, IInteractionInterface
|
|||
TaskQueueComponent = new TaskQueueComponent();
|
||||
|
||||
_itemAttractorArea = (Area)FindNode("ItemAttractorArea", false);
|
||||
if (_itemAttractorArea == null)
|
||||
{
|
||||
if (_itemAttractorArea == null) {
|
||||
GD.PushWarning("No ItemAttractorArea node found for " + GetClass());
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_itemAttractorArea.Connect("body_entered", this, nameof(OnItemAttractorBodyEntered));
|
||||
_itemAttractorArea.Connect("body_exited", this, nameof(OnItemAttractorBodyExited));
|
||||
}
|
||||
|
||||
_itemPickupArea = (Area)FindNode("ItemPickupArea", false);
|
||||
if (_itemPickupArea == null)
|
||||
if (_itemPickupArea == null) {
|
||||
GD.PushWarning("No ItemPickupArea node found for " + GetClass());
|
||||
else
|
||||
} else {
|
||||
_itemPickupArea.Connect("body_entered", this, nameof(OnItemPickupAreaBodyEntered));
|
||||
}
|
||||
|
||||
_playerAnimationPlayer = GetNode<AnimationPlayer>("Geometry/AnimationPlayer");
|
||||
Debug.Assert(_playerAnimationPlayer != null);
|
||||
_animationTree = GetNode<AnimationTree>("Geometry/AnimationTree");
|
||||
Debug.Assert(_animationTree != null);
|
||||
var stateMachine =
|
||||
AnimationNodeStateMachinePlayback stateMachine =
|
||||
(AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
|
||||
stateMachine.Start("Idle");
|
||||
|
||||
_toolAttachement = (BoneAttachment)FindNode("ToolAttachement");
|
||||
if (_toolAttachement == null)
|
||||
{
|
||||
if (_toolAttachement == null) {
|
||||
GD.PushWarning("No ToolAttachement found!");
|
||||
}
|
||||
|
||||
|
@ -73,25 +68,20 @@ public class Player : Entity, IInteractionInterface
|
|||
}
|
||||
|
||||
|
||||
public override void _PhysicsProcess(float delta)
|
||||
{
|
||||
public override void _PhysicsProcess(float delta) {
|
||||
base._PhysicsProcess(delta);
|
||||
|
||||
if (NavigationComponent == null)
|
||||
{
|
||||
if (NavigationComponent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (TaskQueueComponent != null && TaskQueueComponent.Queue.Count > 0)
|
||||
{
|
||||
if (TaskQueueComponent != null && TaskQueueComponent.Queue.Count > 0) {
|
||||
TaskQueueComponent.Process(this, delta);
|
||||
|
||||
if (TaskQueueComponent.Queue.Count > 0)
|
||||
{
|
||||
var currentTask = TaskQueueComponent.Queue.Peek();
|
||||
if (TaskQueueComponent.Queue.Count > 0) {
|
||||
TaskQueueComponent.Task currentTask = TaskQueueComponent.Queue.Peek();
|
||||
TaskQueueComponent.NavigationTask navigationTask = currentTask as TaskQueueComponent.NavigationTask;
|
||||
if (navigationTask != null && navigationTask.PlanningComplete == false)
|
||||
{
|
||||
if (navigationTask != null && navigationTask.PlanningComplete == false) {
|
||||
// _navigationComponent.PlanGridPath(this, GlobalTransform, navigationTask.NavigationPoint);
|
||||
NavigationComponent.PlanSmoothedPath(this, GlobalTransform, navigationTask.NavigationPoint);
|
||||
|
||||
|
@ -103,24 +93,21 @@ public class Player : Entity, IInteractionInterface
|
|||
_groundMotion.PhysicsProcess(delta, this, NavigationComponent.CurrentGoalPositionWorld,
|
||||
NavigationComponent.CurrentGoalAngleWorld, _worldInfo.World);
|
||||
|
||||
if (NavigationComponent.IsGoalReached())
|
||||
if (NavigationComponent.IsGoalReached()) {
|
||||
navigationTask.NavigationPoint = new NavigationPoint(GlobalTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
if (NavigationComponent != null)
|
||||
{
|
||||
public override void _Process(float delta) {
|
||||
if (NavigationComponent != null) {
|
||||
NavigationComponent.UpdateCurrentGoal(GlobalTransform);
|
||||
}
|
||||
|
||||
foreach (Node node in _attractedItemList)
|
||||
{
|
||||
if (node is GoldBar)
|
||||
{
|
||||
foreach (Node node in _attractedItemList) {
|
||||
if (node is GoldBar) {
|
||||
GoldBar bar = (GoldBar)node;
|
||||
bar.SetTarget(GlobalTransform.origin);
|
||||
}
|
||||
|
@ -129,31 +116,25 @@ public class Player : Entity, IInteractionInterface
|
|||
UpdateDebugGeometry();
|
||||
}
|
||||
|
||||
public void UpdateDebugGeometry()
|
||||
{
|
||||
if (_debugGeometry == null || _debugGeometry.Visible == false)
|
||||
{
|
||||
public void UpdateDebugGeometry() {
|
||||
if (_debugGeometry == null || _debugGeometry.Visible == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
_debugGeometry.Clear();
|
||||
_debugGeometry.GlobalTransform = Transform.Identity;
|
||||
|
||||
if (NavigationComponent != null)
|
||||
{
|
||||
if (NavigationComponent != null) {
|
||||
NavigationComponent.DebugDraw(this, _debugGeometry);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnItemAttractorBodyEntered(Node node)
|
||||
{
|
||||
public void OnItemAttractorBodyEntered(Node node) {
|
||||
_attractedItemList.Add(node);
|
||||
}
|
||||
|
||||
public void OnItemAttractorBodyExited(Node node)
|
||||
{
|
||||
if (node is GoldBar)
|
||||
{
|
||||
public void OnItemAttractorBodyExited(Node node) {
|
||||
if (node is GoldBar) {
|
||||
GoldBar bar = (GoldBar)node;
|
||||
bar.UnsetTarget();
|
||||
}
|
||||
|
@ -161,17 +142,14 @@ public class Player : Entity, IInteractionInterface
|
|||
_attractedItemList.Remove(node);
|
||||
}
|
||||
|
||||
public void OnItemPickupAreaBodyEntered(Node body)
|
||||
{
|
||||
public void OnItemPickupAreaBodyEntered(Node body) {
|
||||
GD.Print("Picking up item: " + body.Name);
|
||||
|
||||
if (body is Axe)
|
||||
{
|
||||
if (body is Axe) {
|
||||
SetActiveTool("Axe");
|
||||
}
|
||||
|
||||
if (body is GoldBar)
|
||||
{
|
||||
if (body is GoldBar) {
|
||||
GoldCount++;
|
||||
EmitSignal("GoldCountChanged", GoldCount);
|
||||
}
|
||||
|
@ -179,39 +157,30 @@ public class Player : Entity, IInteractionInterface
|
|||
body.QueueFree();
|
||||
}
|
||||
|
||||
public void SetActiveTool(string toolName)
|
||||
{
|
||||
public void SetActiveTool(string toolName) {
|
||||
Debug.Assert(_toolAttachement != null);
|
||||
if (toolName == "Axe")
|
||||
{
|
||||
if (toolName == "Axe") {
|
||||
_toolAttachement.Visible = true;
|
||||
}
|
||||
else if (toolName == "")
|
||||
{
|
||||
} else if (toolName == "") {
|
||||
_toolAttachement.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnInteractionStart()
|
||||
{
|
||||
public void OnInteractionStart() {
|
||||
AnimationNodeStateMachinePlayback stateMachine =
|
||||
(AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
|
||||
Debug.Assert(stateMachine != null);
|
||||
|
||||
if (InteractionComponent.TargetEntity is Chest)
|
||||
{
|
||||
if (InteractionComponent.TargetEntity is Chest) {
|
||||
GD.Print("Player Opening Box");
|
||||
stateMachine.Travel("Interaction");
|
||||
}
|
||||
else if (InteractionComponent.TargetEntity is Tree)
|
||||
{
|
||||
} else if (InteractionComponent.TargetEntity is Tree) {
|
||||
GD.Print("Player Chopping Tree");
|
||||
stateMachine.Travel("Hit");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnInteractionEnd()
|
||||
{
|
||||
public void OnInteractionEnd() {
|
||||
GD.Print("Player Stopping Interaction");
|
||||
AnimationNodeStateMachinePlayback stateMachine =
|
||||
(AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
using System.Diagnostics;
|
||||
using Godot;
|
||||
|
||||
public class Game : Spatial
|
||||
{
|
||||
public class Game : Spatial {
|
||||
private ImageTexture _blackWhitePatternTexture;
|
||||
private Camera _camera;
|
||||
private Vector3 _cameraOffset;
|
||||
|
@ -42,8 +41,7 @@ public class Game : Spatial
|
|||
private TextureRect _worldTextureRect;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
// debugStatsContainer
|
||||
Container debugStatsContainer = (Container)FindNode("DebugStatsContainer");
|
||||
|
||||
|
@ -86,7 +84,7 @@ public class Game : Spatial
|
|||
Debug.Assert(_tileMaterial != null);
|
||||
|
||||
_blackWhitePatternTexture = new ImageTexture();
|
||||
Image image = new Image();
|
||||
Image image = new();
|
||||
image.Load("assets/4x4checker.png");
|
||||
_blackWhitePatternTexture.CreateFromImage(image, (uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
|
||||
|
@ -108,9 +106,11 @@ public class Game : Spatial
|
|||
_world.Connect("OnHeightmapImageChanged", this, nameof(OnHeightmapImageChanged));
|
||||
|
||||
// register entity events
|
||||
foreach (Node node in GetNode("Entities").GetChildren())
|
||||
if (node.HasSignal("EntityClicked"))
|
||||
foreach (Node node in GetNode("Entities").GetChildren()) {
|
||||
if (node.HasSignal("EntityClicked")) {
|
||||
node.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
||||
}
|
||||
}
|
||||
|
||||
_world.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
||||
|
||||
|
@ -122,15 +122,17 @@ public class Game : Spatial
|
|||
}
|
||||
|
||||
|
||||
public override void _Input(InputEvent inputEvent)
|
||||
{
|
||||
if (inputEvent.IsAction("Forward")) GD.Print("Forward");
|
||||
public override void _Input(InputEvent inputEvent) {
|
||||
if (inputEvent.IsAction("Forward")) {
|
||||
GD.Print("Forward");
|
||||
}
|
||||
|
||||
if (inputEvent.IsAction("Back")) GD.Print("Back");
|
||||
if (inputEvent.IsAction("Back")) {
|
||||
GD.Print("Back");
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateCurrentTile()
|
||||
{
|
||||
public void UpdateCurrentTile() {
|
||||
// cast a ray from the camera to center
|
||||
Vector3 cameraNormal = _camera.ProjectRayNormal(_camera.GetViewport().Size * 0.5f);
|
||||
Vector3 cameraPosition = _camera.ProjectRayOrigin(_camera.GetViewport().Size * 0.5f);
|
||||
|
@ -138,12 +140,9 @@ public class Game : Spatial
|
|||
|
||||
Vector3 centerCoord;
|
||||
|
||||
if (Mathf.Abs(cameraDir.y) > Globals.EpsPosition)
|
||||
{
|
||||
if (Mathf.Abs(cameraDir.y) > Globals.EpsPosition) {
|
||||
centerCoord = cameraPosition + cameraNormal * (-cameraPosition.y / cameraNormal.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
centerCoord = _camera.GlobalTranslation;
|
||||
centerCoord.y = 0;
|
||||
}
|
||||
|
@ -157,8 +156,7 @@ public class Game : Spatial
|
|||
}
|
||||
|
||||
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
public override void _Process(float delta) {
|
||||
_framesPerSecondLabel.Text = Engine.GetFramesPerSecond().ToString();
|
||||
_lastTile = _currentTile;
|
||||
|
||||
|
@ -176,17 +174,17 @@ public class Game : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void OnGenerateButton()
|
||||
{
|
||||
public void OnGenerateButton() {
|
||||
GD.Print("Generating");
|
||||
Slider worldSizeSlider = (Slider)FindNode("WorldSizeSlider");
|
||||
if (worldSizeSlider == null) GD.PrintErr("Could not find WorldSizeSlider!");
|
||||
if (worldSizeSlider == null) {
|
||||
GD.PrintErr("Could not find WorldSizeSlider!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||
int shapeIndex)
|
||||
{
|
||||
int shapeIndex) {
|
||||
HexCell cellAtCursor = _hexGrid.GetHexAt(new Vector2(position.x, position.z));
|
||||
Transform highlightTransform = Transform.Identity;
|
||||
|
||||
|
@ -198,19 +196,21 @@ public class Game : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void OnTileClicked(HexTile3D tile)
|
||||
{
|
||||
if (_player == null) return;
|
||||
public void OnTileClicked(HexTile3D tile) {
|
||||
if (_player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player.InteractionComponent != null) _player.InteractionComponent.EmitSignal("InteractionEnd");
|
||||
if (_player.InteractionComponent != null) {
|
||||
_player.InteractionComponent.EmitSignal("InteractionEnd");
|
||||
}
|
||||
|
||||
_player.TaskQueueComponent.Reset();
|
||||
_player.TaskQueueComponent.Queue.Enqueue(new TaskQueueComponent.NavigationTask(
|
||||
new NavigationPoint(tile.GlobalTranslation)));
|
||||
}
|
||||
|
||||
public void OnTileHovered(HexTile3D tile)
|
||||
{
|
||||
public void OnTileHovered(HexTile3D tile) {
|
||||
Transform highlightTransform = tile.GlobalTransform;
|
||||
_mouseTileHighlight.Transform = highlightTransform;
|
||||
_mouseWorldLabel.Text = highlightTransform.origin.ToString("F3");
|
||||
|
@ -220,13 +220,11 @@ public class Game : Spatial
|
|||
_player.NavigationComponent.FindPath(_player, _player.GlobalTranslation, tile.GlobalTranslation);
|
||||
}
|
||||
|
||||
public void OnEntityClicked(Entity entity)
|
||||
{
|
||||
public void OnEntityClicked(Entity entity) {
|
||||
GD.Print("Clicked on entity at " + entity.GlobalTranslation);
|
||||
|
||||
Spatial mountPoint = (Spatial)entity.FindNode("MountPoint");
|
||||
if (mountPoint != null)
|
||||
{
|
||||
if (mountPoint != null) {
|
||||
_player.TaskQueueComponent.Reset();
|
||||
_player.TaskQueueComponent.Queue.Enqueue(new TaskQueueComponent.NavigationTask(
|
||||
new NavigationPoint(mountPoint.GlobalTransform)));
|
||||
|
@ -235,8 +233,7 @@ public class Game : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void ResetGameState()
|
||||
{
|
||||
public void ResetGameState() {
|
||||
Transform playerStartTransform = Transform.Identity;
|
||||
playerStartTransform.origin.y = 0;
|
||||
_player.Transform = playerStartTransform;
|
||||
|
@ -246,28 +243,25 @@ public class Game : Spatial
|
|||
|
||||
_goldCountLabel.Text = "0";
|
||||
|
||||
foreach (Spatial entity in GetNode("Entities").GetChildren())
|
||||
{
|
||||
foreach (Spatial entity in GetNode("Entities").GetChildren()) {
|
||||
Transform entityTransform = entity.Transform;
|
||||
Vector2 entityPlanePos = new Vector2(entityTransform.origin.x, entityTransform.origin.z);
|
||||
Vector2 entityPlanePos = new(entityTransform.origin.x, entityTransform.origin.z);
|
||||
Vector2 entityOffsetCoordinates = _hexGrid.GetHexAt(entityPlanePos).OffsetCoords;
|
||||
entityTransform.origin.y = 0;
|
||||
entity.Transform = entityTransform;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHeightmapImageChanged(Image heightmapImage)
|
||||
{
|
||||
ImageTexture newHeightmapTexture = new ImageTexture();
|
||||
private void OnHeightmapImageChanged(Image heightmapImage) {
|
||||
ImageTexture newHeightmapTexture = new();
|
||||
newHeightmapTexture.CreateFromImage(heightmapImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
|
||||
_heightTextureRect.Texture = newHeightmapTexture;
|
||||
}
|
||||
|
||||
private void OnWorldViewTileTypeImageChanged(Image viewTileTypeImage)
|
||||
{
|
||||
ImageTexture newWorldTexture = new ImageTexture();
|
||||
private void OnWorldViewTileTypeImageChanged(Image viewTileTypeImage) {
|
||||
ImageTexture newWorldTexture = new();
|
||||
newWorldTexture.CreateFromImage(viewTileTypeImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
|
||||
|
@ -279,8 +273,7 @@ public class Game : Spatial
|
|||
_tileMaterial.SetShaderParam("CoordinateOffsetV", (int)_world.WorldTextureCoordinateOffset.y);
|
||||
}
|
||||
|
||||
public void OnGoldCountChanged(int goldCount)
|
||||
{
|
||||
public void OnGoldCountChanged(int goldCount) {
|
||||
AnimationPlayer animationPlayer = _gameUi.GetNode<AnimationPlayer>("AnimationPlayer");
|
||||
_goldCountLabel.Text = goldCount.ToString();
|
||||
animationPlayer.CurrentAnimation = "FlashLabel";
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
using System.Diagnostics;
|
||||
using Godot;
|
||||
|
||||
public class HexTile3D : Spatial
|
||||
{
|
||||
public enum TileType
|
||||
{
|
||||
public class HexTile3D : Spatial {
|
||||
public enum TileType {
|
||||
Undefined,
|
||||
Sand,
|
||||
Grass,
|
||||
DeepGrass
|
||||
}
|
||||
|
||||
static public TileType[] ValidTileTypes = { TileType.Sand, TileType.Grass, TileType.DeepGrass };
|
||||
public static TileType[] ValidTileTypes = { TileType.Sand, TileType.Grass, TileType.DeepGrass };
|
||||
|
||||
// scene nodes
|
||||
private MeshInstance _mesh;
|
||||
|
@ -19,26 +17,24 @@ public class HexTile3D : Spatial
|
|||
|
||||
// signals
|
||||
[Signal]
|
||||
delegate void TileClicked(HexTile3D tile3d);
|
||||
private delegate void TileClicked(HexTile3D tile3d);
|
||||
|
||||
[Signal]
|
||||
delegate void TileHovered(HexTile3D tile3d);
|
||||
private delegate void TileHovered(HexTile3D tile3d);
|
||||
|
||||
// other member variables
|
||||
private SpatialMaterial _previousMaterial;
|
||||
|
||||
private HexGrid _hexGrid;
|
||||
private readonly HexGrid _hexGrid;
|
||||
|
||||
public HexCell Cell = new HexCell();
|
||||
public bool IsMouseOver = false;
|
||||
public HexCell Cell = new();
|
||||
public bool IsMouseOver;
|
||||
public MeshInstance Mesh;
|
||||
|
||||
public Vector2 OffsetCoords
|
||||
{
|
||||
get { return Cell.OffsetCoords; }
|
||||
public Vector2 OffsetCoords {
|
||||
get => Cell.OffsetCoords;
|
||||
|
||||
set
|
||||
{
|
||||
set {
|
||||
Cell.OffsetCoords = value;
|
||||
Transform tile3dTransform = Transform;
|
||||
Vector2 cellPlaneCoords = _hexGrid.GetHexCenter(Cell);
|
||||
|
@ -50,14 +46,12 @@ public class HexTile3D : Spatial
|
|||
|
||||
public TileType Type { get; set; }
|
||||
|
||||
HexTile3D()
|
||||
{
|
||||
private HexTile3D() {
|
||||
_hexGrid = new HexGrid();
|
||||
}
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_mesh = GetNode<MeshInstance>("Mesh");
|
||||
_staticBody = GetNode<StaticBody>("StaticBody");
|
||||
|
||||
|
@ -65,28 +59,24 @@ public class HexTile3D : Spatial
|
|||
_staticBody.Connect("mouse_entered", this, nameof(OnAreaMouseEntered));
|
||||
_staticBody.Connect("mouse_exited", this, nameof(OnAreaMouseExited));
|
||||
|
||||
Mesh = GetNode<MeshInstance>("Mesh");
|
||||
Mesh = GetNode<MeshInstance>("Mesh");
|
||||
Debug.Assert(Mesh != null);
|
||||
|
||||
this.Type = TileType.Undefined;
|
||||
|
||||
Type = TileType.Undefined;
|
||||
}
|
||||
|
||||
|
||||
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("TileClicked", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAreaMouseEntered()
|
||||
{
|
||||
public void OnAreaMouseEntered() {
|
||||
IsMouseOver = true;
|
||||
_previousMaterial = (SpatialMaterial)_mesh.MaterialOverride;
|
||||
|
||||
|
@ -96,8 +86,7 @@ public class HexTile3D : Spatial
|
|||
// _mesh.MaterialOverride = clonedMaterial;
|
||||
}
|
||||
|
||||
public void OnAreaMouseExited()
|
||||
{
|
||||
public void OnAreaMouseExited() {
|
||||
IsMouseOver = false;
|
||||
_mesh.MaterialOverride = _previousMaterial;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
using System;
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using GoDotLog;
|
||||
using Godot;
|
||||
|
||||
public class StreamContainer : Spatial
|
||||
{
|
||||
public class StreamContainer : Spatial {
|
||||
// readonly variables
|
||||
private readonly Transform _deactivatedTileTransform = new Transform(Basis.Identity, Vector3.Up * 1000);
|
||||
|
||||
private readonly Transform _deactivatedTileTransform = new(Basis.Identity, Vector3.Up * 1000);
|
||||
|
||||
// scene nodes
|
||||
private MeshInstance _bounds;
|
||||
private Spatial _activeTiles;
|
||||
|
@ -18,50 +14,45 @@ public class StreamContainer : Spatial
|
|||
private MultiMeshInstance _tileMultiMesh;
|
||||
|
||||
// resources
|
||||
private PackedScene _hexTileScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
||||
private readonly PackedScene _hexTileScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
||||
|
||||
// exports
|
||||
[Export] public Vector2 Dimensions = new Vector2(8, 4);
|
||||
[Export] public Vector2 Dimensions = new(8, 4);
|
||||
[Export] public NodePath World;
|
||||
[Export] private bool ShowHexTiles = false;
|
||||
[Export] private bool ShowHexTiles;
|
||||
|
||||
[Signal]
|
||||
delegate void TileClicked(HexTile3D tile3d);
|
||||
private delegate void TileClicked(HexTile3D tile3d);
|
||||
|
||||
[Signal]
|
||||
delegate void TileHovered(HexTile3D tile3d);
|
||||
private delegate void TileHovered(HexTile3D tile3d);
|
||||
|
||||
// other members
|
||||
private Rect2 _currentOffsetCoordRect;
|
||||
private Rect2 _oldOffsetCoordRect;
|
||||
private HexGrid _hexGrid;
|
||||
|
||||
private Dictionary<Vector2, HexTile3D> _coordToTile = new();
|
||||
private Dictionary<HexTile3D, int> _tileToInstanceIndex = new();
|
||||
public List<Vector2> RemovedCoords = new List<Vector2>();
|
||||
public List<Vector2> AddedCoords = new List<Vector2>();
|
||||
private readonly Dictionary<Vector2, HexTile3D> _coordToTile = new();
|
||||
private readonly Dictionary<HexTile3D, int> _tileToInstanceIndex = new();
|
||||
public List<Vector2> RemovedCoords = new();
|
||||
public List<Vector2> AddedCoords = new();
|
||||
|
||||
public Rect2 CurrentOffsetCoordRect
|
||||
{
|
||||
get { return _currentOffsetCoordRect; }
|
||||
}
|
||||
public Rect2 CurrentOffsetCoordRect => _currentOffsetCoordRect;
|
||||
|
||||
public void SetWorld(TileWorld tileWorld)
|
||||
{
|
||||
public void SetWorld(TileWorld tileWorld) {
|
||||
TileWorld = tileWorld;
|
||||
}
|
||||
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_unusedTiles = new Queue<HexTile3D>();
|
||||
_bounds = GetNode<MeshInstance>("Bounds");
|
||||
_activeTiles = GetNode<Spatial>("ActiveTiles");
|
||||
|
||||
|
||||
_tileMultiMesh = GetNode<MultiMeshInstance>("TileMultiMesh");
|
||||
_tileMultiMesh.Multimesh.InstanceCount = (int)((Dimensions.x + 5) * (Dimensions.y + 5));
|
||||
_tileMultiMesh.Multimesh.InstanceCount = 1810;
|
||||
foreach (int i in Enumerable.Range(0, _tileMultiMesh.Multimesh.InstanceCount))
|
||||
{
|
||||
foreach (int i in Enumerable.Range(0, _tileMultiMesh.Multimesh.InstanceCount)) {
|
||||
_tileMultiMesh.Multimesh.SetInstanceTransform(i, _deactivatedTileTransform);
|
||||
}
|
||||
|
||||
|
@ -75,13 +66,12 @@ public class StreamContainer : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void UpdateRects(Vector2 centerPlane)
|
||||
{
|
||||
public void UpdateRects(Vector2 centerPlane) {
|
||||
_oldOffsetCoordRect = _currentOffsetCoordRect;
|
||||
|
||||
Vector2 bottomLeftCoord = centerPlane - new Vector2(Dimensions.x / 2, Dimensions.y / 2);
|
||||
Vector2 topRightCoord = centerPlane + new Vector2(Dimensions.x / 2, Dimensions.y / 2);
|
||||
|
||||
|
||||
// GD.Print("World rect now: " + _worldRect.ToString() + " center: " + _worldRect.GetCenter());
|
||||
|
||||
// y axis needs to be inverted as HexGrid's offset coordinates use the opposite axis direction
|
||||
|
@ -104,15 +94,13 @@ public class StreamContainer : Spatial
|
|||
// GD.Print("Bounds Transform: " + boundsTransform.ToString());
|
||||
// GD.Print("Bounds Global : " + _bounds.GlobalTransform.ToString());
|
||||
|
||||
if (!_currentOffsetCoordRect.Equals(_oldOffsetCoordRect))
|
||||
{
|
||||
if (!_currentOffsetCoordRect.Equals(_oldOffsetCoordRect)) {
|
||||
UpdateTileCache();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void UpdateTileCache()
|
||||
{
|
||||
public void UpdateTileCache() {
|
||||
RemovedCoords.Clear();
|
||||
AddedCoords.Clear();
|
||||
_unusedTiles.Clear();
|
||||
|
@ -123,8 +111,7 @@ public class StreamContainer : Spatial
|
|||
MarkUnusedTiles(expandedRect, clippedRect);
|
||||
AddNewTiles(expandedRect, clippedRect);
|
||||
|
||||
foreach (HexTile3D tile3D in _unusedTiles.ToArray())
|
||||
{
|
||||
foreach (HexTile3D tile3D in _unusedTiles.ToArray()) {
|
||||
RemovedCoords.Add(tile3D.OffsetCoords);
|
||||
_activeTiles.RemoveChild(tile3D);
|
||||
tile3D.Disconnect("TileClicked", this, nameof(OnTileClicked));
|
||||
|
@ -134,65 +121,53 @@ public class StreamContainer : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void MarkUnusedTiles(Rect2 expandedRect, Rect2 clippedRect)
|
||||
{
|
||||
public void MarkUnusedTiles(Rect2 expandedRect, Rect2 clippedRect) {
|
||||
foreach (int coord_x in Enumerable.Range(Mathf.FloorToInt(expandedRect.Position.x) - 5,
|
||||
Mathf.CeilToInt(expandedRect.Size.x) + 20))
|
||||
{
|
||||
Mathf.CeilToInt(expandedRect.Size.x) + 20)) {
|
||||
foreach (int coord_y in Enumerable.Range(Mathf.FloorToInt(expandedRect.Position.y) - 5,
|
||||
Mathf.CeilToInt(expandedRect.Size.y) + 20))
|
||||
{
|
||||
Vector2 coord = new Vector2(coord_x, coord_y);
|
||||
Mathf.CeilToInt(expandedRect.Size.y) + 20)) {
|
||||
Vector2 coord = new(coord_x, coord_y);
|
||||
|
||||
if (clippedRect.HasPoint(coord))
|
||||
{
|
||||
if (clippedRect.HasPoint(coord)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isInCurrent = _currentOffsetCoordRect.HasPoint(coord);
|
||||
bool isInOld = _oldOffsetCoordRect.HasPoint(coord);
|
||||
|
||||
if (isInOld && !isInCurrent && _coordToTile.Keys.Contains(coord))
|
||||
{
|
||||
if (isInOld && !isInCurrent && _coordToTile.Keys.Contains(coord)) {
|
||||
HexTile3D tile3D = _coordToTile[coord];
|
||||
|
||||
|
||||
OnTileDeactivate(tile3D, coord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddNewTiles(Rect2 expandedRect, Rect2 clippedRect)
|
||||
{
|
||||
public void AddNewTiles(Rect2 expandedRect, Rect2 clippedRect) {
|
||||
foreach (int coord_x in Enumerable.Range(Mathf.FloorToInt(_currentOffsetCoordRect.Position.x),
|
||||
Mathf.CeilToInt(_currentOffsetCoordRect.Size.x)))
|
||||
{
|
||||
Mathf.CeilToInt(_currentOffsetCoordRect.Size.x))) {
|
||||
foreach (int coord_y in Enumerable.Range(Mathf.FloorToInt(_currentOffsetCoordRect.Position.y),
|
||||
Mathf.CeilToInt(_currentOffsetCoordRect.Size.y)))
|
||||
{
|
||||
Vector2 coord = new Vector2(coord_x, coord_y);
|
||||
Mathf.CeilToInt(_currentOffsetCoordRect.Size.y))) {
|
||||
Vector2 coord = new(coord_x, coord_y);
|
||||
|
||||
if (clippedRect.HasPoint(coord))
|
||||
{
|
||||
if (clippedRect.HasPoint(coord)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_unusedTiles.Count == 0)
|
||||
{
|
||||
if (_unusedTiles.Count == 0) {
|
||||
AddedCoords.Add(coord);
|
||||
HexTile3D tile3D = GetTile3dAt(coord);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
HexTile3D tile3D = _unusedTiles.Dequeue();
|
||||
tile3D.OffsetCoords = coord;
|
||||
tile3D.Type = TileWorld.GetTileTypeAtOffset(coord);
|
||||
Transform tileTransform = tile3D.Transform;
|
||||
tileTransform.origin.y = TileWorld.GetHeightAtOffset(coord);
|
||||
tile3D.Transform = tileTransform;
|
||||
|
||||
|
||||
OnTileActivate(tile3D);
|
||||
|
||||
|
||||
_coordToTile[coord] = tile3D;
|
||||
}
|
||||
}
|
||||
|
@ -200,49 +175,42 @@ public class StreamContainer : Spatial
|
|||
}
|
||||
|
||||
|
||||
public HexTile3D GetTile3dAt(Vector2 offsetCoords)
|
||||
{
|
||||
if (!_coordToTile.Keys.Contains(offsetCoords))
|
||||
{
|
||||
public HexTile3D GetTile3dAt(Vector2 offsetCoords) {
|
||||
if (!_coordToTile.Keys.Contains(offsetCoords)) {
|
||||
HexTile3D tile3D = (HexTile3D)_hexTileScene.Instance();
|
||||
tile3D.OffsetCoords = offsetCoords;
|
||||
_activeTiles.AddChild(tile3D);
|
||||
tile3D.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
tile3D.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
|
||||
if (ShowHexTiles)
|
||||
{
|
||||
if (ShowHexTiles) {
|
||||
MeshInstance HexTileMesh = tile3D.GetNode<MeshInstance>("Mesh");
|
||||
HexTileMesh.Transform = HexTileMesh.Transform.Scaled(new Vector3(0.95f, 1, 0.95f));
|
||||
}
|
||||
|
||||
|
||||
Transform tileTransform = tile3D.Transform;
|
||||
tileTransform.origin.y = TileWorld.GetHeightAtOffset(offsetCoords);
|
||||
tile3D.Transform = tileTransform;
|
||||
tile3D.Type = TileWorld.GetTileTypeAtOffset(offsetCoords);
|
||||
|
||||
_tileToInstanceIndex[tile3D] = _tileToInstanceIndex.Count;
|
||||
|
||||
|
||||
_coordToTile[offsetCoords] = tile3D;
|
||||
}
|
||||
|
||||
OnTileActivate(_coordToTile[offsetCoords]);
|
||||
|
||||
|
||||
return _coordToTile[offsetCoords];
|
||||
}
|
||||
|
||||
public void SetCenterTile(HexCell cell)
|
||||
{
|
||||
public void SetCenterTile(HexCell cell) {
|
||||
UpdateRects(_hexGrid.GetHexCenter(cell));
|
||||
}
|
||||
|
||||
public void SetTileMaterial(ShaderMaterial material)
|
||||
{
|
||||
foreach (Spatial node in _activeTiles.GetChildren())
|
||||
{
|
||||
public void SetTileMaterial(ShaderMaterial material) {
|
||||
foreach (Spatial node in _activeTiles.GetChildren()) {
|
||||
HexTile3D tile = (HexTile3D)node;
|
||||
if (tile == null)
|
||||
{
|
||||
if (tile == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -250,57 +218,51 @@ public class StreamContainer : Spatial
|
|||
}
|
||||
}
|
||||
|
||||
public void OnTileActivate(HexTile3D tile3D)
|
||||
{
|
||||
public void OnTileActivate(HexTile3D tile3D) {
|
||||
int instanceIndex = _tileToInstanceIndex[tile3D];
|
||||
|
||||
Vector3 scale = Vector3.One;
|
||||
if (ShowHexTiles)
|
||||
{
|
||||
if (ShowHexTiles) {
|
||||
scale.x *= 0.96f;
|
||||
scale.z *= 0.96f;
|
||||
}
|
||||
|
||||
Transform instanceTransform = new Transform(tile3D.GlobalTransform.basis.Rotated(Vector3.Up, Mathf.Deg2Rad(30)).Scaled(scale), tile3D.GlobalTransform.origin + Vector3.Up * -2.5f);
|
||||
|
||||
|
||||
Transform instanceTransform =
|
||||
new(tile3D.GlobalTransform.basis.Rotated(Vector3.Up, Mathf.Deg2Rad(30)).Scaled(scale),
|
||||
tile3D.GlobalTransform.origin + Vector3.Up * -2.5f);
|
||||
|
||||
_tileMultiMesh.Multimesh.SetInstanceTransform(instanceIndex, instanceTransform);
|
||||
}
|
||||
|
||||
public void OnTileDeactivate(HexTile3D tile3D, Vector2 coord)
|
||||
{
|
||||
public void OnTileDeactivate(HexTile3D tile3D, Vector2 coord) {
|
||||
int instanceIndex = _tileToInstanceIndex[tile3D];
|
||||
_tileMultiMesh.Multimesh.SetInstanceTransform(instanceIndex, _deactivatedTileTransform);
|
||||
|
||||
|
||||
tile3D.Type = HexTile3D.TileType.Undefined;
|
||||
_unusedTiles.Enqueue(tile3D);
|
||||
_coordToTile.Remove(coord);
|
||||
RemovedCoords.Add(coord);
|
||||
}
|
||||
|
||||
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 OnWorldGenerated()
|
||||
{
|
||||
foreach (Spatial node in _activeTiles.GetChildren())
|
||||
{
|
||||
public void OnWorldGenerated() {
|
||||
foreach (Spatial node in _activeTiles.GetChildren()) {
|
||||
HexTile3D tile = (HexTile3D)node;
|
||||
if (tile == null)
|
||||
{
|
||||
if (tile == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Transform tileTransform = tile.GlobalTransform;
|
||||
tileTransform.origin.y = TileWorld.GetHeightAtOffset(tile.OffsetCoords);
|
||||
tile.GlobalTransform = tileTransform;
|
||||
|
||||
|
||||
OnTileActivate(tile);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,7 @@ using Godot;
|
|||
using Godot.Collections;
|
||||
using Namespace;
|
||||
|
||||
public class TileWorld : Spatial
|
||||
{
|
||||
public class TileWorld : Spatial {
|
||||
// exports
|
||||
[Export] public bool DebugMap;
|
||||
[ExportFlagsEnum(typeof(MapType))] public MapType GenerationMapType = MapType.Debug;
|
||||
|
@ -21,8 +20,7 @@ public class TileWorld : Spatial
|
|||
private Spatial _environmentNode;
|
||||
private readonly Array<Spatial> _grassAssets = new();
|
||||
|
||||
private enum GenerationState
|
||||
{
|
||||
private enum GenerationState {
|
||||
Heightmap,
|
||||
Color,
|
||||
Objects,
|
||||
|
@ -34,8 +32,7 @@ public class TileWorld : Spatial
|
|||
private delegate void WorldGenerated();
|
||||
|
||||
// public members
|
||||
public enum MapType
|
||||
{
|
||||
public enum MapType {
|
||||
Noise,
|
||||
Debug,
|
||||
Flat
|
||||
|
@ -62,8 +59,7 @@ public class TileWorld : Spatial
|
|||
private Viewport _worldOffscreenViewport;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
HexGrid = new HexGrid();
|
||||
_tileTypeRandom = new Random();
|
||||
|
||||
|
@ -83,18 +79,15 @@ public class TileWorld : Spatial
|
|||
|
||||
GetNode<Spatial>("Assets").Visible = false;
|
||||
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Rocks").GetChildren())
|
||||
{
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Rocks").GetChildren()) {
|
||||
_rockAssets.Add(asset);
|
||||
}
|
||||
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Grass").GetChildren())
|
||||
{
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Grass").GetChildren()) {
|
||||
_grassAssets.Add(asset);
|
||||
}
|
||||
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Trees").GetChildren())
|
||||
{
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Trees").GetChildren()) {
|
||||
_treeAssets.Add(asset);
|
||||
}
|
||||
|
||||
|
@ -106,8 +99,7 @@ public class TileWorld : Spatial
|
|||
ResetWorldImages(Size);
|
||||
}
|
||||
|
||||
public void ResetWorldImages(int size)
|
||||
{
|
||||
public void ResetWorldImages(int size) {
|
||||
GD.Print("Resetting World Images to size " + size);
|
||||
|
||||
Vector2 sizeVector = new Vector2(size, size);
|
||||
|
@ -130,12 +122,10 @@ public class TileWorld : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void Generate(int size)
|
||||
{
|
||||
public void Generate(int size) {
|
||||
GD.Print("Triggering generation for size: " + size);
|
||||
|
||||
if (Size != size)
|
||||
{
|
||||
if (Size != size) {
|
||||
ResetWorldImages(size);
|
||||
_resizeTriggered = true;
|
||||
_resizeExtraFrameCount = 1;
|
||||
|
@ -153,8 +143,7 @@ public class TileWorld : Spatial
|
|||
|
||||
OnMapGenerationStart();
|
||||
|
||||
switch (GenerationMapType)
|
||||
{
|
||||
switch (GenerationMapType) {
|
||||
case MapType.Debug:
|
||||
GenerateDebugMap();
|
||||
break;
|
||||
|
@ -167,8 +156,7 @@ public class TileWorld : Spatial
|
|||
}
|
||||
}
|
||||
|
||||
private void GenerateDebugMap()
|
||||
{
|
||||
private void GenerateDebugMap() {
|
||||
ColormapImage = new Image();
|
||||
ColormapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
||||
|
||||
|
@ -178,10 +166,8 @@ public class TileWorld : Spatial
|
|||
HeightmapImage.Lock();
|
||||
ColormapImage.Lock();
|
||||
|
||||
foreach (int coordX in Enumerable.Range(0, Size))
|
||||
{
|
||||
foreach (int coordY in Enumerable.Range(0, Size))
|
||||
{
|
||||
foreach (int coordX in Enumerable.Range(0, Size)) {
|
||||
foreach (int coordY in Enumerable.Range(0, Size)) {
|
||||
ColormapImage.SetPixel(coordX, coordY,
|
||||
new Color((float)Mathf.Min(coordX, coordY) / Size, 0, 0));
|
||||
HeightmapImage.SetPixel(coordX, coordY,
|
||||
|
@ -197,8 +183,7 @@ public class TileWorld : Spatial
|
|||
}
|
||||
|
||||
|
||||
private void GenerateFlatMap()
|
||||
{
|
||||
private void GenerateFlatMap() {
|
||||
ColormapImage = new Image();
|
||||
ColormapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
||||
|
||||
|
@ -208,10 +193,8 @@ public class TileWorld : Spatial
|
|||
HeightmapImage.Lock();
|
||||
ColormapImage.Lock();
|
||||
|
||||
foreach (int coordX in Enumerable.Range(0, Size))
|
||||
{
|
||||
foreach (int coordY in Enumerable.Range(0, Size))
|
||||
{
|
||||
foreach (int coordX in Enumerable.Range(0, Size)) {
|
||||
foreach (int coordY in Enumerable.Range(0, Size)) {
|
||||
HeightmapImage.SetPixel(coordX, coordY,
|
||||
new Color(0.5f, 0.5f, 0.5f));
|
||||
}
|
||||
|
@ -224,8 +207,7 @@ public class TileWorld : Spatial
|
|||
}
|
||||
|
||||
|
||||
private void GenerateNoiseMap()
|
||||
{
|
||||
private void GenerateNoiseMap() {
|
||||
HeightmapImage = new Image();
|
||||
HeightmapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
||||
|
||||
|
@ -245,28 +227,23 @@ public class TileWorld : Spatial
|
|||
OnHeightMapChanged();
|
||||
}
|
||||
|
||||
private void OnMapGenerationStart()
|
||||
{
|
||||
foreach (Node child in _environmentNode.GetChildren())
|
||||
{
|
||||
private void OnMapGenerationStart() {
|
||||
foreach (Node child in _environmentNode.GetChildren()) {
|
||||
child.QueueFree();
|
||||
}
|
||||
|
||||
foreach (Node child in Entities.GetChildren())
|
||||
{
|
||||
foreach (Node child in Entities.GetChildren()) {
|
||||
child.QueueFree();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHeightMapChanged()
|
||||
{
|
||||
private void OnHeightMapChanged() {
|
||||
GD.Print("Triggering rendering of height map");
|
||||
_currentGenerationState = GenerationState.Heightmap;
|
||||
_heightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once;
|
||||
}
|
||||
|
||||
private void OnMapGenerationComplete()
|
||||
{
|
||||
private void OnMapGenerationComplete() {
|
||||
_currentGenerationState = GenerationState.Done;
|
||||
_worldOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
||||
_heightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
||||
|
@ -276,10 +253,9 @@ public class TileWorld : Spatial
|
|||
EmitSignal("WorldGenerated");
|
||||
}
|
||||
|
||||
private Spatial SelectAsset(Vector2 offsetCoord, Array<Spatial> assets, Random randomGenerator, double probability)
|
||||
{
|
||||
if (randomGenerator.NextDouble() < 1.0 - probability)
|
||||
{
|
||||
private Spatial SelectAsset(Vector2 offsetCoord, Array<Spatial> assets, Random randomGenerator,
|
||||
double probability) {
|
||||
if (randomGenerator.NextDouble() < 1.0 - probability) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -295,66 +271,52 @@ public class TileWorld : Spatial
|
|||
return assetInstance;
|
||||
}
|
||||
|
||||
private bool IsColorEqualApprox(Color colorA, Color colorB)
|
||||
{
|
||||
private bool IsColorEqualApprox(Color colorA, Color colorB) {
|
||||
Vector3 colorDifference = new Vector3(colorA.r - colorB.r, colorA.g - colorB.g, colorA.b - colorB.b);
|
||||
return colorDifference.LengthSquared() < 0.1 * 0.1;
|
||||
}
|
||||
|
||||
private bool IsColorWater(Color color)
|
||||
{
|
||||
private bool IsColorWater(Color color) {
|
||||
return (color.r == 0 && color.g == 0 && color.b > 0.01);
|
||||
}
|
||||
|
||||
public void MarkCellUnwalkable(HexCell cell)
|
||||
{
|
||||
public void MarkCellUnwalkable(HexCell cell) {
|
||||
HexGrid.AddObstacle(cell);
|
||||
NavigationmapImage.Lock();
|
||||
NavigationmapImage.SetPixelv(OffsetToTextureCoord(cell.OffsetCoords), Colors.Red);
|
||||
NavigationmapImage.Unlock();
|
||||
}
|
||||
|
||||
private void PopulateEnvironment()
|
||||
{
|
||||
private void PopulateEnvironment() {
|
||||
Random environmentRandom = new Random(Seed);
|
||||
|
||||
ColormapImage.Lock();
|
||||
HeightmapImage.Lock();
|
||||
|
||||
foreach (int textureCoordU in Enumerable.Range(0, Size))
|
||||
{
|
||||
foreach (int textureCoordV in Enumerable.Range(0, Size))
|
||||
{
|
||||
foreach (int textureCoordU in Enumerable.Range(0, Size)) {
|
||||
foreach (int textureCoordV in Enumerable.Range(0, Size)) {
|
||||
Color colorValue = ColormapImage.GetPixel(textureCoordU, textureCoordV);
|
||||
Vector2 textureCoord = new Vector2(textureCoordU, textureCoordV);
|
||||
HexCell cell = TextureCoordToCell(textureCoord);
|
||||
Vector2 offsetCoord = cell.OffsetCoords;
|
||||
|
||||
if (IsColorEqualApprox(colorValue, RockColor))
|
||||
{
|
||||
if (IsColorEqualApprox(colorValue, RockColor)) {
|
||||
Spatial rockAsset = SelectAsset(offsetCoord, _rockAssets, environmentRandom, 0.15);
|
||||
if (rockAsset != null)
|
||||
{
|
||||
if (rockAsset != null) {
|
||||
_environmentNode.AddChild(rockAsset);
|
||||
MarkCellUnwalkable(cell);
|
||||
}
|
||||
}
|
||||
else if (IsColorEqualApprox(colorValue, GrassColor))
|
||||
{
|
||||
} else if (IsColorEqualApprox(colorValue, GrassColor)) {
|
||||
Spatial grassAsset = SelectAsset(offsetCoord, _grassAssets, environmentRandom, 0.35);
|
||||
if (grassAsset != null)
|
||||
{
|
||||
if (grassAsset != null) {
|
||||
_environmentNode.AddChild(grassAsset);
|
||||
}
|
||||
|
||||
Spatial treeAsset = SelectAsset(offsetCoord, _treeAssets, environmentRandom, 0.10);
|
||||
if (treeAsset != null)
|
||||
{
|
||||
if (treeAsset != null) {
|
||||
Entities.AddChild(treeAsset);
|
||||
MarkCellUnwalkable(cell);
|
||||
}
|
||||
else if (environmentRandom.NextDouble() < 0.01)
|
||||
{
|
||||
} else if (environmentRandom.NextDouble() < 0.01) {
|
||||
Chest chestAsset = (Chest)_chestScene.Instance();
|
||||
Transform assetTransform = Transform.Identity;
|
||||
assetTransform.origin = GetHexCenterFromOffset(offsetCoord);
|
||||
|
@ -363,9 +325,7 @@ public class TileWorld : Spatial
|
|||
Entities.AddChild(chestAsset);
|
||||
MarkCellUnwalkable(cell);
|
||||
}
|
||||
}
|
||||
else if (IsColorWater(colorValue))
|
||||
{
|
||||
} else if (IsColorWater(colorValue)) {
|
||||
MarkCellUnwalkable(cell);
|
||||
}
|
||||
}
|
||||
|
@ -375,16 +335,13 @@ public class TileWorld : Spatial
|
|||
ColormapImage.Unlock();
|
||||
}
|
||||
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
if (_resizeTriggered && _resizeExtraFrameCount > 0)
|
||||
{
|
||||
public override void _Process(float delta) {
|
||||
if (_resizeTriggered && _resizeExtraFrameCount > 0) {
|
||||
_resizeExtraFrameCount--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_currentGenerationState == GenerationState.Heightmap)
|
||||
{
|
||||
if (_currentGenerationState == GenerationState.Heightmap) {
|
||||
HeightmapImage.CopyFrom(_heightmapOffscreenViewport.GetTexture().GetData());
|
||||
|
||||
_currentGenerationState = GenerationState.Color;
|
||||
|
@ -397,9 +354,7 @@ public class TileWorld : Spatial
|
|||
|
||||
_worldOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once;
|
||||
_resizeExtraFrameCount = 1;
|
||||
}
|
||||
else if (_currentGenerationState == GenerationState.Color)
|
||||
{
|
||||
} else if (_currentGenerationState == GenerationState.Color) {
|
||||
ColormapImage = new Image();
|
||||
ColormapImage.Create(Size, Size, false, Image.Format.Rgb8);
|
||||
ColormapImage.CopyFrom(_worldOffscreenViewport.GetTexture().GetData());
|
||||
|
@ -407,24 +362,19 @@ public class TileWorld : Spatial
|
|||
_currentGenerationState = GenerationState.Objects;
|
||||
|
||||
PopulateEnvironment();
|
||||
}
|
||||
else if (_currentGenerationState == GenerationState.Objects)
|
||||
{
|
||||
} else if (_currentGenerationState == GenerationState.Objects) {
|
||||
OnMapGenerationComplete();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsOffsetCoordValid(Vector2 offsetCoord)
|
||||
{
|
||||
public bool IsOffsetCoordValid(Vector2 offsetCoord) {
|
||||
return ((int)Math.Clamp(offsetCoord.x, -(float)Size / 2, (float)Size / 2 - 1) == (int)offsetCoord.x
|
||||
&& (int)Math.Clamp(offsetCoord.y, -(float)Size / 2, (float)Size / 2 - 1) == (int)offsetCoord.y);
|
||||
}
|
||||
|
||||
|
||||
public HexTile3D.TileType GetTileTypeAtOffset(Vector2 offsetCoord)
|
||||
{
|
||||
if (!IsOffsetCoordValid(offsetCoord))
|
||||
{
|
||||
public HexTile3D.TileType GetTileTypeAtOffset(Vector2 offsetCoord) {
|
||||
if (!IsOffsetCoordValid(offsetCoord)) {
|
||||
return HexTile3D.TileType.Undefined;
|
||||
}
|
||||
|
||||
|
@ -432,24 +382,20 @@ public class TileWorld : Spatial
|
|||
}
|
||||
|
||||
|
||||
public Vector2 OffsetToTextureCoord(Vector2 offsetCoord)
|
||||
{
|
||||
public Vector2 OffsetToTextureCoord(Vector2 offsetCoord) {
|
||||
Vector2 mapSize = Vector2.One * Size;
|
||||
Vector2 textureCoord = (offsetCoord + mapSize / 2).PosMod(mapSize);
|
||||
return textureCoord;
|
||||
}
|
||||
|
||||
public void SetHeightAtOffset(Vector2 offsetCoord, float height)
|
||||
{
|
||||
public void SetHeightAtOffset(Vector2 offsetCoord, float height) {
|
||||
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
|
||||
|
||||
HeightmapImage.SetPixel((int)textureCoord.x, (int)textureCoord.y, new Color(height, 0f, 0f));
|
||||
}
|
||||
|
||||
public float GetHeightAtOffset(Vector2 offsetCoord)
|
||||
{
|
||||
if (_currentGenerationState != GenerationState.Done)
|
||||
{
|
||||
public float GetHeightAtOffset(Vector2 offsetCoord) {
|
||||
if (_currentGenerationState != GenerationState.Done) {
|
||||
return 0f;
|
||||
}
|
||||
|
||||
|
@ -467,8 +413,7 @@ public class TileWorld : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void SetTileColorAtOffset(Vector2 offsetCoord, Color color)
|
||||
{
|
||||
public void SetTileColorAtOffset(Vector2 offsetCoord, Color color) {
|
||||
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
|
||||
|
||||
ColormapImage.Lock();
|
||||
|
@ -476,32 +421,27 @@ public class TileWorld : Spatial
|
|||
ColormapImage.Unlock();
|
||||
}
|
||||
|
||||
public Vector2 WorldToOffsetCoords(Vector3 worldCoord)
|
||||
{
|
||||
public Vector2 WorldToOffsetCoords(Vector3 worldCoord) {
|
||||
return HexGrid.GetHexAt(new Vector2(worldCoord.x, worldCoord.z)).OffsetCoords +
|
||||
Vector2.One * Mathf.Round(Size / 2f);
|
||||
}
|
||||
|
||||
public Vector3 GetTileWorldCenterFromOffset(Vector2 offsetCoord)
|
||||
{
|
||||
public Vector3 GetTileWorldCenterFromOffset(Vector2 offsetCoord) {
|
||||
Vector2 tileCenter = HexGrid.GetHexCenterFromOffset(offsetCoord - Vector2.One * Mathf.Round(Size / 2f));
|
||||
return new Vector3(tileCenter.x, GetHeightAtOffset(offsetCoord), tileCenter.y);
|
||||
}
|
||||
|
||||
|
||||
public Vector3 GetHexCenterFromOffset(Vector2 offsetCoord)
|
||||
{
|
||||
public Vector3 GetHexCenterFromOffset(Vector2 offsetCoord) {
|
||||
Vector2 tileCenter = HexGrid.GetHexCenterFromOffset(offsetCoord);
|
||||
return new Vector3(tileCenter.x, GetHeightAtOffset(offsetCoord), tileCenter.y);
|
||||
}
|
||||
|
||||
public HexCell TextureCoordToCell(Vector2 textureCoord)
|
||||
{
|
||||
public HexCell TextureCoordToCell(Vector2 textureCoord) {
|
||||
return HexCell.FromOffsetCoords(textureCoord - Vector2.One * _halfSize);
|
||||
}
|
||||
|
||||
public Vector2 TextureCoordToOffsetCoord(Vector2 textureCoord)
|
||||
{
|
||||
public Vector2 TextureCoordToOffsetCoord(Vector2 textureCoord) {
|
||||
return TextureCoordToCell(textureCoord).OffsetCoords;
|
||||
}
|
||||
}
|
|
@ -1,9 +1,8 @@
|
|||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
public class EditorUI : Control
|
||||
{
|
||||
public enum InputMode
|
||||
{
|
||||
public class EditorUI : Control {
|
||||
public enum InputMode {
|
||||
None,
|
||||
Grass,
|
||||
Sand,
|
||||
|
@ -35,8 +34,7 @@ public class EditorUI : Control
|
|||
public Vector2 currentTileOffset = Vector2.Zero;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_tileMaterial = GD.Load<ShaderMaterial>("materials/HexTileTextureLookup.tres");
|
||||
|
||||
// signals
|
||||
|
@ -69,74 +67,65 @@ public class EditorUI : Control
|
|||
}
|
||||
|
||||
|
||||
public void OnResetButton()
|
||||
{
|
||||
public void OnResetButton() {
|
||||
GD.Print("Resetting Map");
|
||||
_tileWorld.Seed = _tileWorld.Seed + 1;
|
||||
_tileWorld.Generate(24);
|
||||
}
|
||||
|
||||
public void OnGrassButton()
|
||||
{
|
||||
public void OnGrassButton() {
|
||||
CurrentInputMode = InputMode.Grass;
|
||||
}
|
||||
|
||||
public void OnSandButton()
|
||||
{
|
||||
public void OnSandButton() {
|
||||
CurrentInputMode = InputMode.Sand;
|
||||
}
|
||||
|
||||
public void OnWaterButton()
|
||||
{
|
||||
public void OnWaterButton() {
|
||||
CurrentInputMode = InputMode.Water;
|
||||
}
|
||||
|
||||
public void OnObstacleButton()
|
||||
{
|
||||
public void OnObstacleButton() {
|
||||
CurrentInputMode = InputMode.Obstacle;
|
||||
}
|
||||
|
||||
public void OnNavigateButton()
|
||||
{
|
||||
public void OnNavigateButton() {
|
||||
CurrentInputMode = InputMode.Navigate;
|
||||
}
|
||||
|
||||
public void OnGameGeometryCheckBoxToggled(bool pressed)
|
||||
{
|
||||
var gameGeometries = GetTree().GetNodesInGroup("GameGeometry");
|
||||
foreach (Spatial mesh in gameGeometries)
|
||||
if (mesh != null)
|
||||
public void OnGameGeometryCheckBoxToggled(bool pressed) {
|
||||
Array gameGeometries = GetTree().GetNodesInGroup("GameGeometry");
|
||||
foreach (Spatial mesh in gameGeometries) {
|
||||
if (mesh != null) {
|
||||
mesh.Visible = pressed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnPhysicsGeometryCheckBoxToggled(bool pressed)
|
||||
{
|
||||
var physicsGeometries = GetTree().GetNodesInGroup("PhysicsGeometry");
|
||||
foreach (Spatial mesh in physicsGeometries)
|
||||
if (mesh != null)
|
||||
public void OnPhysicsGeometryCheckBoxToggled(bool pressed) {
|
||||
Array physicsGeometries = GetTree().GetNodesInGroup("PhysicsGeometry");
|
||||
foreach (Spatial mesh in physicsGeometries) {
|
||||
if (mesh != null) {
|
||||
mesh.Visible = pressed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnNavigationGeometryCheckBoxToggled(bool pressed)
|
||||
{
|
||||
public void OnNavigationGeometryCheckBoxToggled(bool pressed) {
|
||||
UpdateTileMaterial();
|
||||
}
|
||||
|
||||
public void UpdateTileMaterial()
|
||||
{
|
||||
if (_navigationGeometryCheckBox.Pressed)
|
||||
{
|
||||
ImageTexture newWorldTexture = new ImageTexture();
|
||||
public void UpdateTileMaterial() {
|
||||
if (_navigationGeometryCheckBox.Pressed) {
|
||||
ImageTexture newWorldTexture = new();
|
||||
newWorldTexture.CreateFromImage(_tileWorld.NavigationmapImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
|
||||
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.NavigationmapImage.GetSize().x);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageTexture newWorldTexture = new ImageTexture();
|
||||
} else {
|
||||
ImageTexture newWorldTexture = new();
|
||||
newWorldTexture.CreateFromImage(_tileWorld.ColormapImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
|
||||
|
@ -145,10 +134,8 @@ public class EditorUI : Control
|
|||
}
|
||||
|
||||
|
||||
public void OnTileClicked(Vector2 offsetCoord)
|
||||
{
|
||||
switch (CurrentInputMode)
|
||||
{
|
||||
public void OnTileClicked(Vector2 offsetCoord) {
|
||||
switch (CurrentInputMode) {
|
||||
case InputMode.Grass:
|
||||
_tileWorld.SetTileColorAtOffset(currentTileOffset, Colors.Green);
|
||||
break;
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
using Godot;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Godot;
|
||||
|
||||
public class HexTile3DMaterialAssign : Spatial
|
||||
{
|
||||
public class HexTile3DMaterialAssign : Spatial {
|
||||
// Declare member variables here. Examples:
|
||||
// private int a = 2;
|
||||
// private string b = "text";
|
||||
|
@ -15,10 +13,9 @@ public class HexTile3DMaterialAssign : Spatial
|
|||
private ShaderMaterial _customTileMaterial;
|
||||
private ImageTexture _blackWhitePatternTexture;
|
||||
private ImageTexture _colorPatternTexture;
|
||||
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_blackWhitePatternButton = (Button)FindNode("BlackWhitePatternButton");
|
||||
Debug.Assert(_blackWhitePatternButton != null);
|
||||
_blackWhitePatternButton.Connect("pressed", this, nameof(OnBlackWhitePatternButton));
|
||||
|
@ -30,42 +27,39 @@ public class HexTile3DMaterialAssign : Spatial
|
|||
_textureSizeSpinBox = (SpinBox)FindNode("TextureSizeSpinBox");
|
||||
Debug.Assert(_textureSizeSpinBox != null);
|
||||
_textureSizeSpinBox.Connect("value_changed", this, nameof(OnTextureSizeChanged));
|
||||
|
||||
|
||||
_hexTile = (HexTile3D)FindNode("HexTile3D");
|
||||
Debug.Assert(_hexTile != null);
|
||||
|
||||
|
||||
_customTileMaterial = GD.Load<ShaderMaterial>("materials/HexTileTextureLookup.tres");
|
||||
|
||||
_blackWhitePatternTexture = new ImageTexture();
|
||||
Image image = new Image();
|
||||
Image image = new();
|
||||
image.Load("assets/4x4checker.png");
|
||||
_blackWhitePatternTexture.CreateFromImage(image, (uint) (Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
|
||||
_blackWhitePatternTexture.CreateFromImage(image, (uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
|
||||
_colorPatternTexture = new ImageTexture();
|
||||
image.Load("assets/4x4checkerColor.png");
|
||||
_colorPatternTexture.CreateFromImage(image, (uint) (Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
_colorPatternTexture.CreateFromImage(image, (uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
}
|
||||
|
||||
public void OnBlackWhitePatternButton()
|
||||
{
|
||||
public void OnBlackWhitePatternButton() {
|
||||
GD.Print("Apply Black White Pattern!");
|
||||
_customTileMaterial.SetShaderParam("MapAlbedoTexture", _blackWhitePatternTexture);
|
||||
}
|
||||
|
||||
public void OnColorPatternButton()
|
||||
{
|
||||
|
||||
public void OnColorPatternButton() {
|
||||
GD.Print("Apply Collor Pattern!");
|
||||
//currentMaterial.SetShaderParam("MapAlbedoTexture", _colorPatternTexture);
|
||||
_customTileMaterial.SetShaderParam("MapAlbedoTexture", _colorPatternTexture);
|
||||
|
||||
|
||||
// _customTileMaterial.SetShaderParam("MapAlbedoTexture", _imageTexture);
|
||||
|
||||
|
||||
// _hexTile.Mesh.SetSurfaceMaterial(0, _customTileMaterial);
|
||||
}
|
||||
|
||||
public void OnTextureSizeChanged(float value)
|
||||
{
|
||||
_customTileMaterial.SetShaderParam("TextureSize", (int) value);
|
||||
public void OnTextureSizeChanged(float value) {
|
||||
_customTileMaterial.SetShaderParam("TextureSize", (int)value);
|
||||
GD.Print("Texture size: " + _customTileMaterial.GetShaderParam("TextureSize"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,12 @@
|
|||
using Godot;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
public class NavigationTests : Spatial
|
||||
{
|
||||
public class NavigationTests : Spatial {
|
||||
private HexGrid _hexGrid;
|
||||
private HexCell _currentTile;
|
||||
private HexCell _lastTile;
|
||||
|
||||
|
||||
private Spatial _mouseHighlight;
|
||||
private ShaderMaterial _tileMaterial;
|
||||
|
||||
|
@ -17,27 +15,26 @@ public class NavigationTests : Spatial
|
|||
private StreamContainer _streamContainer;
|
||||
private Player _player;
|
||||
private NavigationComponent _playerNavigationComponent;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
|
||||
public override void _Ready() {
|
||||
_hexGrid = new HexGrid();
|
||||
_currentTile = new HexCell();
|
||||
_lastTile = new HexCell();
|
||||
|
||||
|
||||
_tileMaterial = GD.Load<ShaderMaterial>("materials/HexTileTextureLookup.tres");
|
||||
|
||||
|
||||
_mouseHighlight = GetNode<Spatial>("MouseHighlight");
|
||||
|
||||
_editorUi = GetNode<EditorUI>("EditorUI");
|
||||
_tileWorld = GetNode<TileWorld>("TileWorld");
|
||||
_tileWorld.Connect("WorldGenerated", this, nameof(OnWorldGenerated));
|
||||
_streamContainer = GetNode<StreamContainer>("StreamContainer");
|
||||
|
||||
|
||||
_streamContainer.SetCenterTile(_currentTile);
|
||||
|
||||
_player = GetNode<Player>("Player");
|
||||
_playerNavigationComponent = _player.GetNode<NavigationComponent>("Navigation");
|
||||
|
||||
|
||||
// input handling
|
||||
// _groundLayer.Connect("input_event", this, nameof(OnGroundLayerInputEvent));
|
||||
_streamContainer.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
|
@ -46,18 +43,15 @@ public class NavigationTests : Spatial
|
|||
CorrectEntityGridPositions();
|
||||
}
|
||||
|
||||
public void CorrectEntityGridPositions()
|
||||
{
|
||||
public void CorrectEntityGridPositions() {
|
||||
Spatial entitiesNode = GetNode<Spatial>("Entities");
|
||||
if (entitiesNode == null)
|
||||
{
|
||||
if (entitiesNode == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var entities = entitiesNode.GetChildren();
|
||||
foreach (Spatial entity in entities)
|
||||
{
|
||||
Vector2 entityPlaneCoords = new Vector2(entity.GlobalTranslation.x, entity.GlobalTranslation.z);
|
||||
Array entities = entitiesNode.GetChildren();
|
||||
foreach (Spatial entity in entities) {
|
||||
Vector2 entityPlaneCoords = new(entity.GlobalTranslation.x, entity.GlobalTranslation.z);
|
||||
HexCell entityCell = _tileWorld.HexGrid.GetHexAt(entityPlaneCoords);
|
||||
_tileWorld.MarkCellUnwalkable(entityCell);
|
||||
Vector2 cellPlaneCoords = _hexGrid.GetHexCenterFromOffset(entityCell.OffsetCoords);
|
||||
|
@ -68,8 +62,7 @@ public class NavigationTests : Spatial
|
|||
}
|
||||
}
|
||||
|
||||
public void OnWorldGenerated()
|
||||
{
|
||||
public void OnWorldGenerated() {
|
||||
_streamContainer.OnWorldGenerated();
|
||||
|
||||
// Properly place the Player
|
||||
|
@ -80,7 +73,7 @@ public class NavigationTests : Spatial
|
|||
playerTransform.origin = worldCenterTileCoords;
|
||||
_player.Transform = playerTransform;
|
||||
|
||||
ImageTexture newWorldTexture = new ImageTexture();
|
||||
ImageTexture newWorldTexture = new();
|
||||
newWorldTexture.CreateFromImage(_tileWorld.ColormapImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
|
||||
|
@ -90,57 +83,49 @@ public class NavigationTests : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void UpdateCurrentTile(HexCell tile)
|
||||
{
|
||||
if (_currentTile.AxialCoords == tile.AxialCoords)
|
||||
{
|
||||
public void UpdateCurrentTile(HexCell tile) {
|
||||
if (_currentTile.AxialCoords == tile.AxialCoords) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_lastTile = _currentTile;
|
||||
_currentTile = tile;
|
||||
|
||||
|
||||
GD.Print("Current tile: " + _currentTile.OffsetCoords);
|
||||
|
||||
if (_lastTile.OffsetCoords != _currentTile.OffsetCoords && _editorUi != null)
|
||||
{
|
||||
if (_lastTile.OffsetCoords != _currentTile.OffsetCoords && _editorUi != null) {
|
||||
_editorUi.currentTileOffset = _currentTile.OffsetCoords;
|
||||
}
|
||||
|
||||
|
||||
Vector2 planeCoords = _hexGrid.GetHexCenterFromOffset(_currentTile.OffsetCoords);
|
||||
Transform tileTransform = Transform.Identity;
|
||||
tileTransform.origin.x = planeCoords.x;
|
||||
tileTransform.origin.y = _tileWorld.GetHeightAtOffset(_currentTile.OffsetCoords) + 0.1f;
|
||||
tileTransform.origin.z = planeCoords.y;
|
||||
|
||||
|
||||
_mouseHighlight.Transform = tileTransform;
|
||||
}
|
||||
|
||||
|
||||
public void OnGroundLayerInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||
int shapeIndex)
|
||||
{
|
||||
int shapeIndex) {
|
||||
UpdateCurrentTile(_hexGrid.GetHexAt(new Vector2(position.x, position.z)));
|
||||
}
|
||||
|
||||
public void OnTileClicked(HexTile3D tile)
|
||||
{
|
||||
if (_editorUi != null)
|
||||
{
|
||||
public void OnTileClicked(HexTile3D tile) {
|
||||
if (_editorUi != null) {
|
||||
_editorUi.OnTileClicked(tile.OffsetCoords);
|
||||
|
||||
if (_editorUi.CurrentInputMode == EditorUI.InputMode.Navigate)
|
||||
{
|
||||
if (_editorUi.CurrentInputMode == EditorUI.InputMode.Navigate) {
|
||||
_playerNavigationComponent.FindPath(_player, _player.GlobalTranslation, tile.GlobalTranslation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnTileHovered(HexTile3D tile)
|
||||
{
|
||||
public void OnTileHovered(HexTile3D tile) {
|
||||
UpdateCurrentTile(tile.Cell);
|
||||
|
||||
|
||||
Debug.Assert(_playerNavigationComponent != null);
|
||||
|
||||
_playerNavigationComponent.FindPath(_player, _player.GlobalTranslation, tile.GlobalTranslation);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,11 @@
|
|||
public class LookupWorldSystem : IWorldSystemInterface
|
||||
{
|
||||
public void RegisterEntityComponent(Entity entity, Component component)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
using System;
|
||||
|
||||
public class LookupWorldSystem : IWorldSystemInterface {
|
||||
public void RegisterEntityComponent(Entity entity, Component component) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Update(float delta)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
public void Update(float delta) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
public interface IWorldSystemInterface
|
||||
{
|
||||
public interface IWorldSystemInterface {
|
||||
void RegisterEntityComponent(Entity entity, Component component);
|
||||
void Update(float delta);
|
||||
}
|
|
@ -1,27 +1,22 @@
|
|||
using Godot;
|
||||
using GoDotTest;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
using GoDotTest;
|
||||
using Xunit;
|
||||
|
||||
public class HexCellTests : TestClass
|
||||
{
|
||||
public HexCellTests(Node testScene) : base(testScene)
|
||||
{
|
||||
}
|
||||
public class HexCellTests : TestClass {
|
||||
public HexCellTests(Node testScene) : base(testScene) { }
|
||||
|
||||
[Test]
|
||||
public void TestHexCellSimple()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestHexCellSimple() {
|
||||
HexCell cell = new();
|
||||
Debug.Assert(cell.CubeCoords == new Vector3(0, 0, 0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHexCellEqualityInequality()
|
||||
{
|
||||
HexCell cellA = new HexCell();
|
||||
HexCell cellB = new HexCell();
|
||||
public void TestHexCellEqualityInequality() {
|
||||
HexCell cellA = new();
|
||||
HexCell cellB = new();
|
||||
|
||||
cellA.AxialCoords = new Vector2(2, 3);
|
||||
cellB.AxialCoords = new Vector2(2, 3);
|
||||
|
@ -37,9 +32,8 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestAxialCoords()
|
||||
{
|
||||
HexCell cell = new HexCell(1, 1, -2);
|
||||
public void TestAxialCoords() {
|
||||
HexCell cell = new(1, 1, -2);
|
||||
Debug.Assert(cell.AxialCoords == new Vector2(1, 1));
|
||||
|
||||
cell = new HexCell(1, -1);
|
||||
|
@ -51,9 +45,8 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestAxialCoordsRounded()
|
||||
{
|
||||
HexCell cell = new HexCell(new Vector2(-0.1f, 0.6f));
|
||||
public void TestAxialCoordsRounded() {
|
||||
HexCell cell = new(new Vector2(-0.1f, 0.6f));
|
||||
Debug.Assert(cell.CubeCoords == new Vector3(0, 1, -1));
|
||||
|
||||
cell = new HexCell(new Vector2(4.2f, -5.5f));
|
||||
|
@ -61,17 +54,15 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestConversion()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestConversion() {
|
||||
HexCell cell = new();
|
||||
Debug.Assert(cell.AxialToCubeCoords(new Vector2(2, 1)) == new Vector3(2, 1, -3));
|
||||
Debug.Assert(cell.AxialToCubeCoords(new Vector2(-1, -1)) == new Vector3(-1, -1, 2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRounding()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestRounding() {
|
||||
HexCell cell = new();
|
||||
Debug.Assert(cell.RoundCoords(new Vector3(0.1f, 0.5f, -0.6f)) == new Vector3(0, 1, -1));
|
||||
Debug.Assert(cell.RoundCoords(new Vector3(-0.4f, -1.3f, 1.7f)) == new Vector3(-1, -1, 2));
|
||||
|
||||
|
@ -80,9 +71,8 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestCoords()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestCoords() {
|
||||
HexCell cell = new();
|
||||
|
||||
// from cubic positive
|
||||
cell.CubeCoords = new Vector3(2, 1, -3);
|
||||
|
@ -104,9 +94,8 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestNearby()
|
||||
{
|
||||
HexCell cell = new HexCell(new Vector2(1, 2));
|
||||
public void TestNearby() {
|
||||
HexCell cell = new(new Vector2(1, 2));
|
||||
|
||||
// adjacent
|
||||
HexCell otherCell = cell.GetAdjacent(HexCell.DIR_N);
|
||||
|
@ -128,9 +117,8 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestDistance()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestDistance() {
|
||||
HexCell cell = new();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
Debug.Assert(cell.DistanceTo(new HexCell(new Vector2(0, 0))) == 3);
|
||||
|
@ -140,80 +128,71 @@ public class HexCellTests : TestClass
|
|||
|
||||
|
||||
[Test]
|
||||
public void TestLineTo()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestLineTo() {
|
||||
HexCell cell = new();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
HexCell[] path = cell.LineTo(new HexCell(5, 2));
|
||||
|
||||
HexCell[] pathExpected =
|
||||
{
|
||||
new HexCell(1, 2),
|
||||
new HexCell(2, 2),
|
||||
new HexCell(3, 2),
|
||||
new HexCell(4, 2),
|
||||
new HexCell(5, 2)
|
||||
HexCell[] pathExpected = {
|
||||
new(1, 2),
|
||||
new(2, 2),
|
||||
new(3, 2),
|
||||
new(4, 2),
|
||||
new(5, 2)
|
||||
};
|
||||
|
||||
Debug.Assert(path.Length == pathExpected.Length);
|
||||
|
||||
foreach (int index in Enumerable.Range(0, path.Length))
|
||||
{
|
||||
foreach (int index in Enumerable.Range(0, path.Length)) {
|
||||
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestLineToAngled()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestLineToAngled() {
|
||||
HexCell cell = new();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
HexCell[] path = cell.LineTo(new HexCell(5, 4));
|
||||
|
||||
HexCell[] pathExpected =
|
||||
{
|
||||
new HexCell(1, 2),
|
||||
new HexCell(2, 2),
|
||||
new HexCell(2, 3),
|
||||
new HexCell(3, 3),
|
||||
new HexCell(4, 3),
|
||||
new HexCell(4, 4),
|
||||
new HexCell(5, 4)
|
||||
HexCell[] pathExpected = {
|
||||
new(1, 2),
|
||||
new(2, 2),
|
||||
new(2, 3),
|
||||
new(3, 3),
|
||||
new(4, 3),
|
||||
new(4, 4),
|
||||
new(5, 4)
|
||||
};
|
||||
|
||||
Debug.Assert(path.Length == pathExpected.Length);
|
||||
|
||||
foreach (int index in Enumerable.Range(0, path.Length))
|
||||
{
|
||||
foreach (int index in Enumerable.Range(0, path.Length)) {
|
||||
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestLineEdge()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestLineEdge() {
|
||||
HexCell cell = new();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
HexCell[] path = cell.LineTo(new HexCell(3, 4));
|
||||
|
||||
HexCell[] pathExpected =
|
||||
{
|
||||
new HexCell(1, 2),
|
||||
new HexCell(2, 2),
|
||||
new HexCell(2, 3),
|
||||
new HexCell(2, 4),
|
||||
new HexCell(3, 4)
|
||||
HexCell[] pathExpected = {
|
||||
new(1, 2),
|
||||
new(2, 2),
|
||||
new(2, 3),
|
||||
new(2, 4),
|
||||
new(3, 4)
|
||||
};
|
||||
|
||||
Debug.Assert(path.Length == pathExpected.Length);
|
||||
|
||||
foreach (int index in Enumerable.Range(0, path.Length))
|
||||
{
|
||||
foreach (int index in Enumerable.Range(0, path.Length)) {
|
||||
Debug.Print("index: " + index + " path: " + path[index].AxialCoords + " expected: " +
|
||||
pathExpected[index].AxialCoords);
|
||||
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
||||
|
@ -221,9 +200,8 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestCellDirections()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestCellDirections() {
|
||||
HexCell cell = new();
|
||||
|
||||
HexCell cellN = HexCell.FromOffsetCoords(new Vector2(0, 1));
|
||||
HexCell cellNW = HexCell.FromOffsetCoords(new Vector2(-1, 0));
|
||||
|
@ -252,8 +230,7 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestCellDirectionsNonzeroReference()
|
||||
{
|
||||
public void TestCellDirectionsNonzeroReference() {
|
||||
HexCell cell = HexCell.FromOffsetCoords(new Vector2(-4, -3));
|
||||
|
||||
HexCell cellN = HexCell.FromOffsetCoords(new Vector2(-4, -2));
|
||||
|
@ -283,9 +260,8 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestNextCellAlongLine()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestNextCellAlongLine() {
|
||||
HexCell cell = new();
|
||||
HexCell cellN = HexCell.FromOffsetCoords(new Vector2(0, 1));
|
||||
HexCell cellNE = HexCell.FromOffsetCoords(new Vector2(1, 0));
|
||||
HexCell cellSE = HexCell.FromOffsetCoords(new Vector2(1, -1));
|
||||
|
|
|
@ -7,50 +7,43 @@ using Xunit;
|
|||
|
||||
namespace GodotComponentTest.tests;
|
||||
|
||||
public class HexGridPathFindingTests : TestClass
|
||||
{
|
||||
public class HexGridPathFindingTests : TestClass {
|
||||
private HexGrid _hexGrid;
|
||||
private HexCell _hexCell;
|
||||
|
||||
private HexCell _positionA = new HexCell(new Vector2(2, 0));
|
||||
private HexCell _positionB = new HexCell(new Vector2(4, 2));
|
||||
private HexCell _positionC = new HexCell(new Vector2(7, 0));
|
||||
private HexCell _positionD = new HexCell(new Vector2(5, 0));
|
||||
private HexCell _positionE = new HexCell(new Vector2(2, 2));
|
||||
private HexCell _positionF = new HexCell(new Vector2(1, 3));
|
||||
private HexCell _positionG = new HexCell(new Vector2(1, 0));
|
||||
private readonly HexCell _positionA = new(new Vector2(2, 0));
|
||||
private readonly HexCell _positionB = new(new Vector2(4, 2));
|
||||
private readonly HexCell _positionC = new(new Vector2(7, 0));
|
||||
private readonly HexCell _positionD = new(new Vector2(5, 0));
|
||||
private HexCell _positionE = new(new Vector2(2, 2));
|
||||
private HexCell _positionF = new(new Vector2(1, 3));
|
||||
private readonly HexCell _positionG = new(new Vector2(1, 0));
|
||||
|
||||
private Vector2[] _obstacles =
|
||||
{
|
||||
new Vector2(2, 1),
|
||||
new Vector2(3, 1),
|
||||
new Vector2(4, 1),
|
||||
new Vector2(1, 2),
|
||||
new Vector2(3, 2),
|
||||
new Vector2(1, 3),
|
||||
new Vector2(2, 3),
|
||||
private readonly Vector2[] _obstacles = {
|
||||
new(2, 1),
|
||||
new(3, 1),
|
||||
new(4, 1),
|
||||
new(1, 2),
|
||||
new(3, 2),
|
||||
new(1, 3),
|
||||
new(2, 3)
|
||||
};
|
||||
|
||||
public HexGridPathFindingTests(Node testScene) : base(testScene)
|
||||
{
|
||||
}
|
||||
public HexGridPathFindingTests(Node testScene) : base(testScene) { }
|
||||
|
||||
[Setup]
|
||||
public void Setup()
|
||||
{
|
||||
public void Setup() {
|
||||
_hexGrid = new HexGrid();
|
||||
_hexCell = new HexCell();
|
||||
|
||||
_hexGrid.SetBounds(new Vector2(0, 0), new Vector2(7, 4));
|
||||
foreach (Vector2 obstacle in _obstacles)
|
||||
{
|
||||
foreach (Vector2 obstacle in _obstacles) {
|
||||
_hexGrid.AddObstacle(new HexCell(obstacle));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBounds()
|
||||
{
|
||||
public void TestBounds() {
|
||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(0, 0)));
|
||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(0, 4)));
|
||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(7, 0)));
|
||||
|
@ -63,9 +56,8 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestNegativeBounds()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
public void TestNegativeBounds() {
|
||||
HexGrid grid = new();
|
||||
grid.SetBounds(new Vector2(-5, -5), new Vector2(-2, -2));
|
||||
|
||||
Assert.Equal(grid.PathCostDefault, grid.GetHexCost(new Vector2(-2, -2)));
|
||||
|
@ -76,9 +68,8 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestNegativeBoundsAlt()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
public void TestNegativeBoundsAlt() {
|
||||
HexGrid grid = new();
|
||||
grid.SetBounds(new Vector2(-3, -3), new Vector2(2, 2));
|
||||
|
||||
Assert.Equal(grid.PathCostDefault, grid.GetHexCost(new Vector2(-3, -3)));
|
||||
|
@ -89,8 +80,7 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestGridObstacles()
|
||||
{
|
||||
public void TestGridObstacles() {
|
||||
Assert.Equal(_obstacles.Length, _hexGrid.Obstacles.Count);
|
||||
|
||||
// Adding an obstacle
|
||||
|
@ -110,8 +100,7 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestHexCost()
|
||||
{
|
||||
public void TestHexCost() {
|
||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(1, 1)));
|
||||
Assert.Equal(0, _hexGrid.GetHexCost(new HexCell(new Vector3(2, 1, -3))));
|
||||
|
||||
|
@ -120,14 +109,12 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestMoveCost()
|
||||
{
|
||||
public void TestMoveCost() {
|
||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetMoveCost(new Vector2(0, 0), HexCell.DIR_N));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMovieCostCumulative()
|
||||
{
|
||||
public void TestMovieCostCumulative() {
|
||||
_hexGrid.AddObstacle(new Vector2(0, 0), 1);
|
||||
_hexGrid.AddObstacle(new Vector2(0, 1), 2);
|
||||
_hexGrid.AddBarrier(new Vector2(0, 0), HexCell.DIR_N, 4);
|
||||
|
@ -138,12 +125,10 @@ public class HexGridPathFindingTests : TestClass
|
|||
Assert.Equal(14, _hexGrid.GetMoveCost(new Vector2(0, 0), HexCell.DIR_N));
|
||||
}
|
||||
|
||||
void ComparePath(List<HexCell> expected, List<HexCell> path)
|
||||
{
|
||||
private void ComparePath(List<HexCell> expected, List<HexCell> path) {
|
||||
Assert.Equal(expected.Count, path.Count());
|
||||
|
||||
foreach (int i in Enumerable.Range(0, Math.Min(expected.Count, path.Count())))
|
||||
{
|
||||
foreach (int i in Enumerable.Range(0, Math.Min(expected.Count, path.Count()))) {
|
||||
HexCell pathCell = path[i];
|
||||
HexCell expectedCell = expected[i];
|
||||
Assert.Equal(expectedCell.AxialCoords, pathCell.AxialCoords);
|
||||
|
@ -151,10 +136,8 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestStraightLine()
|
||||
{
|
||||
List<HexCell> expectedPath = new List<HexCell>()
|
||||
{
|
||||
public void TestStraightLine() {
|
||||
List<HexCell> expectedPath = new() {
|
||||
_positionA,
|
||||
new HexCell(new Vector2(3, 0)),
|
||||
new HexCell(new Vector2(4, 0)),
|
||||
|
@ -184,10 +167,8 @@ public class HexGridPathFindingTests : TestClass
|
|||
// }
|
||||
|
||||
[Test]
|
||||
public void TestObstacle()
|
||||
{
|
||||
List<HexCell> expectedPath = new List<HexCell>()
|
||||
{
|
||||
public void TestObstacle() {
|
||||
List<HexCell> expectedPath = new() {
|
||||
_positionA,
|
||||
new HexCell(new Vector2(3, 0)),
|
||||
new HexCell(new Vector2(4, 0)),
|
||||
|
@ -200,10 +181,8 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestWalls()
|
||||
{
|
||||
Vector3[] walls =
|
||||
{
|
||||
public void TestWalls() {
|
||||
Vector3[] walls = {
|
||||
HexCell.DIR_N,
|
||||
HexCell.DIR_NE,
|
||||
HexCell.DIR_SE,
|
||||
|
@ -212,13 +191,11 @@ public class HexGridPathFindingTests : TestClass
|
|||
HexCell.DIR_NW
|
||||
};
|
||||
|
||||
foreach (Vector3 wall in walls)
|
||||
{
|
||||
foreach (Vector3 wall in walls) {
|
||||
_hexGrid.AddBarrier(_positionG, wall);
|
||||
}
|
||||
|
||||
List<HexCell> expectedPath = new List<HexCell>()
|
||||
{
|
||||
List<HexCell> expectedPath = new() {
|
||||
_positionA,
|
||||
new HexCell(new Vector2(1, 1)),
|
||||
new HexCell(new Vector2(0, 1)),
|
||||
|
@ -230,13 +207,11 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestSlopes()
|
||||
{
|
||||
public void TestSlopes() {
|
||||
_hexGrid.AddBarrier(_positionG, HexCell.DIR_NE, 3);
|
||||
_hexGrid.AddBarrier(_positionG, HexCell.DIR_N, _hexGrid.PathCostDefault - 0.1f);
|
||||
|
||||
List<HexCell> expectedPath = new List<HexCell>()
|
||||
{
|
||||
List<HexCell> expectedPath = new() {
|
||||
_positionA,
|
||||
new HexCell(new Vector2(1, 1)),
|
||||
_positionG
|
||||
|
@ -246,20 +221,17 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestRoughTerrain()
|
||||
{
|
||||
List<HexCell> shortPath = new List<HexCell>()
|
||||
{
|
||||
public void TestRoughTerrain() {
|
||||
List<HexCell> shortPath = new() {
|
||||
_positionA,
|
||||
new HexCell(new Vector2(3, 0)),
|
||||
new HexCell(new Vector2(4, 0)),
|
||||
_positionD,
|
||||
new HexCell(new Vector2(5, 1)),
|
||||
_positionB,
|
||||
_positionB
|
||||
};
|
||||
|
||||
List<HexCell> longPath = new List<HexCell>()
|
||||
{
|
||||
List<HexCell> longPath = new() {
|
||||
_positionA,
|
||||
new HexCell(new Vector2(1, 1)),
|
||||
new HexCell(new Vector2(0, 2)),
|
||||
|
@ -268,7 +240,7 @@ public class HexGridPathFindingTests : TestClass
|
|||
new HexCell(new Vector2(1, 4)),
|
||||
new HexCell(new Vector2(2, 4)),
|
||||
new HexCell(new Vector2(3, 3)),
|
||||
_positionB,
|
||||
_positionB
|
||||
};
|
||||
|
||||
_hexGrid.PathCostDefault = 1f;
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Godot;
|
||||
using GoDotTest;
|
||||
using System.Diagnostics;
|
||||
using Xunit;
|
||||
|
||||
public class HexGridTests : TestClass
|
||||
{
|
||||
public HexGridTests(Node testScene) : base(testScene)
|
||||
{
|
||||
}
|
||||
public class HexGridTests : TestClass {
|
||||
public HexGridTests(Node testScene) : base(testScene) { }
|
||||
|
||||
[Test]
|
||||
public void TestGetAt()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
public void TestGetAt() {
|
||||
HexGrid grid = new();
|
||||
float w = grid.HexSize.x;
|
||||
float h = grid.HexSize.y;
|
||||
|
||||
|
@ -24,9 +20,8 @@ public class HexGridTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestGetCellsForLineSimple()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
public void TestGetCellsForLineSimple() {
|
||||
HexGrid grid = new();
|
||||
|
||||
List<HexCell> lineCells =
|
||||
grid.GetCellsForLine(new Vector2(0, 0), grid.GetHexCenterFromOffset(new Vector2(0, 2)));
|
||||
|
@ -46,9 +41,8 @@ public class HexGridTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestGetCellsDiagonal()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
public void TestGetCellsDiagonal() {
|
||||
HexGrid grid = new();
|
||||
|
||||
List<HexCell> lineCells =
|
||||
grid.GetCellsForLine(new Vector2(0, 0), grid.GetHexCenterFromOffset(new Vector2(2, 1)));
|
||||
|
@ -68,9 +62,8 @@ public class HexGridTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestGetCellsForLineAlongEdge()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
public void TestGetCellsForLineAlongEdge() {
|
||||
HexGrid grid = new();
|
||||
|
||||
List<HexCell> lineCells =
|
||||
grid.GetCellsForLine(new Vector2(0, -0.0001f), grid.GetHexCenterFromOffset(new Vector2(2, 0)));
|
||||
|
@ -90,13 +83,12 @@ public class HexGridTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void GetTestsInfiniteLoop()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
|
||||
Vector2 fromPlane = new Vector2(-2.31678f, -5.024752f);
|
||||
Vector2 toPlane = new Vector2(-2.599937f, -6.134028f);
|
||||
|
||||
public void GetTestsInfiniteLoop() {
|
||||
HexGrid grid = new();
|
||||
|
||||
Vector2 fromPlane = new(-2.31678f, -5.024752f);
|
||||
Vector2 toPlane = new(-2.599937f, -6.134028f);
|
||||
|
||||
List<HexCell> cellList = grid.GetCellsForLine(fromPlane, toPlane);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
using Godot;
|
||||
using GoDotTest;
|
||||
|
||||
public class NavigationComponentTests : TestClass
|
||||
{
|
||||
public class NavigationComponentTests : TestClass {
|
||||
private readonly Node _testScene;
|
||||
|
||||
private readonly PackedScene _WorldScene = GD.Load<PackedScene>("res://scenes/World.tscn");
|
||||
|
@ -10,14 +9,12 @@ public class NavigationComponentTests : TestClass
|
|||
private NavigationComponent _navigationComponent;
|
||||
private World _world;
|
||||
|
||||
public NavigationComponentTests(Node testScene) : base(testScene)
|
||||
{
|
||||
public NavigationComponentTests(Node testScene) : base(testScene) {
|
||||
_testScene = testScene;
|
||||
}
|
||||
|
||||
[Setup]
|
||||
public void Setup()
|
||||
{
|
||||
public void Setup() {
|
||||
_world = (World)_WorldScene.Instance();
|
||||
_world.HexGrid = new HexGrid();
|
||||
_testScene.AddChild(_world);
|
||||
|
|
|
@ -6,41 +6,35 @@ using Xunit;
|
|||
|
||||
namespace GodotComponentTest.tests;
|
||||
|
||||
public class Plane2DTests : TestClass
|
||||
{
|
||||
public Plane2DTests(Node testScene) : base(testScene)
|
||||
{
|
||||
public class Plane2DTests : TestClass {
|
||||
public Plane2DTests(Node testScene) : base(testScene) { }
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistSimple() {
|
||||
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(0, -1));
|
||||
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 0)) - 1) < float.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 1))) < float.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 2)) + 1) < float.Epsilon);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistSimple()
|
||||
{
|
||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(0, -1));
|
||||
public void Plane2DDistAngled() {
|
||||
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 0)) - 1) < Single.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 1))) < Single.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 2)) + 1) < Single.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 1))) < float.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 0)) - MathF.Sqrt(2) / 2) < float.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(-1, 0))) < float.Epsilon);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistAngled()
|
||||
{
|
||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 1))) < Single.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 0)) - MathF.Sqrt(2) / 2) < Single.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(-1, 0))) < Single.Epsilon);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistLineSegment()
|
||||
{
|
||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
public void Plane2DDistLineSegment() {
|
||||
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
|
||||
Assert.True(
|
||||
Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(-1, 0)) - 1) < Single.Epsilon);
|
||||
Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(-1, 0)) - 1) < float.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(0, 1)) - 1) <
|
||||
Single.Epsilon);
|
||||
float.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(1, -1).Normalized()) +
|
||||
MathF.Sqrt(2) / 2) < Plane2D.DistancePrecision);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(-1, 1).Normalized()) -
|
||||
|
@ -48,22 +42,20 @@ public class Plane2DTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DTestIsParallel()
|
||||
{
|
||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
public void Plane2DTestIsParallel() {
|
||||
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
|
||||
Assert.True(plane2D.IsParallelToDir(new Vector2(1, 1.00001f).Normalized()));
|
||||
Assert.True(plane2D.IsParallelToDir(new Vector2(1, 0.99999f).Normalized()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistLineSegmentParallel()
|
||||
{
|
||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
public void Plane2DDistLineSegmentParallel() {
|
||||
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
|
||||
Assert.Equal(Single.PositiveInfinity,
|
||||
Assert.Equal(float.PositiveInfinity,
|
||||
plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(1, 1.00001f).Normalized()));
|
||||
Assert.Equal(Single.NegativeInfinity,
|
||||
Assert.Equal(float.NegativeInfinity,
|
||||
plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(1, 0.99999f).Normalized()));
|
||||
}
|
||||
}
|
|
@ -1,37 +1,29 @@
|
|||
using System;
|
||||
using Godot;
|
||||
using GodotComponentTest.utils;
|
||||
using GoDotTest;
|
||||
using Xunit;
|
||||
|
||||
namespace GodotComponentTest.tests;
|
||||
|
||||
public class StreamContainerTests : TestClass
|
||||
{
|
||||
private Node _testScene = null;
|
||||
public class StreamContainerTests : TestClass {
|
||||
private readonly Node _testScene;
|
||||
private TileWorld _tileWorld;
|
||||
private StreamContainer _streamContainer;
|
||||
|
||||
private PackedScene _tileWorldScene = GD.Load<PackedScene>("res://scenes/TileWorld.tscn");
|
||||
private PackedScene _streamContainerScene = GD.Load<PackedScene>("res://scenes/StreamContainer.tscn");
|
||||
|
||||
public StreamContainerTests(Node testScene) : base(testScene)
|
||||
{
|
||||
|
||||
private readonly PackedScene _tileWorldScene = GD.Load<PackedScene>("res://scenes/TileWorld.tscn");
|
||||
private readonly PackedScene _streamContainerScene = GD.Load<PackedScene>("res://scenes/StreamContainer.tscn");
|
||||
|
||||
public StreamContainerTests(Node testScene) : base(testScene) {
|
||||
_testScene = testScene;
|
||||
}
|
||||
|
||||
[Setup]
|
||||
public void Setup()
|
||||
{
|
||||
_tileWorld = (TileWorld) _tileWorldScene.Instance();
|
||||
public void Setup() {
|
||||
_tileWorld = (TileWorld)_tileWorldScene.Instance();
|
||||
_tileWorld.HexGrid = new HexGrid();
|
||||
_testScene.AddChild(_tileWorld);
|
||||
_streamContainer = (StreamContainer) _streamContainerScene.Instance();
|
||||
_streamContainer = (StreamContainer)_streamContainerScene.Instance();
|
||||
|
||||
foreach (Node node in _testScene.GetChildren())
|
||||
{
|
||||
if (node is TileWorld)
|
||||
{
|
||||
foreach (Node node in _testScene.GetChildren()) {
|
||||
if (node is TileWorld) {
|
||||
_streamContainer.World = node.GetPath();
|
||||
}
|
||||
}
|
||||
|
@ -40,20 +32,17 @@ public class StreamContainerTests : TestClass
|
|||
}
|
||||
|
||||
[Cleanup]
|
||||
public void Cleanup()
|
||||
{
|
||||
foreach (Node node in _testScene.GetChildren())
|
||||
{
|
||||
public void Cleanup() {
|
||||
foreach (Node node in _testScene.GetChildren()) {
|
||||
node.QueueFree();
|
||||
}
|
||||
|
||||
|
||||
_streamContainer.QueueFree();
|
||||
_tileWorld.QueueFree();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistSimple()
|
||||
{
|
||||
public void Plane2DDistSimple() {
|
||||
// _streamContainer.UpdateRects(new Vector2(0, 0));
|
||||
// _streamContainer.UpdateRects(new Vector2(1, 0));
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@ using System.Reflection;
|
|||
using Godot;
|
||||
using GoDotTest;
|
||||
|
||||
public class Tests : Control
|
||||
{
|
||||
public override async void _Ready()
|
||||
=> await GoTest.RunTests(Assembly.GetExecutingAssembly(), this);
|
||||
public class Tests : Control {
|
||||
public override async void _Ready() {
|
||||
await GoTest.RunTests(Assembly.GetExecutingAssembly(), this);
|
||||
}
|
||||
}
|
|
@ -1,76 +1,63 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
|
||||
namespace GodotComponentTest.utils;
|
||||
|
||||
public class DebugGeometry : Spatial
|
||||
{
|
||||
public class DebugGeometry : Spatial {
|
||||
private ImmediateGeometry _immediateGeometry;
|
||||
|
||||
private List<Transform> _transformStack;
|
||||
private Transform _currentTransform = Transform.Identity;
|
||||
private Transform _currentTransform = Transform.Identity;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
base._Ready();
|
||||
|
||||
|
||||
_immediateGeometry = (ImmediateGeometry)FindNode("ImmediateGeometry");
|
||||
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
public void Clear() {
|
||||
_immediateGeometry.Clear();
|
||||
_transformStack = new List<Transform>();
|
||||
_transformStack.Add(Transform.Identity);
|
||||
}
|
||||
|
||||
public void PushTransform(Transform transform)
|
||||
{
|
||||
public void PushTransform(Transform transform) {
|
||||
_transformStack.Add(transform);
|
||||
_currentTransform = transform;
|
||||
}
|
||||
|
||||
public void PushTranslated(Vector3 offset)
|
||||
{
|
||||
public void PushTranslated(Vector3 offset) {
|
||||
PushTransform(_currentTransform.Translated(offset));
|
||||
}
|
||||
|
||||
public void PopTransform()
|
||||
{
|
||||
public void PopTransform() {
|
||||
_transformStack.RemoveAt(_transformStack.Count - 1);
|
||||
_currentTransform = PeekTransform();
|
||||
}
|
||||
|
||||
public Transform PeekTransform()
|
||||
{
|
||||
public Transform PeekTransform() {
|
||||
return _transformStack[_transformStack.Count - 1];
|
||||
}
|
||||
|
||||
public void Begin(Mesh.PrimitiveType primitive, Texture texture = null)
|
||||
{
|
||||
public void Begin(Mesh.PrimitiveType primitive, Texture texture = null) {
|
||||
_immediateGeometry.Begin(primitive, texture);
|
||||
}
|
||||
|
||||
public void End()
|
||||
{
|
||||
public void End() {
|
||||
_immediateGeometry.End();
|
||||
}
|
||||
|
||||
public void AddVertex(Vector3 vertex)
|
||||
{
|
||||
public void AddVertex(Vector3 vertex) {
|
||||
_immediateGeometry.AddVertex(_currentTransform.Xform(vertex));
|
||||
}
|
||||
|
||||
public void SetColor(Color color)
|
||||
{
|
||||
public void SetColor(Color color) {
|
||||
_immediateGeometry.SetColor(color);
|
||||
}
|
||||
|
||||
public void AddBox(Vector3 extents)
|
||||
{
|
||||
|
||||
public void AddBox(Vector3 extents) {
|
||||
Transform currentTransform = PeekTransform();
|
||||
// bottom square
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||
|
@ -81,7 +68,7 @@ public class DebugGeometry : Spatial
|
|||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||
|
||||
|
||||
// top square
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * 0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * 0.5f, extents.z * 0.5f));
|
||||
|
@ -91,15 +78,15 @@ public class DebugGeometry : Spatial
|
|||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * 0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * 0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * 0.5f, extents.z * -0.5f));
|
||||
|
||||
|
||||
// side
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * 0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * 0.5f, extents.z * 0.5f));
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * -0.5f, extents.z * 0.5f));
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * -0.5f, extents.z * 0.5f));
|
||||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * 0.5f, extents.z * 0.5f));
|
||||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * -0.5f, extents.z * 0.5f));
|
||||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * 0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||
}
|
||||
}
|
|
@ -5,43 +5,39 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using Godot;
|
||||
|
||||
namespace Namespace
|
||||
{
|
||||
using UnderlyingType = UInt64;
|
||||
namespace Namespace;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
public class ExportFlagsEnumAttribute : ExportAttribute
|
||||
{
|
||||
public ExportFlagsEnumAttribute(Type enumType)
|
||||
: base(PropertyHint.Flags, GetFlagsEnumHintString(enumType))
|
||||
{ }
|
||||
using UnderlyingType = UInt64;
|
||||
|
||||
private static string GetFlagsEnumHintString(Type enumType)
|
||||
{
|
||||
Dictionary<UnderlyingType, List<string>> flagNamesByFlag = new Dictionary<UnderlyingType, List<string>>();
|
||||
UnderlyingType flag = (UnderlyingType)1;
|
||||
foreach (string name in Enum.GetNames(enumType))
|
||||
{
|
||||
UnderlyingType value = (UnderlyingType)Convert.ChangeType(Enum.Parse(enumType, name), typeof(UnderlyingType));
|
||||
while (value > flag)
|
||||
{
|
||||
if (!flagNamesByFlag.ContainsKey(flag))
|
||||
{
|
||||
flagNamesByFlag.Add(flag, new List<string>());
|
||||
}
|
||||
flag <<= 1;
|
||||
}
|
||||
if (value == flag)
|
||||
{
|
||||
if (!flagNamesByFlag.TryGetValue(flag, out List<string> names))
|
||||
{
|
||||
names = new List<string>();
|
||||
flagNamesByFlag.Add(flag, names);
|
||||
}
|
||||
names.Add(name);
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
public class ExportFlagsEnumAttribute : ExportAttribute {
|
||||
public ExportFlagsEnumAttribute(Type enumType)
|
||||
: base(PropertyHint.Flags, GetFlagsEnumHintString(enumType)) { }
|
||||
|
||||
private static string GetFlagsEnumHintString(Type enumType) {
|
||||
Dictionary<UnderlyingType, List<string>> flagNamesByFlag = new();
|
||||
UnderlyingType flag = 1;
|
||||
foreach (string name in Enum.GetNames(enumType)) {
|
||||
UnderlyingType value =
|
||||
(UnderlyingType)Convert.ChangeType(Enum.Parse(enumType, name), typeof(UnderlyingType));
|
||||
while (value > flag) {
|
||||
if (!flagNamesByFlag.ContainsKey(flag)) {
|
||||
flagNamesByFlag.Add(flag, new List<string>());
|
||||
}
|
||||
|
||||
flag <<= 1;
|
||||
}
|
||||
|
||||
if (value == flag) {
|
||||
if (!flagNamesByFlag.TryGetValue(flag, out List<string> names)) {
|
||||
names = new List<string>();
|
||||
flagNamesByFlag.Add(flag, names);
|
||||
}
|
||||
|
||||
names.Add(name);
|
||||
}
|
||||
return string.Join(", ", flagNamesByFlag.Values.Select(flagNames => string.Join(" / ", flagNames)));
|
||||
}
|
||||
|
||||
return string.Join(", ", flagNamesByFlag.Values.Select(flagNames => string.Join(" / ", flagNames)));
|
||||
}
|
||||
}
|
|
@ -1,11 +1,9 @@
|
|||
using System;
|
||||
using Godot;
|
||||
|
||||
public class NavigationPoint
|
||||
{
|
||||
public class NavigationPoint {
|
||||
[Flags]
|
||||
public enum NavigationFlags
|
||||
{
|
||||
public enum NavigationFlags {
|
||||
Position = 1,
|
||||
Orientation = 2
|
||||
}
|
||||
|
@ -16,52 +14,43 @@ public class NavigationPoint
|
|||
|
||||
public Vector3 WorldPosition = Vector3.Zero;
|
||||
|
||||
public NavigationPoint(Vector3 worldPosition)
|
||||
{
|
||||
public NavigationPoint(Vector3 worldPosition) {
|
||||
WorldPosition = worldPosition;
|
||||
Flags = NavigationFlags.Position;
|
||||
}
|
||||
|
||||
public NavigationPoint(Quat worldOrientation)
|
||||
{
|
||||
public NavigationPoint(Quat worldOrientation) {
|
||||
WorldOrientation = worldOrientation;
|
||||
Flags = NavigationFlags.Orientation;
|
||||
}
|
||||
|
||||
public NavigationPoint(Transform worldTransform)
|
||||
{
|
||||
public NavigationPoint(Transform worldTransform) {
|
||||
WorldPosition = worldTransform.origin;
|
||||
WorldOrientation = worldTransform.basis.Quat();
|
||||
WorldAngle = Globals.CalcPlaneAngle(worldTransform);
|
||||
|
||||
|
||||
Flags = NavigationFlags.Position | NavigationFlags.Orientation;
|
||||
}
|
||||
|
||||
public bool IsReached(Transform worldTransform)
|
||||
{
|
||||
var goalReached = false;
|
||||
var positionError = new Vector2(WorldPosition.x - worldTransform.origin.x,
|
||||
public bool IsReached(Transform worldTransform) {
|
||||
bool goalReached = false;
|
||||
Vector2 positionError = new Vector2(WorldPosition.x - worldTransform.origin.x,
|
||||
WorldPosition.z - worldTransform.origin.z);
|
||||
var positionErrorSquared = positionError.LengthSquared();
|
||||
float positionErrorSquared = positionError.LengthSquared();
|
||||
worldTransform.basis.Quat();
|
||||
var orientationError = Mathf.Abs(worldTransform.basis.Quat().AngleTo(WorldOrientation));
|
||||
var angleError = Mathf.Abs(Globals.CalcPlaneAngle(worldTransform) - WorldAngle);
|
||||
float orientationError = Mathf.Abs(worldTransform.basis.Quat().AngleTo(WorldOrientation));
|
||||
float angleError = Mathf.Abs(Globals.CalcPlaneAngle(worldTransform) - WorldAngle);
|
||||
|
||||
if (Flags.HasFlag(NavigationFlags.Position)
|
||||
&& Flags.HasFlag(NavigationFlags.Orientation)
|
||||
&& positionErrorSquared < Globals.EpsPositionSquared
|
||||
&& angleError < Globals.EpsRadians)
|
||||
{
|
||||
&& angleError < Globals.EpsRadians) {
|
||||
goalReached = true;
|
||||
}
|
||||
else if (Flags == NavigationFlags.Position &&
|
||||
positionErrorSquared < Globals.EpsPositionSquared)
|
||||
{
|
||||
} else if (Flags == NavigationFlags.Position &&
|
||||
positionErrorSquared < Globals.EpsPositionSquared) {
|
||||
goalReached = true;
|
||||
}
|
||||
else if (Flags == NavigationFlags.Orientation &&
|
||||
angleError < Globals.EpsRadians)
|
||||
{
|
||||
} else if (Flags == NavigationFlags.Orientation &&
|
||||
angleError < Globals.EpsRadians) {
|
||||
goalReached = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,47 +1,39 @@
|
|||
using System;
|
||||
using Godot;
|
||||
|
||||
namespace GodotComponentTest.utils;
|
||||
|
||||
public class Plane2D
|
||||
{
|
||||
public class Plane2D {
|
||||
public static readonly float DistancePrecision = 1.0e-5f;
|
||||
|
||||
private Vector2 _planePoint;
|
||||
public Vector2 Normal;
|
||||
|
||||
public Plane2D(Vector2 planePoint, Vector2 normal)
|
||||
{
|
||||
public Plane2D(Vector2 planePoint, Vector2 normal) {
|
||||
_planePoint = planePoint;
|
||||
Normal = normal;
|
||||
}
|
||||
|
||||
public float DistanceToPoint(Vector2 point)
|
||||
{
|
||||
public float DistanceToPoint(Vector2 point) {
|
||||
return (point - _planePoint).Dot(Normal);
|
||||
}
|
||||
|
||||
public bool IsParallelToDir(Vector2 dir)
|
||||
{
|
||||
public bool IsParallelToDir(Vector2 dir) {
|
||||
float normalDotDir = Normal.Dot(dir);
|
||||
|
||||
return (Mathf.Abs(normalDotDir) <= Plane2D.DistancePrecision);
|
||||
return Mathf.Abs(normalDotDir) <= DistancePrecision;
|
||||
}
|
||||
|
||||
public float DistanceToLineSegment(Vector2 point, Vector2 dir)
|
||||
{
|
||||
public float DistanceToLineSegment(Vector2 point, Vector2 dir) {
|
||||
float normalDotDir = Normal.Dot(dir);
|
||||
|
||||
if (Mathf.Abs(normalDotDir) > Plane2D.DistancePrecision)
|
||||
{
|
||||
if (Mathf.Abs(normalDotDir) > DistancePrecision) {
|
||||
return (_planePoint.Dot(Normal) - point.Dot(Normal)) / normalDotDir;
|
||||
}
|
||||
|
||||
if (normalDotDir < 0)
|
||||
{
|
||||
return Single.PositiveInfinity;
|
||||
if (normalDotDir < 0) {
|
||||
return float.PositiveInfinity;
|
||||
}
|
||||
|
||||
return Single.NegativeInfinity;
|
||||
return float.NegativeInfinity;
|
||||
}
|
||||
}
|
|
@ -1,23 +1,19 @@
|
|||
// Based on: allenchou.net/2015/04/game-math-precise-control-over-numeric-springing/
|
||||
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Godot;
|
||||
|
||||
public class SpringDamper
|
||||
{
|
||||
public class SpringDamper {
|
||||
public float omega = 1;
|
||||
public float zeta = 1;
|
||||
|
||||
public SpringDamper(float osc_freq = 1.0f, float osc_red = 0.1f, float osc_red_h = 1.0f)
|
||||
{
|
||||
public SpringDamper(float osc_freq = 1.0f, float osc_red = 0.1f, float osc_red_h = 1.0f) {
|
||||
Debug.Assert(osc_red > 0.001 && osc_red < 0.999);
|
||||
omega = osc_freq * 2 * Mathf.Pi;
|
||||
zeta = Mathf.Log(1.0f - osc_red) / (-omega * osc_red_h);
|
||||
}
|
||||
|
||||
public (float, float) Calc(float x, float v, float xt, float h)
|
||||
{
|
||||
public (float, float) Calc(float x, float v, float xt, float h) {
|
||||
float f = 1 + 2 * h * zeta * omega;
|
||||
float oo = omega * omega;
|
||||
float hoo = oo * h;
|
||||
|
@ -30,8 +26,7 @@ public class SpringDamper
|
|||
return (det_x * det_inv, det_v * det_inv);
|
||||
}
|
||||
|
||||
public (Vector3, Vector3) Calc(Vector3 x, Vector3 v, Vector3 xt, float h)
|
||||
{
|
||||
public (Vector3, Vector3) Calc(Vector3 x, Vector3 v, Vector3 xt, float h) {
|
||||
float f = 1 + 2 * h * zeta * omega;
|
||||
float oo = omega * omega;
|
||||
float hoo = oo * h;
|
||||
|
@ -44,27 +39,24 @@ public class SpringDamper
|
|||
return (det_x * det_inv, det_v * det_inv);
|
||||
}
|
||||
|
||||
public (Vector3, Vector3) CalcClampedSpeed(Vector3 x, Vector3 v, Vector3 xt, float h, float speedMax)
|
||||
{
|
||||
var defaultResult = Calc(x, v, xt, h);
|
||||
public (Vector3, Vector3) CalcClampedSpeed(Vector3 x, Vector3 v, Vector3 xt, float h, float speedMax) {
|
||||
(Vector3, Vector3) defaultResult = Calc(x, v, xt, h);
|
||||
|
||||
Vector3 x_new = defaultResult.Item1;
|
||||
Vector3 vel_new = (x_new - x) / h;
|
||||
float speed_new = vel_new.Length();
|
||||
|
||||
if (speed_new > speedMax)
|
||||
{
|
||||
vel_new = (vel_new / speed_new) * speedMax;
|
||||
if (speed_new > speedMax) {
|
||||
vel_new = vel_new / speed_new * speedMax;
|
||||
x_new = x + vel_new * h;
|
||||
}
|
||||
|
||||
return (x_new, vel_new);
|
||||
}
|
||||
|
||||
public (Vector3, Vector3) CalcClampedSpeedXZ(Vector3 x, Vector3 v, Vector3 xt, float h, float speedMax)
|
||||
{
|
||||
var result_x = Calc(x.x, v.x, xt.x, h);
|
||||
var result_z = Calc(x.z, v.z, xt.z, h);
|
||||
|
||||
public (Vector3, Vector3) CalcClampedSpeedXZ(Vector3 x, Vector3 v, Vector3 xt, float h, float speedMax) {
|
||||
(float, float) result_x = Calc(x.x, v.x, xt.x, h);
|
||||
(float, float) result_z = Calc(x.z, v.z, xt.z, h);
|
||||
|
||||
Vector3 x_new = x;
|
||||
Vector3 v_new = v;
|
||||
|
@ -74,24 +66,23 @@ public class SpringDamper
|
|||
|
||||
x_new.z = result_z.Item1;
|
||||
v_new.z = result_z.Item2;
|
||||
|
||||
Vector3 result_v_xz = new Vector3(
|
||||
|
||||
Vector3 result_v_xz = new(
|
||||
(result_x.Item1 - x.x) / h,
|
||||
0,
|
||||
(result_z.Item1 - x.z) / h);
|
||||
|
||||
|
||||
float speed_new = result_v_xz.Length();
|
||||
|
||||
if (speed_new > speedMax)
|
||||
{
|
||||
result_v_xz = (result_v_xz) / speed_new * speedMax;
|
||||
if (speed_new > speedMax) {
|
||||
result_v_xz = result_v_xz / speed_new * speedMax;
|
||||
x_new.x = x.x + result_v_xz.x * h;
|
||||
x_new.z = x.z + result_v_xz.z * h;
|
||||
}
|
||||
|
||||
v.x = result_v_xz.x;
|
||||
v.z = result_v_xz.z;
|
||||
|
||||
|
||||
return (x_new, v_new);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue