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