Compare commits
7 Commits
187dac2d85
...
cfb731c27e
Author | SHA1 | Date |
---|---|---|
Martin Felis | cfb731c27e | |
Martin Felis | bfd5eef2f5 | |
Martin Felis | 2109c6b6ec | |
Martin Felis | a37b028b39 | |
Martin Felis | fcc2fdb8d3 | |
Martin Felis | 71162f9420 | |
Martin Felis | d2611c6073 |
|
@ -1,14 +1,12 @@
|
|||
using Godot;
|
||||
|
||||
public static class Globals
|
||||
{
|
||||
public static class Globals {
|
||||
public const float EpsPosition = 0.01f;
|
||||
public const float EpsPositionSquared = EpsPosition * EpsPosition;
|
||||
public const float EpsRadians = 0.1f * Mathf.Pi / 180f;
|
||||
public const float EpsRadiansSquared = EpsRadians * EpsRadians;
|
||||
|
||||
public static float CalcPlaneAngle(Transform worldTransform)
|
||||
{
|
||||
public static float CalcPlaneAngle(Transform worldTransform) {
|
||||
return worldTransform.basis.x.SignedAngleTo(Vector3.Right.Rotated(Vector3.Up, Mathf.Pi * 0.5f), -Vector3.Up);
|
||||
}
|
||||
}
|
188
HexCell.cs
188
HexCell.cs
|
@ -3,18 +3,24 @@ using System.Linq;
|
|||
using Godot;
|
||||
using GodotComponentTest.utils;
|
||||
|
||||
public class HexCell : IEquatable<HexCell>
|
||||
{
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
public class HexCell : IEquatable<HexCell> {
|
||||
public override bool Equals(object obj) {
|
||||
if (ReferenceEquals(null, obj)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, obj)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj.GetType() != GetType()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Equals((HexCell)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
public override int GetHashCode() {
|
||||
return _cubeCoords.GetHashCode();
|
||||
}
|
||||
|
||||
|
@ -29,8 +35,7 @@ public class HexCell : IEquatable<HexCell>
|
|||
public static readonly Vector3 DIR_SW = new(-1, 0, 1);
|
||||
public static readonly Vector3 DIR_NW = new(-1, 1, 0);
|
||||
|
||||
public static readonly Vector3[] NeighborDirections =
|
||||
{
|
||||
public static readonly Vector3[] NeighborDirections = {
|
||||
DIR_N,
|
||||
DIR_NW,
|
||||
DIR_SW,
|
||||
|
@ -39,13 +44,13 @@ public class HexCell : IEquatable<HexCell>
|
|||
DIR_NE
|
||||
};
|
||||
|
||||
private static readonly Vector2 CornerNW = new Vector2(-Width / 4, -Height / 2);
|
||||
private static readonly Vector2 CornerNE = new Vector2(Width / 4, -Height / 2);
|
||||
private static readonly Vector2 CornerE = new Vector2(Width / 2, 0);
|
||||
private static readonly Vector2 CornerSE = new Vector2(Width / 4, Height / 2);
|
||||
private static readonly Vector2 CornerSW = new Vector2(-Width / 4, Height / 2);
|
||||
private static readonly Vector2 CornerW = new Vector2(-Width / 2, 0);
|
||||
private static readonly Vector2 PlaneNormalN = new Vector2(0, 1);
|
||||
private static readonly Vector2 CornerNW = new(-Width / 4, -Height / 2);
|
||||
private static readonly Vector2 CornerNE = new(Width / 4, -Height / 2);
|
||||
private static readonly Vector2 CornerE = new(Width / 2, 0);
|
||||
private static readonly Vector2 CornerSE = new(Width / 4, Height / 2);
|
||||
private static readonly Vector2 CornerSW = new(-Width / 4, Height / 2);
|
||||
private static readonly Vector2 CornerW = new(-Width / 2, 0);
|
||||
private static readonly Vector2 PlaneNormalN = new(0, 1);
|
||||
|
||||
private static readonly Vector2 PlaneNormalNE =
|
||||
-new Vector2(Mathf.Cos(Mathf.Deg2Rad(30)), -Mathf.Sin(Mathf.Deg2Rad(30)));
|
||||
|
@ -53,76 +58,61 @@ public class HexCell : IEquatable<HexCell>
|
|||
private static readonly Vector2 PlaneNormalSE =
|
||||
-new Vector2(Mathf.Cos(Mathf.Deg2Rad(-30)), -Mathf.Sin(Mathf.Deg2Rad(-30)));
|
||||
|
||||
private static readonly Vector2 PlaneNormalS = new Vector2(0, -1);
|
||||
private static readonly Vector2 PlaneNormalS = new(0, -1);
|
||||
|
||||
private static readonly Vector2 PlaneNormalSW =
|
||||
new Vector2(Mathf.Cos(Mathf.Deg2Rad(30)), -Mathf.Sin(Mathf.Deg2Rad(30)));
|
||||
private static readonly Vector2 PlaneNormalSW = new(Mathf.Cos(Mathf.Deg2Rad(30)), -Mathf.Sin(Mathf.Deg2Rad(30)));
|
||||
|
||||
private static readonly Vector2 PlaneNormalNW =
|
||||
new Vector2(Mathf.Cos(Mathf.Deg2Rad(-30)), -Mathf.Sin(Mathf.Deg2Rad(-30)));
|
||||
private static readonly Vector2 PlaneNormalNW = new(Mathf.Cos(Mathf.Deg2Rad(-30)), -Mathf.Sin(Mathf.Deg2Rad(-30)));
|
||||
|
||||
private static readonly Plane2D[] BoundaryPlanes =
|
||||
{
|
||||
new Plane2D(CornerNE, PlaneNormalN),
|
||||
new Plane2D(CornerNW, PlaneNormalNW),
|
||||
new Plane2D(CornerW, PlaneNormalSW),
|
||||
new Plane2D(CornerSW, PlaneNormalS),
|
||||
new Plane2D(CornerSE, PlaneNormalSE),
|
||||
new Plane2D(CornerE, PlaneNormalNE),
|
||||
private static readonly Plane2D[] BoundaryPlanes = {
|
||||
new(CornerNE, PlaneNormalN),
|
||||
new(CornerNW, PlaneNormalNW),
|
||||
new(CornerW, PlaneNormalSW),
|
||||
new(CornerSW, PlaneNormalS),
|
||||
new(CornerSE, PlaneNormalSE),
|
||||
new(CornerE, PlaneNormalNE)
|
||||
};
|
||||
|
||||
public HexCell()
|
||||
{
|
||||
}
|
||||
public HexCell() { }
|
||||
|
||||
public HexCell(float cubeX, float cubeY, float cubeZ)
|
||||
{
|
||||
public HexCell(float cubeX, float cubeY, float cubeZ) {
|
||||
CubeCoords = RoundCoords(new Vector3(cubeX, cubeY, cubeZ));
|
||||
}
|
||||
|
||||
public virtual bool Equals(HexCell other)
|
||||
{
|
||||
if (other == null)
|
||||
{
|
||||
public virtual bool Equals(HexCell other) {
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return CubeCoords == other.CubeCoords;
|
||||
}
|
||||
|
||||
public static bool operator ==(HexCell cellA, HexCell cellB)
|
||||
{
|
||||
public static bool operator ==(HexCell cellA, HexCell cellB) {
|
||||
return Equals(cellA, cellB);
|
||||
}
|
||||
|
||||
public static bool operator !=(HexCell cellA, HexCell cellB)
|
||||
{
|
||||
public static bool operator !=(HexCell cellA, HexCell cellB) {
|
||||
return !(cellA == cellB);
|
||||
}
|
||||
|
||||
public HexCell(Vector3 cubeCoords)
|
||||
{
|
||||
public HexCell(Vector3 cubeCoords) {
|
||||
CubeCoords = cubeCoords;
|
||||
}
|
||||
|
||||
public HexCell(float axialX, float axialY)
|
||||
{
|
||||
public HexCell(float axialX, float axialY) {
|
||||
AxialCoords = new Vector2(axialX, axialY);
|
||||
}
|
||||
|
||||
public HexCell(Vector2 axialCoords)
|
||||
{
|
||||
public HexCell(Vector2 axialCoords) {
|
||||
AxialCoords = axialCoords;
|
||||
}
|
||||
|
||||
public HexCell(HexCell other)
|
||||
{
|
||||
public HexCell(HexCell other) {
|
||||
CubeCoords = other.CubeCoords;
|
||||
}
|
||||
|
||||
public static HexCell FromOffsetCoords(Vector2 offsetCoords)
|
||||
{
|
||||
HexCell result = new HexCell();
|
||||
public static HexCell FromOffsetCoords(Vector2 offsetCoords) {
|
||||
HexCell result = new();
|
||||
result.OffsetCoords = offsetCoords;
|
||||
|
||||
return result;
|
||||
|
@ -130,13 +120,10 @@ public class HexCell : IEquatable<HexCell>
|
|||
|
||||
private Vector3 _cubeCoords;
|
||||
|
||||
public Vector3 CubeCoords
|
||||
{
|
||||
get { return _cubeCoords; }
|
||||
set
|
||||
{
|
||||
if (Mathf.Abs(value.x + value.y + value.z) > 0.0001)
|
||||
{
|
||||
public Vector3 CubeCoords {
|
||||
get => _cubeCoords;
|
||||
set {
|
||||
if (Mathf.Abs(value.x + value.y + value.z) > 0.0001) {
|
||||
GD.Print("Warning: Invalid cube coordinates for hex (x + y + z != 0): ", value.ToString());
|
||||
}
|
||||
|
||||
|
@ -144,25 +131,21 @@ public class HexCell : IEquatable<HexCell>
|
|||
}
|
||||
}
|
||||
|
||||
public Vector2 AxialCoords
|
||||
{
|
||||
get => new Vector2(CubeCoords.x, CubeCoords.y);
|
||||
public Vector2 AxialCoords {
|
||||
get => new(CubeCoords.x, CubeCoords.y);
|
||||
|
||||
set { CubeCoords = AxialToCubeCoords(value); }
|
||||
set => CubeCoords = AxialToCubeCoords(value);
|
||||
}
|
||||
|
||||
public Vector2 OffsetCoords
|
||||
{
|
||||
get
|
||||
{
|
||||
public Vector2 OffsetCoords {
|
||||
get {
|
||||
int x = (int)CubeCoords.x;
|
||||
int y = (int)CubeCoords.y;
|
||||
int offY = y + (x - (x & 1)) / 2;
|
||||
return new Vector2(x, offY);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
set {
|
||||
int x = (int)value.x;
|
||||
int y = (int)value.y;
|
||||
int cubeY = y - (x - (x & 1)) / 2;
|
||||
|
@ -170,51 +153,40 @@ public class HexCell : IEquatable<HexCell>
|
|||
}
|
||||
}
|
||||
|
||||
public Vector3 AxialToCubeCoords(Vector2 axialCoords)
|
||||
{
|
||||
public Vector3 AxialToCubeCoords(Vector2 axialCoords) {
|
||||
return new Vector3(axialCoords.x, axialCoords.y, -axialCoords.x - axialCoords.y);
|
||||
}
|
||||
|
||||
public Vector3 RoundCoords(Vector2 coords)
|
||||
{
|
||||
public Vector3 RoundCoords(Vector2 coords) {
|
||||
Vector3 cubeCoords = AxialToCubeCoords(coords);
|
||||
|
||||
return RoundCoords(cubeCoords);
|
||||
}
|
||||
|
||||
public Vector3 RoundCoords(Vector3 cubeCoords)
|
||||
{
|
||||
Vector3 rounded = new Vector3(
|
||||
public Vector3 RoundCoords(Vector3 cubeCoords) {
|
||||
Vector3 rounded = new(
|
||||
Mathf.Round(cubeCoords.x),
|
||||
Mathf.Round(cubeCoords.y),
|
||||
Mathf.Round(cubeCoords.z));
|
||||
|
||||
Vector3 diffs = (rounded - cubeCoords).Abs();
|
||||
if (diffs.x > diffs.y && diffs.x > diffs.z)
|
||||
{
|
||||
if (diffs.x > diffs.y && diffs.x > diffs.z) {
|
||||
rounded.x = -rounded.y - rounded.z;
|
||||
}
|
||||
else if (diffs.y > diffs.z)
|
||||
{
|
||||
} else if (diffs.y > diffs.z) {
|
||||
rounded.y = -rounded.x - rounded.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
rounded.z = -rounded.x - rounded.y;
|
||||
}
|
||||
|
||||
return rounded;
|
||||
}
|
||||
|
||||
public HexCell GetAdjacent(Vector3 dir)
|
||||
{
|
||||
return new HexCell(this.CubeCoords + dir);
|
||||
public HexCell GetAdjacent(Vector3 dir) {
|
||||
return new HexCell(CubeCoords + dir);
|
||||
}
|
||||
|
||||
public HexCell[] GetAllAdjacent()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
public HexCell[] GetAllAdjacent() {
|
||||
return new[] {
|
||||
GetAdjacent(DIR_NE),
|
||||
GetAdjacent(DIR_SE),
|
||||
GetAdjacent(DIR_S),
|
||||
|
@ -224,8 +196,7 @@ public class HexCell : IEquatable<HexCell>
|
|||
};
|
||||
}
|
||||
|
||||
public int DistanceTo(HexCell target)
|
||||
{
|
||||
public int DistanceTo(HexCell target) {
|
||||
return (int)(
|
||||
Mathf.Abs(_cubeCoords.x - target.CubeCoords.x)
|
||||
+ Mathf.Abs(_cubeCoords.y - target.CubeCoords.y)
|
||||
|
@ -233,16 +204,14 @@ public class HexCell : IEquatable<HexCell>
|
|||
) / 2;
|
||||
}
|
||||
|
||||
public HexCell[] LineTo(HexCell target)
|
||||
{
|
||||
HexCell nudgedTarget = new HexCell();
|
||||
public HexCell[] LineTo(HexCell target) {
|
||||
HexCell nudgedTarget = new();
|
||||
nudgedTarget.CubeCoords = target.CubeCoords + new Vector3(1.0e-6f, 2.0e-6f, -3.0e-6f);
|
||||
int steps = DistanceTo(target);
|
||||
|
||||
HexCell[] path = new HexCell[steps + 1];
|
||||
|
||||
foreach (int dist in Enumerable.Range(0, steps))
|
||||
{
|
||||
foreach (int dist in Enumerable.Range(0, steps)) {
|
||||
path[dist] = new HexCell();
|
||||
path[dist].CubeCoords = CubeCoords.LinearInterpolate(nudgedTarget.CubeCoords, (float)dist / steps);
|
||||
}
|
||||
|
@ -252,28 +221,23 @@ public class HexCell : IEquatable<HexCell>
|
|||
return path;
|
||||
}
|
||||
|
||||
public void QueryClosestCellBoundary(Vector2 pointLocal, Vector2 dir, out int neighbourIndex, out float distance)
|
||||
{
|
||||
distance = Single.PositiveInfinity;
|
||||
public void QueryClosestCellBoundary(Vector2 pointLocal, Vector2 dir, out int neighbourIndex, out float distance) {
|
||||
distance = float.PositiveInfinity;
|
||||
neighbourIndex = 0;
|
||||
foreach (int i in Enumerable.Range(0, 6))
|
||||
{
|
||||
if (BoundaryPlanes[i].Normal.Dot(dir) >= Plane2D.DistancePrecision)
|
||||
{
|
||||
foreach (int i in Enumerable.Range(0, 6)) {
|
||||
if (BoundaryPlanes[i].Normal.Dot(dir) >= Plane2D.DistancePrecision) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float planeDistance = BoundaryPlanes[i].DistanceToLineSegment(pointLocal, dir);
|
||||
if (planeDistance > Single.NegativeInfinity && planeDistance < distance)
|
||||
{
|
||||
if (planeDistance > float.NegativeInfinity && planeDistance < distance) {
|
||||
distance = planeDistance;
|
||||
neighbourIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public HexCell NextCellAlongLine(Vector2 pointLocal, Vector2 dir)
|
||||
{
|
||||
public HexCell NextCellAlongLine(Vector2 pointLocal, Vector2 dir) {
|
||||
int planeIndex;
|
||||
|
||||
QueryClosestCellBoundary(pointLocal, dir, out planeIndex, out _);
|
||||
|
|
205
HexGrid.cs
205
HexGrid.cs
|
@ -4,8 +4,7 @@ using Godot;
|
|||
using Priority_Queue;
|
||||
using AxialCoordDirectionPair = System.Tuple<Godot.Vector2, Godot.Vector3>;
|
||||
|
||||
public class HexGrid : Resource
|
||||
{
|
||||
public class HexGrid : Resource {
|
||||
private readonly Vector2 _baseHexSize = new(1, Mathf.Sqrt(3) / 2);
|
||||
private Rect2 _boundsAxialCoords = new(-Vector2.Inf, Vector2.Inf);
|
||||
private Rect2 _boundsOffsetCoords = new(-Vector2.Inf, Vector2.Inf);
|
||||
|
@ -24,18 +23,15 @@ public class HexGrid : Resource
|
|||
|
||||
public float PathCostDefault = 1;
|
||||
|
||||
public HexGrid()
|
||||
{
|
||||
public HexGrid() {
|
||||
HexScale = new Vector2(1, 1);
|
||||
}
|
||||
|
||||
public Vector2 HexSize => _hexSize;
|
||||
|
||||
public Vector2 HexScale
|
||||
{
|
||||
public Vector2 HexScale {
|
||||
get => _hexScale;
|
||||
set
|
||||
{
|
||||
set {
|
||||
_hexScale = value;
|
||||
_hexSize = _baseHexSize * _hexScale;
|
||||
_hexTransform = new Transform2D(
|
||||
|
@ -48,135 +44,129 @@ public class HexGrid : Resource
|
|||
}
|
||||
}
|
||||
|
||||
public Vector2 GetHexCenter(HexCell cell)
|
||||
{
|
||||
public Vector2 GetHexCenter(HexCell cell) {
|
||||
return _hexTransform * cell.AxialCoords;
|
||||
}
|
||||
|
||||
public Vector2 GetHexCenterFromOffset(Vector2 offsetCoord)
|
||||
{
|
||||
var cell = new HexCell();
|
||||
public Vector2 GetHexCenterFromOffset(Vector2 offsetCoord) {
|
||||
HexCell cell = new HexCell();
|
||||
cell.OffsetCoords = offsetCoord;
|
||||
return GetHexCenter(cell);
|
||||
}
|
||||
|
||||
public Vector3 GetHexCenterVec3FromOffset(Vector2 offsetCoord)
|
||||
{
|
||||
var cell = new HexCell();
|
||||
public Vector3 GetHexCenterVec3FromOffset(Vector2 offsetCoord) {
|
||||
HexCell cell = new HexCell();
|
||||
cell.OffsetCoords = offsetCoord;
|
||||
var hexCenter = GetHexCenter(cell);
|
||||
Vector2 hexCenter = GetHexCenter(cell);
|
||||
return new Vector3(hexCenter.x, 0, hexCenter.y);
|
||||
}
|
||||
|
||||
public HexCell GetHexAtOffset(Vector2 offsetCoord)
|
||||
{
|
||||
var cell = new HexCell();
|
||||
public HexCell GetHexAtOffset(Vector2 offsetCoord) {
|
||||
HexCell cell = new HexCell();
|
||||
cell.OffsetCoords = offsetCoord;
|
||||
return cell;
|
||||
}
|
||||
|
||||
public HexCell GetHexAt(Vector2 planeCoord)
|
||||
{
|
||||
var result = new HexCell(_hexTransformInv * planeCoord);
|
||||
public HexCell GetHexAt(Vector2 planeCoord) {
|
||||
HexCell result = new HexCell(_hexTransformInv * planeCoord);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SetBounds(Vector2 minAxial, Vector2 maxAxial)
|
||||
{
|
||||
public void SetBounds(Vector2 minAxial, Vector2 maxAxial) {
|
||||
SetBounds(new HexCell(minAxial), new HexCell(maxAxial));
|
||||
}
|
||||
|
||||
public void SetBounds(HexCell minCell, HexCell maxCell)
|
||||
{
|
||||
public void SetBounds(HexCell minCell, HexCell maxCell) {
|
||||
_minCoords = minCell;
|
||||
_maxCoords = maxCell;
|
||||
_boundsAxialCoords = new Rect2(_minCoords.AxialCoords,
|
||||
_maxCoords.AxialCoords - _minCoords.AxialCoords + Vector2.One);
|
||||
}
|
||||
|
||||
public void SetBounds(HexCell center, int size)
|
||||
{
|
||||
var centerOffset = center.OffsetCoords;
|
||||
public void SetBounds(HexCell center, int size) {
|
||||
Vector2 centerOffset = center.OffsetCoords;
|
||||
SetBounds(GetHexAtOffset(centerOffset - Vector2.One * size / 2),
|
||||
GetHexAtOffset(centerOffset + Vector2.One * size / 2));
|
||||
}
|
||||
|
||||
public void SetBoundsOffset(HexCell cellSouthEast, Vector2 size)
|
||||
{
|
||||
public void SetBoundsOffset(HexCell cellSouthEast, Vector2 size) {
|
||||
_boundsOffsetCoords = new Rect2(cellSouthEast.OffsetCoords, size);
|
||||
_boundsAxialCoords = new Rect2(-Vector2.Inf, Vector2.Inf);
|
||||
}
|
||||
|
||||
public void AddObstacle(Vector2 axialCoords, float cost = 0)
|
||||
{
|
||||
public void AddObstacle(Vector2 axialCoords, float cost = 0) {
|
||||
AddObstacle(new HexCell(axialCoords), cost);
|
||||
}
|
||||
|
||||
public void AddObstacle(HexCell cell, float cost = 0)
|
||||
{
|
||||
public void AddObstacle(HexCell cell, float cost = 0) {
|
||||
Obstacles[cell.AxialCoords] = cost;
|
||||
}
|
||||
|
||||
public void RemoveObstacle(HexCell cell)
|
||||
{
|
||||
public void RemoveObstacle(HexCell cell) {
|
||||
Obstacles.Remove(cell.AxialCoords);
|
||||
}
|
||||
|
||||
|
||||
public void AddBarrier(Vector2 axialCoords, Vector3 directionCube, float cost = 0)
|
||||
{
|
||||
public void AddBarrier(Vector2 axialCoords, Vector3 directionCube, float cost = 0) {
|
||||
AddBarrier(new HexCell(axialCoords), directionCube, cost);
|
||||
}
|
||||
|
||||
public void AddBarrier(HexCell cell, Vector3 directionCube, float cost = 0)
|
||||
{
|
||||
public void AddBarrier(HexCell cell, Vector3 directionCube, float cost = 0) {
|
||||
Barriers.Add((cell.AxialCoords, directionCube), cost);
|
||||
}
|
||||
|
||||
public void RemoveBarrier(HexCell cell, Vector3 directionCube)
|
||||
{
|
||||
if (Barriers.ContainsKey((cell.AxialCoords, directionCube))) Barriers.Remove((cell.AxialCoords, directionCube));
|
||||
public void RemoveBarrier(HexCell cell, Vector3 directionCube) {
|
||||
if (Barriers.ContainsKey((cell.AxialCoords, directionCube))) {
|
||||
Barriers.Remove((cell.AxialCoords, directionCube));
|
||||
}
|
||||
}
|
||||
|
||||
public float GetHexCost(HexCell cell)
|
||||
{
|
||||
public float GetHexCost(HexCell cell) {
|
||||
return GetHexCost(cell.AxialCoords);
|
||||
}
|
||||
|
||||
public float GetHexCost(Vector2 axialCoords)
|
||||
{
|
||||
if (!_boundsAxialCoords.HasPoint(axialCoords)) return 0;
|
||||
public float GetHexCost(Vector2 axialCoords) {
|
||||
if (!_boundsAxialCoords.HasPoint(axialCoords)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_boundsOffsetCoords.HasPoint(new HexCell(axialCoords).OffsetCoords)) return 0;
|
||||
if (!_boundsOffsetCoords.HasPoint(new HexCell(axialCoords).OffsetCoords)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float value;
|
||||
return Obstacles.TryGetValue(axialCoords, out value) ? value : PathCostDefault;
|
||||
}
|
||||
|
||||
public float GetMoveCost(Vector2 axialCoords, Vector3 directionCube)
|
||||
{
|
||||
var startCell = new HexCell(axialCoords);
|
||||
var targetCell = new HexCell(startCell.CubeCoords + directionCube);
|
||||
public float GetMoveCost(Vector2 axialCoords, Vector3 directionCube) {
|
||||
HexCell startCell = new HexCell(axialCoords);
|
||||
HexCell targetCell = new HexCell(startCell.CubeCoords + directionCube);
|
||||
|
||||
var cost = GetHexCost(axialCoords);
|
||||
if (cost == 0) return 0;
|
||||
float cost = GetHexCost(axialCoords);
|
||||
if (cost == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cost = GetHexCost(targetCell.AxialCoords);
|
||||
if (cost == 0) return 0;
|
||||
if (cost == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float barrierCost;
|
||||
if (Barriers.ContainsKey((axialCoords, directionCube)))
|
||||
{
|
||||
if (Barriers.ContainsKey((axialCoords, directionCube))) {
|
||||
barrierCost = Barriers[(axialCoords, directionCube)];
|
||||
if (barrierCost == 0) return 0;
|
||||
if (barrierCost == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cost += barrierCost;
|
||||
}
|
||||
|
||||
if (Barriers.ContainsKey((targetCell.AxialCoords, -directionCube)))
|
||||
{
|
||||
if (Barriers.ContainsKey((targetCell.AxialCoords, -directionCube))) {
|
||||
barrierCost = Barriers[(targetCell.AxialCoords, -directionCube)];
|
||||
if (barrierCost == 0) return 0;
|
||||
if (barrierCost == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cost += barrierCost;
|
||||
}
|
||||
|
@ -185,32 +175,29 @@ public class HexGrid : Resource
|
|||
}
|
||||
|
||||
|
||||
public HexCell GetClosestWalkableCell(HexCell fromCell, HexCell toCell)
|
||||
{
|
||||
if (GetHexCost(toCell) == 0)
|
||||
{
|
||||
var line = fromCell.LineTo(toCell);
|
||||
public HexCell GetClosestWalkableCell(HexCell fromCell, HexCell toCell) {
|
||||
if (GetHexCost(toCell) == 0) {
|
||||
HexCell[] line = fromCell.LineTo(toCell);
|
||||
|
||||
foreach (var i in Enumerable.Range(1, line.Length))
|
||||
if (GetHexCost(line[i]) == 0)
|
||||
{
|
||||
foreach (int i in Enumerable.Range(1, line.Length)) {
|
||||
if (GetHexCost(line[i]) == 0) {
|
||||
toCell = line[i - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return toCell;
|
||||
}
|
||||
|
||||
public List<HexCell> FindPath(HexCell startHex, HexCell goalHex)
|
||||
{
|
||||
var goalAxialCoords = goalHex.AxialCoords;
|
||||
public List<HexCell> FindPath(HexCell startHex, HexCell goalHex) {
|
||||
Vector2 goalAxialCoords = goalHex.AxialCoords;
|
||||
|
||||
var frontier = new SimplePriorityQueue<Vector2, float>();
|
||||
SimplePriorityQueue<Vector2, float> frontier = new SimplePriorityQueue<Vector2, float>();
|
||||
frontier.Enqueue(startHex.AxialCoords, 0);
|
||||
var cameFrom =
|
||||
Dictionary<Vector2, Vector2> cameFrom =
|
||||
new Dictionary<Vector2, Vector2>();
|
||||
var costSoFar =
|
||||
Dictionary<Vector2, float> costSoFar =
|
||||
new Dictionary<Vector2, float>();
|
||||
|
||||
cameFrom.Add(startHex.AxialCoords, startHex.AxialCoords);
|
||||
|
@ -218,34 +205,34 @@ public class HexGrid : Resource
|
|||
|
||||
FindPathCheckedCellCount = 0;
|
||||
|
||||
while (frontier.Any())
|
||||
{
|
||||
while (frontier.Any()) {
|
||||
FindPathCheckedCellCount++;
|
||||
var currentHex = new HexCell(frontier.Dequeue());
|
||||
var currentAxial = currentHex.AxialCoords;
|
||||
HexCell currentHex = new HexCell(frontier.Dequeue());
|
||||
Vector2 currentAxial = currentHex.AxialCoords;
|
||||
|
||||
if (currentHex == goalHex) break;
|
||||
if (currentHex == goalHex) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var nextHex in currentHex.GetAllAdjacent())
|
||||
{
|
||||
var nextAxial = nextHex.AxialCoords;
|
||||
var nextCost = GetMoveCost(currentAxial, new HexCell(nextAxial - currentHex.AxialCoords).CubeCoords);
|
||||
foreach (HexCell nextHex in currentHex.GetAllAdjacent()) {
|
||||
Vector2 nextAxial = nextHex.AxialCoords;
|
||||
float nextCost = GetMoveCost(currentAxial, new HexCell(nextAxial - currentHex.AxialCoords).CubeCoords);
|
||||
|
||||
if (nextHex == goalHex && GetHexCost(nextAxial) == 0)
|
||||
{
|
||||
if (nextHex == goalHex && GetHexCost(nextAxial) == 0) {
|
||||
// Goal ist an obstacle
|
||||
cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
|
||||
frontier.Clear();
|
||||
break;
|
||||
}
|
||||
|
||||
if (nextCost == 0) continue;
|
||||
if (nextCost == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nextCost += costSoFar[currentHex.AxialCoords];
|
||||
if (!costSoFar.ContainsKey(nextHex.AxialCoords) || nextCost < costSoFar[nextHex.AxialCoords])
|
||||
{
|
||||
if (!costSoFar.ContainsKey(nextHex.AxialCoords) || nextCost < costSoFar[nextHex.AxialCoords]) {
|
||||
costSoFar[nextHex.AxialCoords] = nextCost;
|
||||
var priority = nextCost + nextHex.DistanceTo(goalHex);
|
||||
float priority = nextCost + nextHex.DistanceTo(goalHex);
|
||||
|
||||
frontier.Enqueue(nextHex.AxialCoords, priority);
|
||||
cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
|
||||
|
@ -255,18 +242,18 @@ public class HexGrid : Resource
|
|||
|
||||
// GD.Print("Checked Cell Count: " + FindPathCheckedCellCount);
|
||||
|
||||
var result = new List<HexCell>();
|
||||
if (!cameFrom.ContainsKey(goalHex.AxialCoords))
|
||||
{
|
||||
List<HexCell> result = new List<HexCell>();
|
||||
if (!cameFrom.ContainsKey(goalHex.AxialCoords)) {
|
||||
GD.Print("Failed to find path from " + startHex + " to " + goalHex);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (GetHexCost(goalAxialCoords) != 0) result.Add(goalHex);
|
||||
if (GetHexCost(goalAxialCoords) != 0) {
|
||||
result.Add(goalHex);
|
||||
}
|
||||
|
||||
var pathHex = goalHex;
|
||||
while (pathHex != startHex)
|
||||
{
|
||||
HexCell pathHex = goalHex;
|
||||
while (pathHex != startHex) {
|
||||
pathHex = new HexCell(cameFrom[pathHex.AxialCoords]);
|
||||
result.Insert(0, pathHex);
|
||||
}
|
||||
|
@ -275,22 +262,20 @@ public class HexGrid : Resource
|
|||
}
|
||||
|
||||
|
||||
public List<HexCell> GetCellsForLine(Vector2 fromPlane, Vector2 toPlane)
|
||||
{
|
||||
var result = new List<HexCell>();
|
||||
public List<HexCell> GetCellsForLine(Vector2 fromPlane, Vector2 toPlane) {
|
||||
List<HexCell> result = new List<HexCell>();
|
||||
|
||||
var distance = (toPlane - fromPlane).Length();
|
||||
var direction = (toPlane - fromPlane) / distance;
|
||||
float distance = (toPlane - fromPlane).Length();
|
||||
Vector2 direction = (toPlane - fromPlane) / distance;
|
||||
|
||||
var currentPointPlane = fromPlane;
|
||||
var currentCell = GetHexAt(currentPointPlane);
|
||||
Vector2 currentPointPlane = fromPlane;
|
||||
HexCell currentCell = GetHexAt(currentPointPlane);
|
||||
float currentDistance = 0;
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
result.Add(currentCell);
|
||||
GetHexCenter(currentCell);
|
||||
var currentPointLocal = currentPointPlane - GetHexCenter(currentCell);
|
||||
Vector2 currentPointLocal = currentPointPlane - GetHexCenter(currentCell);
|
||||
|
||||
int neighbourIndex;
|
||||
float boundaryPlaneDistance;
|
||||
|
|
|
@ -21,7 +21,7 @@ compress/lossy_quality=0.7
|
|||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=true
|
||||
flags/repeat=1
|
||||
flags/filter=false
|
||||
flags/mipmaps=true
|
||||
flags/anisotropic=false
|
||||
|
|
|
@ -19,7 +19,7 @@ compress/lossy_quality=0.7
|
|||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=2
|
||||
flags/repeat=true
|
||||
flags/repeat=0
|
||||
flags/filter=false
|
||||
flags/mipmaps=true
|
||||
flags/anisotropic=false
|
||||
|
|
Binary file not shown.
|
@ -2,28 +2,30 @@
|
|||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.stex"
|
||||
path.s3tc="res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.s3tc.stex"
|
||||
path.etc2="res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.etc2.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
"imported_formats": [ "s3tc", "etc2" ],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/IslandMasks/IslandMask2.png"
|
||||
dest_files=[ "res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.stex" ]
|
||||
dest_files=[ "res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.s3tc.stex", "res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.etc2.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/mode=2
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/repeat=true
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/mipmaps=true
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
flags/srgb=1
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
|
@ -31,5 +33,5 @@ process/invert_color=false
|
|||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
detect_3d=false
|
||||
svg/scale=1.0
|
||||
|
|
|
@ -2,24 +2,21 @@ using System;
|
|||
using Godot;
|
||||
using GoDotLog;
|
||||
|
||||
public class ClickableComponent : Spatial
|
||||
{
|
||||
public class ClickableComponent : Spatial {
|
||||
[Export] public string ClickName = "ClickName";
|
||||
|
||||
[Signal]
|
||||
delegate void Clicked();
|
||||
|
||||
|
||||
public bool IsMouseOver = false;
|
||||
|
||||
// private members
|
||||
private CollisionObject _collisionObject;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_collisionObject = (CollisionObject)FindNode("Area", false);
|
||||
if (_collisionObject == null)
|
||||
{
|
||||
if (_collisionObject == null) {
|
||||
GD.PrintErr("Error: could not find Area for Clickable Component!");
|
||||
return;
|
||||
}
|
||||
|
@ -30,26 +27,21 @@ public class ClickableComponent : Spatial
|
|||
}
|
||||
|
||||
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||
int shapeIndex)
|
||||
{
|
||||
if (IsMouseOver && inputEvent is InputEventMouseButton)
|
||||
{
|
||||
int shapeIndex) {
|
||||
if (IsMouseOver && inputEvent is InputEventMouseButton) {
|
||||
InputEventMouseButton mouseButtonEvent = (InputEventMouseButton)inputEvent;
|
||||
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed)
|
||||
{
|
||||
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed) {
|
||||
GD.Print("Clicked on Clickable Component!");
|
||||
EmitSignal("Clicked", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAreaMouseEntered()
|
||||
{
|
||||
public void OnAreaMouseEntered() {
|
||||
IsMouseOver = true;
|
||||
}
|
||||
|
||||
public void OnAreaMouseExited()
|
||||
{
|
||||
public void OnAreaMouseExited() {
|
||||
IsMouseOver = false;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,3 @@
|
|||
using Godot;
|
||||
|
||||
public class Component : Node
|
||||
{
|
||||
|
||||
}
|
||||
public class Component : Node { }
|
|
@ -2,8 +2,7 @@ using Godot;
|
|||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public class GroundMotionComponent : Component
|
||||
{
|
||||
public class GroundMotionComponent : Component {
|
||||
public float Accel = 50;
|
||||
public float Damping = 0.2f;
|
||||
public Vector3 DirectionToTarget = Vector3.Zero;
|
||||
|
@ -14,59 +13,47 @@ public class GroundMotionComponent : Component
|
|||
public float TargetAngle;
|
||||
public float TargetDeltaAngle;
|
||||
|
||||
private void CalcAndApplyOrientation(float delta, Entity entity, Vector3 targetPosition, float targetAngle)
|
||||
{
|
||||
private void CalcAndApplyOrientation(float delta, Entity entity, Vector3 targetPosition, float targetAngle) {
|
||||
float deltaAngleAbsolute = Mathf.Abs(TargetDeltaAngle);
|
||||
if (deltaAngleAbsolute > 0.001)
|
||||
{
|
||||
if (RotationSpeedRadPerSecond * delta >= deltaAngleAbsolute)
|
||||
{
|
||||
if (deltaAngleAbsolute > 0.001) {
|
||||
if (RotationSpeedRadPerSecond * delta >= deltaAngleAbsolute) {
|
||||
entity.PlaneAngle = TargetAngle;
|
||||
TargetDeltaAngle = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
entity.PlaneAngle += Mathf.Sign(TargetDeltaAngle) * RotationSpeedRadPerSecond * delta;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
TargetDeltaAngle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void CalcPlaneVelocity(float delta, Entity entity, Vector3 targetPosition)
|
||||
{
|
||||
Vector2 planeTargetDirection = new Vector2(DirectionToTarget.x, DirectionToTarget.z);
|
||||
private void CalcPlaneVelocity(float delta, Entity entity, Vector3 targetPosition) {
|
||||
Vector2 planeTargetDirection = new(DirectionToTarget.x, DirectionToTarget.z);
|
||||
|
||||
Vector2 planeVelocity = new Vector2(entity.Velocity.x, entity.Velocity.z);
|
||||
Vector2 planeVelocity = new(entity.Velocity.x, entity.Velocity.z);
|
||||
// GD.Print("-- Step: distance: " + targetDistance + " dir: " + planeTargetDirection + " speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
||||
planeVelocity -= planeVelocity * Damping;
|
||||
// GD.Print(" damp : speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
||||
|
||||
if (DistanceToTarget < 0.01)
|
||||
{
|
||||
if (DistanceToTarget < 0.01) {
|
||||
planeVelocity = Vector2.Zero;
|
||||
}
|
||||
else if (TargetDeltaAngle == 0.0)
|
||||
{
|
||||
} else if (TargetDeltaAngle == 0.0) {
|
||||
planeVelocity = planeVelocity.Length() * planeTargetDirection + planeTargetDirection * Accel * delta;
|
||||
// GD.Print(" accel: speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
||||
|
||||
var projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
|
||||
float projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
|
||||
// GD.Print(" Projected step: " + projectedStep + " Speed: " + planeVelocity.Length() + " delta: " + delta);
|
||||
if (projectedStep > DistanceToTarget)
|
||||
{
|
||||
if (projectedStep > DistanceToTarget) {
|
||||
planeVelocity *= DistanceToTarget / projectedStep;
|
||||
projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
|
||||
// GD.Print(" corr speed: " + planeVelocity.Length() + " step: " + projectedStep);
|
||||
}
|
||||
|
||||
var planeSpeed = planeVelocity.Length();
|
||||
if (planeSpeed > MaxSpeed) planeVelocity *= MaxSpeed / planeSpeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
float planeSpeed = planeVelocity.Length();
|
||||
if (planeSpeed > MaxSpeed) {
|
||||
planeVelocity *= MaxSpeed / planeSpeed;
|
||||
}
|
||||
} else {
|
||||
planeVelocity = Vector2.Zero;
|
||||
}
|
||||
|
||||
|
@ -74,22 +61,19 @@ public class GroundMotionComponent : Component
|
|||
}
|
||||
|
||||
|
||||
private void CalcVerticalVelocity(float delta, Entity entity, TileWorld tileWorld)
|
||||
{
|
||||
private void CalcVerticalVelocity(float delta, Entity entity, TileWorld tileWorld) {
|
||||
Vector3 entityVelocity = entity.Velocity;
|
||||
|
||||
Vector2 currentTile = tileWorld.WorldToOffsetCoords(entity.GlobalTransform.origin);
|
||||
Vector2 nextTile = tileWorld.WorldToOffsetCoords(entity.GlobalTransform.origin + entityVelocity * delta);
|
||||
|
||||
if (nextTile != currentTile)
|
||||
{
|
||||
if (nextTile != currentTile) {
|
||||
float currentHeight = tileWorld.GetHeightAtOffset(currentTile);
|
||||
float nextHeight = tileWorld.GetHeightAtOffset(nextTile);
|
||||
|
||||
bool isOnFloor = entity.IsOnFloor();
|
||||
|
||||
if (nextHeight - entity.GlobalTransform.origin.y > 0.1)
|
||||
{
|
||||
if (nextHeight - entity.GlobalTransform.origin.y > 0.1) {
|
||||
GD.Print("Jump!");
|
||||
entityVelocity.y = 10;
|
||||
|
||||
|
@ -105,32 +89,26 @@ public class GroundMotionComponent : Component
|
|||
}
|
||||
|
||||
public void PhysicsProcess(float delta, Entity entity, Vector3 targetPosition, float targetAngle,
|
||||
World world)
|
||||
{
|
||||
World world) {
|
||||
DirectionToTarget = targetPosition - entity.GlobalTranslation;
|
||||
DirectionToTarget.y = 0;
|
||||
DistanceToTarget = DirectionToTarget.Length();
|
||||
|
||||
if (DistanceToTarget >= Globals.EpsPosition)
|
||||
{
|
||||
if (DistanceToTarget >= Globals.EpsPosition) {
|
||||
DirectionToTarget = DirectionToTarget.Normalized();
|
||||
TargetAngle = Vector3.Right.SignedAngleTo(DirectionToTarget, Vector3.Up);
|
||||
TargetDeltaAngle = entity.CalcShortestPlaneRotationToTargetDirection(DirectionToTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
DirectionToTarget = Vector3.Right;
|
||||
entity.GlobalTranslation = targetPosition;
|
||||
entity.Velocity = new Vector3(0, entity.Velocity.y, 0);
|
||||
|
||||
if (entity.PlaneAngle != targetAngle)
|
||||
{
|
||||
if (entity.PlaneAngle != targetAngle) {
|
||||
Vector3 directionToTarget = Vector3.Right.Rotated(Vector3.Up, targetAngle);
|
||||
TargetAngle = targetAngle;
|
||||
TargetDeltaAngle = entity.CalcShortestPlaneRotationToTargetDirection(directionToTarget);
|
||||
|
||||
if (Mathf.Abs(TargetDeltaAngle) < Globals.EpsRadians)
|
||||
{
|
||||
if (Mathf.Abs(TargetDeltaAngle) < Globals.EpsRadians) {
|
||||
TargetAngle = entity.PlaneAngle;
|
||||
TargetDeltaAngle = 0;
|
||||
|
||||
|
|
|
@ -2,14 +2,18 @@ using Godot;
|
|||
|
||||
namespace GodotComponentTest.components;
|
||||
|
||||
public class InteractionComponent: Component
|
||||
{
|
||||
public class InteractionComponent : Component {
|
||||
[Signal]
|
||||
delegate void InteractionStart(Spatial owningEntity, Spatial targetEntity);
|
||||
|
||||
[Signal]
|
||||
delegate void InteractionEnd(Spatial owningEntity, Spatial targetEntity);
|
||||
private delegate void InteractionStart(Spatial owningEntity, Spatial targetEntity);
|
||||
|
||||
[Signal]
|
||||
private delegate void InteractionEnd(Spatial owningEntity, Spatial targetEntity);
|
||||
|
||||
public void EndInteraction() {
|
||||
hasStopped = true;
|
||||
}
|
||||
|
||||
public bool hasStopped;
|
||||
public Spatial OwningEntity;
|
||||
public Spatial TargetEntity;
|
||||
}
|
|
@ -1,15 +1,13 @@
|
|||
using Godot;
|
||||
using System;
|
||||
|
||||
public class MovableComponent : Component
|
||||
{
|
||||
public class MovableComponent : Component {
|
||||
public Vector3 targetPosition = Vector3.Zero;
|
||||
public Vector3 currentPosition = Vector3.Zero;
|
||||
public Vector3 currentVelocity = Vector3.Zero;
|
||||
|
||||
public float targetAngle = 0;
|
||||
public float currentAngle = 0;
|
||||
public float currentAngularVelocity = 0;
|
||||
public float targetAngle;
|
||||
public float currentAngle;
|
||||
public float currentAngularVelocity;
|
||||
|
||||
[Export] public float maxSpeed = 3;
|
||||
|
||||
|
@ -17,62 +15,55 @@ public class MovableComponent : Component
|
|||
private SpringDamper _angleSpringDamper;
|
||||
|
||||
[Signal]
|
||||
delegate void PositionUpdated(Vector3 newPosition);
|
||||
private delegate void PositionUpdated(Vector3 newPosition);
|
||||
|
||||
[Signal]
|
||||
delegate void OrientationUpdated(float newAngle);
|
||||
private delegate void OrientationUpdated(float newAngle);
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_positionSpringDamper = new SpringDamper(4, 0.99f, 0.5f);
|
||||
_angleSpringDamper = new SpringDamper(4, 0.99f, 0.5f);
|
||||
}
|
||||
|
||||
// Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
public override void _Process(float delta) {
|
||||
Vector3 targetError = targetPosition - currentPosition;
|
||||
|
||||
if (targetError.LengthSquared() > 0.01)
|
||||
{
|
||||
if (targetError.LengthSquared() > 0.01) {
|
||||
Vector3 targetDir = targetError.Normalized();
|
||||
targetAngle = new Vector3(0, 0, 1).SignedAngleTo(targetDir, Vector3.Up);
|
||||
|
||||
if (targetAngle - currentAngle > Mathf.Pi)
|
||||
{
|
||||
if (targetAngle - currentAngle > Mathf.Pi) {
|
||||
currentAngle += 2 * Mathf.Pi;
|
||||
}
|
||||
else if (targetAngle - currentAngle < -Mathf.Pi)
|
||||
{
|
||||
} else if (targetAngle - currentAngle < -Mathf.Pi) {
|
||||
currentAngle -= 2 * Mathf.Pi;
|
||||
}
|
||||
}
|
||||
|
||||
if (Mathf.Abs(currentAngularVelocity) > 0.1 || Mathf.Abs(targetAngle - currentAngle) > 0.01)
|
||||
{
|
||||
var springDamperResult =
|
||||
if (Mathf.Abs(currentAngularVelocity) > 0.1 || Mathf.Abs(targetAngle - currentAngle) > 0.01) {
|
||||
(float, float) springDamperResult =
|
||||
_angleSpringDamper.Calc(currentAngle, currentAngularVelocity, targetAngle, delta);
|
||||
|
||||
currentAngle = springDamperResult.Item1;
|
||||
currentAngularVelocity = springDamperResult.Item2;
|
||||
|
||||
EmitSignal("OrientationUpdated", this.currentAngle);
|
||||
EmitSignal("OrientationUpdated", currentAngle);
|
||||
}
|
||||
|
||||
if ((Mathf.Abs(currentAngularVelocity) < 5 && Mathf.Abs(targetAngle - currentAngle) < 0.3)
|
||||
&& (targetPosition - currentPosition).LengthSquared() > 0.01)
|
||||
{
|
||||
var springDamperResult =
|
||||
if (Mathf.Abs(currentAngularVelocity) < 5 && Mathf.Abs(targetAngle - currentAngle) < 0.3
|
||||
&& (targetPosition - currentPosition).LengthSquared() > 0.01) {
|
||||
(Vector3, Vector3) springDamperResult =
|
||||
_positionSpringDamper.CalcClampedSpeedXZ(currentPosition, currentVelocity, targetPosition, delta,
|
||||
maxSpeed);
|
||||
|
||||
currentPosition = springDamperResult.Item1;
|
||||
currentVelocity = springDamperResult.Item2;
|
||||
}
|
||||
|
||||
currentVelocity.y = currentVelocity.y - 9.81f * delta;
|
||||
currentPosition.y = currentPosition.y + currentVelocity.y * delta;
|
||||
|
||||
|
||||
EmitSignal("PositionUpdated", currentPosition);
|
||||
}
|
||||
}
|
|
@ -7,8 +7,7 @@ using GodotComponentTest.utils;
|
|||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public class NavigationComponent : Spatial
|
||||
{
|
||||
public class NavigationComponent : Spatial {
|
||||
public World World { set; get; }
|
||||
public Vector3 CurrentGoalPositionWorld { get; private set; } = Vector3.Zero;
|
||||
public float CurrentGoalAngleWorld { get; private set; }
|
||||
|
@ -21,39 +20,29 @@ public class NavigationComponent : Spatial
|
|||
private List<NavigationPoint> _planningPathWorldNavigationPoints = new();
|
||||
private List<NavigationPoint> _smoothedPathWorldNavigationPoints = new();
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
base._Ready();
|
||||
_pathWorldNavigationPoints = new List<NavigationPoint>();
|
||||
}
|
||||
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
public override void _Process(float delta) {
|
||||
Debug.Assert(World != null);
|
||||
}
|
||||
|
||||
public void PlanSmoothedPath(KinematicBody body, Transform fromTransformWorld, NavigationPoint navigationPoint)
|
||||
{
|
||||
public void PlanSmoothedPath(Entity body, Transform fromTransformWorld, NavigationPoint navigationPoint) {
|
||||
if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)
|
||||
&& navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation))
|
||||
{
|
||||
&& navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation)) {
|
||||
FindPath(body, fromTransformWorld.origin, navigationPoint);
|
||||
}
|
||||
else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position))
|
||||
{
|
||||
} else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)) {
|
||||
FindPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public void FindPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld)
|
||||
{
|
||||
var fromCell = World.HexGrid.GetHexAt(new Vector2(fromPositionWorld.x, fromPositionWorld.z));
|
||||
if (World.HexGrid.GetHexCost(fromCell) == 0)
|
||||
{
|
||||
public void FindPath(Entity entity, Vector3 fromPositionWorld, Vector3 toPositionWorld) {
|
||||
HexCell fromCell = World.HexGrid.GetHexAt(new Vector2(fromPositionWorld.x, fromPositionWorld.z));
|
||||
if (World.HexGrid.GetHexCost(fromCell) == 0) {
|
||||
GD.Print("Invalid starting point for FindPath(): returning empty path.");
|
||||
_planningPathWorldNavigationPoints = new List<NavigationPoint>();
|
||||
_planningPathWorldNavigationPoints.Add(new NavigationPoint(fromPositionWorld));
|
||||
|
@ -61,11 +50,10 @@ public class NavigationComponent : Spatial
|
|||
return;
|
||||
}
|
||||
|
||||
var toCell = World.HexGrid.GetHexAt(new Vector2(toPositionWorld.x, toPositionWorld.z));
|
||||
HexCell toCell = World.HexGrid.GetHexAt(new Vector2(toPositionWorld.x, toPositionWorld.z));
|
||||
toCell = World.HexGrid.GetClosestWalkableCell(fromCell, toCell);
|
||||
|
||||
if (World.HexGrid.GetHexCost(toCell) == 0)
|
||||
{
|
||||
if (World.HexGrid.GetHexCost(toCell) == 0) {
|
||||
GD.Print("Invalid target point for FindPath(): returning empty path.");
|
||||
_planningPathWorldNavigationPoints = new List<NavigationPoint>();
|
||||
_planningPathWorldNavigationPoints.Add(new NavigationPoint(fromPositionWorld));
|
||||
|
@ -73,12 +61,11 @@ public class NavigationComponent : Spatial
|
|||
return;
|
||||
}
|
||||
|
||||
var path = World.HexGrid.FindPath(fromCell, toCell);
|
||||
List<HexCell> path = World.FindPath(entity, fromCell, toCell);
|
||||
|
||||
// Generate grid navigation points
|
||||
_planningPathWorldNavigationPoints = new List<NavigationPoint>();
|
||||
foreach (var index in Enumerable.Range(0, path.Count))
|
||||
{
|
||||
foreach (int index in Enumerable.Range(0, path.Count)) {
|
||||
_planningPathWorldNavigationPoints.Add(
|
||||
new NavigationPoint(World.HexGrid.GetHexCenterVec3FromOffset(path[index].OffsetCoords)));
|
||||
}
|
||||
|
@ -86,40 +73,36 @@ public class NavigationComponent : Spatial
|
|||
// Ensure the last point coincides with the target position
|
||||
if (_planningPathWorldNavigationPoints.Count > 0 &&
|
||||
(_planningPathWorldNavigationPoints.Last().WorldPosition - toPositionWorld).LengthSquared() <
|
||||
0.5f * 0.5f)
|
||||
{
|
||||
0.5f * 0.5f) {
|
||||
_planningPathWorldNavigationPoints[_planningPathWorldNavigationPoints.Count - 1].WorldPosition =
|
||||
toPositionWorld;
|
||||
}
|
||||
|
||||
// Perform smoothing
|
||||
_planningPathSmoothedWorldNavigationPoints = SmoothPath(body, _planningPathWorldNavigationPoints);
|
||||
_planningPathSmoothedWorldNavigationPoints = World.SmoothPath(entity, _planningPathWorldNavigationPoints);
|
||||
|
||||
// Ensure starting point is the current position
|
||||
if (_planningPathSmoothedWorldNavigationPoints.Count > 0)
|
||||
{
|
||||
if (_planningPathSmoothedWorldNavigationPoints.Count > 0) {
|
||||
_planningPathSmoothedWorldNavigationPoints[0] = new NavigationPoint(fromPositionWorld);
|
||||
}
|
||||
}
|
||||
|
||||
public void FindPath(KinematicBody body, Vector3 fromPositionWorld, NavigationPoint navigationPoint)
|
||||
{
|
||||
FindPath(body, fromPositionWorld, navigationPoint.WorldPosition);
|
||||
public void FindPath(Entity entity, Vector3 fromPositionWorld, NavigationPoint navigationPoint) {
|
||||
FindPath(entity, fromPositionWorld, navigationPoint.WorldPosition);
|
||||
|
||||
_planningPathWorldNavigationPoints[_planningPathWorldNavigationPoints.Count - 1] = navigationPoint;
|
||||
_planningPathSmoothedWorldNavigationPoints[_planningPathSmoothedWorldNavigationPoints.Count - 1] =
|
||||
navigationPoint;
|
||||
}
|
||||
|
||||
public void PlanGridPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld)
|
||||
{
|
||||
var fromPositionOffset = World.WorldToOffsetCoords(fromPositionWorld);
|
||||
var toPositionOffset = World.WorldToOffsetCoords(toPositionWorld);
|
||||
public void PlanGridPath(Entity entity, Vector3 fromPositionWorld, Vector3 toPositionWorld) {
|
||||
Vector2 fromPositionOffset = World.WorldToOffsetCoords(fromPositionWorld);
|
||||
Vector2 toPositionOffset = World.WorldToOffsetCoords(toPositionWorld);
|
||||
|
||||
var fromCell = new HexCell();
|
||||
HexCell fromCell = new();
|
||||
fromCell.OffsetCoords = fromPositionOffset;
|
||||
|
||||
var toCell = new HexCell();
|
||||
HexCell toCell = new();
|
||||
toCell.OffsetCoords = toPositionOffset;
|
||||
|
||||
_path = fromCell.LineTo(toCell);
|
||||
|
@ -129,26 +112,23 @@ public class NavigationComponent : Spatial
|
|||
_pathWorldNavigationPoints.Add(
|
||||
new NavigationPoint(World.HexGrid.GetHexCenterVec3FromOffset(fromPositionOffset)));
|
||||
|
||||
foreach (var index in Enumerable.Range(1, _path.Length - 1))
|
||||
{
|
||||
foreach (int index in Enumerable.Range(1, _path.Length - 1)) {
|
||||
_pathWorldNavigationPoints.Add(
|
||||
new NavigationPoint(World.GetHexCenterFromOffset(_path[index].OffsetCoords)));
|
||||
}
|
||||
|
||||
if ((fromPositionWorld - World.GetHexCenterFromOffset(toCell.OffsetCoords)).LengthSquared() >
|
||||
Globals.EpsPositionSquared)
|
||||
{
|
||||
// Remove the last one, because it is only the position rounded to HexGrid coordinates.
|
||||
if (_pathWorldNavigationPoints.Count > 0)
|
||||
{
|
||||
{
|
||||
if (_pathWorldNavigationPoints.Count > 0) {
|
||||
_pathWorldNavigationPoints.RemoveAt(_pathWorldNavigationPoints.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
_pathWorldNavigationPoints.Add(new NavigationPoint(toPositionWorld));
|
||||
if (_pathWorldNavigationPoints.Count > 2)
|
||||
{
|
||||
_smoothedPathWorldNavigationPoints = SmoothPath(body, _pathWorldNavigationPoints);
|
||||
if (_pathWorldNavigationPoints.Count > 2) {
|
||||
_smoothedPathWorldNavigationPoints = SmoothPath(entity, _pathWorldNavigationPoints);
|
||||
_pathWorldNavigationPoints = _smoothedPathWorldNavigationPoints;
|
||||
}
|
||||
|
||||
|
@ -156,36 +136,28 @@ public class NavigationComponent : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void PlanGridPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld,
|
||||
Quat toWorldOrientation)
|
||||
{
|
||||
PlanGridPath(body, fromPositionWorld, toPositionWorld);
|
||||
public void PlanGridPath(Entity entity, Vector3 fromPositionWorld, Vector3 toPositionWorld,
|
||||
Quat toWorldOrientation) {
|
||||
PlanGridPath(entity, fromPositionWorld, toPositionWorld);
|
||||
|
||||
_pathWorldNavigationPoints.Add(new NavigationPoint(toWorldOrientation));
|
||||
}
|
||||
|
||||
|
||||
public void PlanGridPath(KinematicBody body, Transform fromTransformWorld, NavigationPoint navigationPoint)
|
||||
{
|
||||
public void PlanGridPath(Entity entity, Transform fromTransformWorld, NavigationPoint navigationPoint) {
|
||||
if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)
|
||||
&& navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation))
|
||||
{
|
||||
PlanGridPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition,
|
||||
&& navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation)) {
|
||||
PlanGridPath(entity, fromTransformWorld.origin, navigationPoint.WorldPosition,
|
||||
navigationPoint.WorldOrientation);
|
||||
}
|
||||
else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position))
|
||||
{
|
||||
PlanGridPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)) {
|
||||
PlanGridPath(entity, fromTransformWorld.origin, navigationPoint.WorldPosition);
|
||||
} else {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void PlanDirectPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld)
|
||||
{
|
||||
public void PlanDirectPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld) {
|
||||
_pathWorldNavigationPoints.Clear();
|
||||
_pathWorldNavigationPoints.Add(new NavigationPoint(toPositionWorld));
|
||||
|
||||
|
@ -194,23 +166,20 @@ public class NavigationComponent : Spatial
|
|||
|
||||
|
||||
public void PlanDirectPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld,
|
||||
Quat toWorldOrientation)
|
||||
{
|
||||
Quat toWorldOrientation) {
|
||||
PlanDirectPath(body, fromPositionWorld, toPositionWorld);
|
||||
|
||||
_pathWorldNavigationPoints.Add(new NavigationPoint(toWorldOrientation));
|
||||
}
|
||||
|
||||
|
||||
public bool HasPathCollision(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld)
|
||||
{
|
||||
public bool HasPathCollision(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld) {
|
||||
Vector3 fromPositionLocal = GlobalTransform.XformInv(fromPositionWorld);
|
||||
Vector3 toPositionLocal = GlobalTransform.XformInv(toPositionWorld);
|
||||
Vector3 relativeVelocity = GlobalTransform.basis.Xform(toPositionLocal - fromPositionLocal);
|
||||
|
||||
KinematicCollision moveCollision = body.MoveAndCollide(relativeVelocity, true, true, true);
|
||||
if (moveCollision != null)
|
||||
{
|
||||
if (moveCollision != null) {
|
||||
Spatial colliderSpatial = moveCollision.Collider as Spatial;
|
||||
// GD.Print("Found collision: " + moveCollision.Collider + " (" + colliderSpatial.Name + ")");
|
||||
return true;
|
||||
|
@ -220,37 +189,30 @@ public class NavigationComponent : Spatial
|
|||
}
|
||||
|
||||
|
||||
public bool CheckSweptTriangleCellCollision(Vector3 startWorld, Vector3 endWorld, float radius)
|
||||
{
|
||||
Vector2 startPlane = new Vector2(startWorld.x, startWorld.z);
|
||||
Vector2 endPlane = new Vector2(endWorld.x, endWorld.z);
|
||||
public bool CheckSweptTriangleCellCollision(Vector3 startWorld, Vector3 endWorld, float radius) {
|
||||
Vector2 startPlane = new(startWorld.x, startWorld.z);
|
||||
Vector2 endPlane = new(endWorld.x, endWorld.z);
|
||||
Vector2 directionPlane = (endPlane - startPlane).Normalized();
|
||||
Vector2 sidePlane = directionPlane.Rotated(Mathf.Pi * 0.5f);
|
||||
|
||||
List<HexCell> cells =
|
||||
World.HexGrid.GetCellsForLine(startPlane + directionPlane * radius, endPlane + directionPlane * radius);
|
||||
foreach (HexCell cell in cells)
|
||||
{
|
||||
if (World.HexGrid.GetHexCost(cell) == 0)
|
||||
{
|
||||
foreach (HexCell cell in cells) {
|
||||
if (World.HexGrid.GetHexCost(cell) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
cells = World.HexGrid.GetCellsForLine(startPlane + sidePlane * radius, endPlane + sidePlane * radius);
|
||||
foreach (HexCell cell in cells)
|
||||
{
|
||||
if (World.HexGrid.GetHexCost(cell) == 0)
|
||||
{
|
||||
foreach (HexCell cell in cells) {
|
||||
if (World.HexGrid.GetHexCost(cell) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
cells = World.HexGrid.GetCellsForLine(startPlane - sidePlane * radius, endPlane - sidePlane * radius);
|
||||
foreach (HexCell cell in cells)
|
||||
{
|
||||
if (World.HexGrid.GetHexCost(cell) == 0)
|
||||
{
|
||||
foreach (HexCell cell in cells) {
|
||||
if (World.HexGrid.GetHexCost(cell) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -258,29 +220,24 @@ public class NavigationComponent : Spatial
|
|||
return false;
|
||||
}
|
||||
|
||||
public List<NavigationPoint> SmoothPath(KinematicBody body, List<NavigationPoint> navigationPoints)
|
||||
{
|
||||
if (navigationPoints.Count <= 2)
|
||||
{
|
||||
public List<NavigationPoint> SmoothPath(KinematicBody body, List<NavigationPoint> navigationPoints) {
|
||||
if (navigationPoints.Count <= 2) {
|
||||
return navigationPoints;
|
||||
}
|
||||
|
||||
Vector3 bodyGlobalTranslation = body.GlobalTranslation;
|
||||
List<NavigationPoint> smoothedPath = new List<NavigationPoint>();
|
||||
List<NavigationPoint> smoothedPath = new();
|
||||
|
||||
int startIndex = 0;
|
||||
int endIndex = navigationPoints.Count > 1 ? 1 : 0;
|
||||
smoothedPath.Add(navigationPoints[startIndex]);
|
||||
Vector3 startPoint = navigationPoints[startIndex].WorldPosition;
|
||||
|
||||
while (endIndex != navigationPoints.Count)
|
||||
{
|
||||
while (endIndex != navigationPoints.Count) {
|
||||
Vector3 endPoint = navigationPoints[endIndex].WorldPosition;
|
||||
|
||||
if (CheckSweptTriangleCellCollision(startPoint, endPoint, 0.27f))
|
||||
{
|
||||
if (endIndex - startIndex == 1)
|
||||
{
|
||||
if (CheckSweptTriangleCellCollision(startPoint, endPoint, 0.27f)) {
|
||||
if (endIndex - startIndex == 1) {
|
||||
GD.Print("Aborting SmoothPath: input path passes through collision geometry.");
|
||||
body.GlobalTranslation = bodyGlobalTranslation;
|
||||
return smoothedPath;
|
||||
|
@ -294,8 +251,7 @@ public class NavigationComponent : Spatial
|
|||
continue;
|
||||
}
|
||||
|
||||
if (endIndex == navigationPoints.Count - 1)
|
||||
{
|
||||
if (endIndex == navigationPoints.Count - 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -308,34 +264,25 @@ public class NavigationComponent : Spatial
|
|||
return smoothedPath;
|
||||
}
|
||||
|
||||
public void PlanDirectPath(KinematicBody body, Transform fromTransformWorld, NavigationPoint navigationPoint)
|
||||
{
|
||||
public void PlanDirectPath(KinematicBody body, Transform fromTransformWorld, NavigationPoint navigationPoint) {
|
||||
if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)
|
||||
&& navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation))
|
||||
{
|
||||
&& navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation)) {
|
||||
PlanDirectPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition,
|
||||
navigationPoint.WorldOrientation);
|
||||
}
|
||||
else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position))
|
||||
{
|
||||
} else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)) {
|
||||
PlanDirectPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public void ActivatePlannedPath()
|
||||
{
|
||||
public void ActivatePlannedPath() {
|
||||
_pathWorldNavigationPoints = _planningPathSmoothedWorldNavigationPoints;
|
||||
UpdateCurrentGoal();
|
||||
}
|
||||
|
||||
private void UpdateCurrentGoal()
|
||||
{
|
||||
if (_pathWorldNavigationPoints.Count == 0)
|
||||
{
|
||||
private void UpdateCurrentGoal() {
|
||||
if (_pathWorldNavigationPoints.Count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -344,73 +291,56 @@ public class NavigationComponent : Spatial
|
|||
CurrentGoalAngleWorld = _pathWorldNavigationPoints[0].WorldAngle;
|
||||
}
|
||||
|
||||
private void ApplyExistingTransform(Transform worldTransform)
|
||||
{
|
||||
if (_currentGoal.Flags == NavigationPoint.NavigationFlags.Orientation)
|
||||
{
|
||||
private void ApplyExistingTransform(Transform worldTransform) {
|
||||
if (_currentGoal.Flags == NavigationPoint.NavigationFlags.Orientation) {
|
||||
CurrentGoalPositionWorld = worldTransform.origin;
|
||||
}
|
||||
else if (_currentGoal.Flags == NavigationPoint.NavigationFlags.Position)
|
||||
{
|
||||
} else if (_currentGoal.Flags == NavigationPoint.NavigationFlags.Position) {
|
||||
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(worldTransform);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void UpdateCurrentGoal(Transform currentTransformWorld)
|
||||
{
|
||||
if (_currentGoal == null)
|
||||
{
|
||||
public void UpdateCurrentGoal(Transform currentTransformWorld) {
|
||||
if (_currentGoal == null) {
|
||||
_currentGoal = new NavigationPoint(currentTransformWorld);
|
||||
}
|
||||
|
||||
if (_pathWorldNavigationPoints.Count == 0)
|
||||
{
|
||||
if (_pathWorldNavigationPoints.Count == 0) {
|
||||
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
|
||||
CurrentGoalPositionWorld = currentTransformWorld.origin;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Position))
|
||||
{
|
||||
if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)) {
|
||||
CurrentGoalPositionWorld = _pathWorldNavigationPoints[0].WorldPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
|
||||
}
|
||||
|
||||
if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation))
|
||||
{
|
||||
if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation)) {
|
||||
CurrentGoalAngleWorld = _currentGoal.WorldAngle;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
|
||||
}
|
||||
|
||||
if (_currentGoal.IsReached(currentTransformWorld))
|
||||
{
|
||||
if (_currentGoal.IsReached(currentTransformWorld)) {
|
||||
_pathWorldNavigationPoints.RemoveAt(0);
|
||||
|
||||
UpdateCurrentGoal();
|
||||
ApplyExistingTransform(currentTransformWorld);
|
||||
}
|
||||
|
||||
if (_pathWorldNavigationPoints.Count == 0)
|
||||
{
|
||||
if (_pathWorldNavigationPoints.Count == 0) {
|
||||
CurrentGoalPositionWorld = currentTransformWorld.origin;
|
||||
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsGoalReached()
|
||||
{
|
||||
public bool IsGoalReached() {
|
||||
return _pathWorldNavigationPoints.Count == 0;
|
||||
}
|
||||
|
||||
public void DebugDraw(Spatial parentNode, DebugGeometry debugGeometry)
|
||||
{
|
||||
public void DebugDraw(Spatial parentNode, DebugGeometry debugGeometry) {
|
||||
Vector3 yOffset = Vector3.Up * 0.1f;
|
||||
|
||||
debugGeometry.GlobalTransform = Transform.Identity;
|
||||
|
@ -428,8 +358,7 @@ public class NavigationComponent : Spatial
|
|||
debugGeometry.PopTransform();
|
||||
|
||||
Vector3 previousPoint = parentNode.GlobalTranslation;
|
||||
foreach (NavigationPoint point in _pathWorldNavigationPoints)
|
||||
{
|
||||
foreach (NavigationPoint point in _pathWorldNavigationPoints) {
|
||||
debugGeometry.AddVertex(previousPoint + yOffset);
|
||||
debugGeometry.AddVertex(point.WorldPosition + yOffset);
|
||||
|
||||
|
@ -437,8 +366,7 @@ public class NavigationComponent : Spatial
|
|||
}
|
||||
|
||||
previousPoint = parentNode.GlobalTranslation;
|
||||
foreach (NavigationPoint point in _smoothedPathWorldNavigationPoints)
|
||||
{
|
||||
foreach (NavigationPoint point in _smoothedPathWorldNavigationPoints) {
|
||||
debugGeometry.SetColor(new Color(0, 0, 1));
|
||||
debugGeometry.AddVertex(previousPoint + yOffset);
|
||||
debugGeometry.AddVertex(point.WorldPosition + yOffset);
|
||||
|
@ -447,8 +375,7 @@ public class NavigationComponent : Spatial
|
|||
}
|
||||
|
||||
previousPoint = parentNode.GlobalTranslation;
|
||||
foreach (NavigationPoint point in _planningPathWorldNavigationPoints)
|
||||
{
|
||||
foreach (NavigationPoint point in _planningPathWorldNavigationPoints) {
|
||||
debugGeometry.SetColor(new Color(1, 0, 1));
|
||||
debugGeometry.AddVertex(previousPoint + yOffset);
|
||||
debugGeometry.AddVertex(point.WorldPosition + yOffset);
|
||||
|
@ -457,8 +384,7 @@ public class NavigationComponent : Spatial
|
|||
}
|
||||
|
||||
previousPoint = parentNode.GlobalTranslation;
|
||||
foreach (NavigationPoint point in _planningPathSmoothedWorldNavigationPoints)
|
||||
{
|
||||
foreach (NavigationPoint point in _planningPathSmoothedWorldNavigationPoints) {
|
||||
debugGeometry.SetColor(new Color(1, 1, 0));
|
||||
debugGeometry.AddVertex(previousPoint + yOffset);
|
||||
debugGeometry.AddVertex(point.WorldPosition + yOffset);
|
||||
|
|
|
@ -1,81 +1,72 @@
|
|||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
public class TaskQueueComponent : Component
|
||||
{
|
||||
public class TaskQueueComponent : Component {
|
||||
[Signal]
|
||||
private delegate void StartInteraction(Entity entity, Entity targetEntity);
|
||||
|
||||
public Queue<Task> Queue;
|
||||
|
||||
public TaskQueueComponent()
|
||||
{
|
||||
public TaskQueueComponent() {
|
||||
Queue = new Queue<Task>();
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
public void Reset() {
|
||||
Queue.Clear();
|
||||
}
|
||||
|
||||
public void Process(Entity entity, float delta)
|
||||
{
|
||||
if (Queue.Count == 0) return;
|
||||
public void Process(Entity entity, float delta) {
|
||||
if (Queue.Count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
var currentTask = Queue.Peek();
|
||||
var interactionTask = currentTask as InteractionTask;
|
||||
if (interactionTask != null) EmitSignal("StartInteraction", entity, interactionTask.TargetEntity);
|
||||
do {
|
||||
Task currentTask = Queue.Peek();
|
||||
|
||||
if (currentTask.PerformTask(entity, delta))
|
||||
if (currentTask.PerformTask(entity, this, delta)) {
|
||||
Queue.Dequeue();
|
||||
else
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (Queue.Count > 0);
|
||||
}
|
||||
|
||||
public abstract class Task : Object
|
||||
{
|
||||
public abstract class Task : Object {
|
||||
/// <summary>
|
||||
/// Executes a Task on the specified entity.
|
||||
/// </summary>
|
||||
/// <returns>true when the Task is complete, false otherwise</returns>
|
||||
public abstract bool PerformTask(Entity entity, float delta);
|
||||
public abstract bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes an entity move towards a target (translation and or orientation).
|
||||
/// </summary>
|
||||
public class NavigationTask : Task
|
||||
{
|
||||
public class NavigationTask : Task {
|
||||
public NavigationPoint NavigationPoint;
|
||||
public bool PlanningComplete = false;
|
||||
|
||||
public NavigationTask(NavigationPoint navigationPoint)
|
||||
{
|
||||
public NavigationTask(NavigationPoint navigationPoint) {
|
||||
NavigationPoint = navigationPoint;
|
||||
}
|
||||
|
||||
public override bool PerformTask(Entity entity, float delta)
|
||||
{
|
||||
public override bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta) {
|
||||
return NavigationPoint.IsReached(entity.GlobalTransform);
|
||||
}
|
||||
}
|
||||
|
||||
public class InteractionTask : Task
|
||||
{
|
||||
public class InteractionTask : Task {
|
||||
public Entity TargetEntity;
|
||||
|
||||
public InteractionTask(Entity entity)
|
||||
{
|
||||
public InteractionTask(Entity entity) {
|
||||
TargetEntity = entity;
|
||||
}
|
||||
|
||||
public override bool PerformTask(Entity entity, float delta)
|
||||
{
|
||||
public override bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta) {
|
||||
taskQueueComponent.EmitSignal("StartInteraction", entity, TargetEntity);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
using Godot;
|
||||
|
||||
public class WorldInfoComponent : Component
|
||||
{
|
||||
public class WorldInfoComponent : Component {
|
||||
[Export] public NodePath WorldPath;
|
||||
public World World;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
World = GetNode<World>(WorldPath);
|
||||
}
|
||||
|
||||
public void SetWorld(World world)
|
||||
{
|
||||
public void SetWorld(World world) {
|
||||
World = world;
|
||||
}
|
||||
}
|
|
@ -1,11 +1,6 @@
|
|||
using Godot;
|
||||
using System;
|
||||
|
||||
public class Axe : StaticBody
|
||||
{
|
||||
public class Axe : StaticBody {
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
public override void _Ready() { }
|
||||
}
|
|
@ -3,13 +3,11 @@ using Godot;
|
|||
using GodotComponentTest.components;
|
||||
using GodotComponentTest.entities;
|
||||
|
||||
public class Chest : Entity, IInteractionInterface
|
||||
{
|
||||
public class Chest : Entity, IInteractionInterface {
|
||||
// resources
|
||||
private readonly PackedScene _goldBarScene = GD.Load<PackedScene>("res://entities/GoldBar.tscn");
|
||||
|
||||
public enum LidState
|
||||
{
|
||||
public enum LidState {
|
||||
Closed,
|
||||
Open
|
||||
}
|
||||
|
@ -29,8 +27,7 @@ public class Chest : Entity, IInteractionInterface
|
|||
private delegate void ChestOpened(Entity entity);
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_mesh = GetNode<MeshInstance>("Geometry/Skeleton/Chest");
|
||||
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
|
||||
|
||||
|
@ -42,64 +39,51 @@ public class Chest : Entity, IInteractionInterface
|
|||
|
||||
|
||||
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||
int shapeIndex)
|
||||
{
|
||||
if (IsMouseOver && inputEvent is InputEventMouseButton)
|
||||
{
|
||||
int shapeIndex) {
|
||||
if (IsMouseOver && inputEvent is InputEventMouseButton) {
|
||||
InputEventMouseButton mouseButtonEvent = (InputEventMouseButton)inputEvent;
|
||||
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed)
|
||||
{
|
||||
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed) {
|
||||
EmitSignal("EntityClicked", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnAreaMouseEntered()
|
||||
{
|
||||
public void OnAreaMouseEntered() {
|
||||
IsMouseOver = true;
|
||||
SpatialMaterial overrideMaterial = new SpatialMaterial();
|
||||
SpatialMaterial overrideMaterial = new();
|
||||
overrideMaterial.AlbedoColor = new Color(1, 0, 0);
|
||||
_mesh.MaterialOverride = overrideMaterial;
|
||||
}
|
||||
|
||||
|
||||
public void OnAreaMouseExited()
|
||||
{
|
||||
public void OnAreaMouseExited() {
|
||||
IsMouseOver = false;
|
||||
_mesh.MaterialOverride = null;
|
||||
}
|
||||
|
||||
|
||||
public void OnInteractionStart()
|
||||
{
|
||||
public void OnInteractionStart() {
|
||||
_animationPlayer.Stop();
|
||||
|
||||
if (State == LidState.Closed)
|
||||
{
|
||||
if (State == LidState.Closed) {
|
||||
State = LidState.Open;
|
||||
_animationPlayer.Play("ChestOpen");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_animationPlayer.PlayBackwards("ChestOpen");
|
||||
State = LidState.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnInteractionEnd()
|
||||
{
|
||||
|
||||
}
|
||||
public void OnInteractionEnd() { }
|
||||
|
||||
public void OnChestOpened()
|
||||
{
|
||||
public void OnChestOpened() {
|
||||
GD.Print("Chest now opened!");
|
||||
foreach (int i in Enumerable.Range(0, 10))
|
||||
{
|
||||
foreach (int i in Enumerable.Range(0, 10)) {
|
||||
GoldBar bar = (GoldBar)_goldBarScene.Instance();
|
||||
bar.Transform = new Transform(Transform.basis.Rotated(Vector3.Up, GD.Randf() * 2 * Mathf.Pi), Transform.origin + Vector3.Up * 0.8f);
|
||||
bar.Transform = new Transform(Transform.basis.Rotated(Vector3.Up, GD.Randf() * 2 * Mathf.Pi),
|
||||
Transform.origin + Vector3.Up * 0.8f);
|
||||
bar.velocity = new Vector3(
|
||||
(GD.Randf() * 2f - 1f) * 2,
|
||||
5 + GD.Randf() * 0.3f,
|
||||
|
@ -108,8 +92,7 @@ public class Chest : Entity, IInteractionInterface
|
|||
GetParent().AddChild(bar);
|
||||
}
|
||||
|
||||
if (InteractionComponent != null)
|
||||
{
|
||||
if (InteractionComponent != null) {
|
||||
InteractionComponent.EndInteraction();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +1,24 @@
|
|||
using Godot;
|
||||
using System;
|
||||
|
||||
public class Entity : KinematicBody
|
||||
{
|
||||
public class Entity : KinematicBody {
|
||||
public Vector3 Velocity { get; set; } = Vector3.Zero;
|
||||
public float RotationalVelocity { get; set; } = 0;
|
||||
|
||||
/** Defines the angle in plane coordinates, 0 => pointing to the right/east, pi/2 pointing up/north, range [-pi,pi]. */
|
||||
public float PlaneAngle
|
||||
{
|
||||
/**
|
||||
* Defines the angle in plane coordinates, 0 => pointing to the right/east, pi/2 pointing up/north, range [-pi,pi].
|
||||
*/
|
||||
public float PlaneAngle {
|
||||
get => Globals.CalcPlaneAngle(GlobalTransform);
|
||||
set => GlobalTransform = new Transform(new Basis(Vector3.Up, value + Mathf.Pi * 0.5f), GlobalTranslation);
|
||||
}
|
||||
|
||||
public float CalcShortestPlaneRotationToTargetDirection(Vector3 globalTargetDirection)
|
||||
{
|
||||
|
||||
public float CalcShortestPlaneRotationToTargetDirection(Vector3 globalTargetDirection) {
|
||||
float angleToTarget = Vector3.Right.SignedAngleTo(globalTargetDirection, Vector3.Up);
|
||||
float currentAngle = PlaneAngle;
|
||||
|
||||
float delta = angleToTarget - currentAngle;
|
||||
|
||||
delta += (delta > Mathf.Pi) ? -Mathf.Pi * 2 : (delta < -Mathf.Pi) ? Mathf.Pi * 2 : 0;
|
||||
|
||||
delta += delta > Mathf.Pi ? -Mathf.Pi * 2 : delta < -Mathf.Pi ? Mathf.Pi * 2 : 0;
|
||||
return delta;
|
||||
}
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,61 +1,49 @@
|
|||
using Godot;
|
||||
using System;
|
||||
|
||||
public class GoldBar : KinematicBody
|
||||
{
|
||||
public class GoldBar : KinematicBody {
|
||||
private Vector3 targetPosition;
|
||||
private bool hasTarget = false;
|
||||
private bool hasTarget;
|
||||
public Vector3 velocity;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
targetPosition = GlobalTransform.origin;
|
||||
}
|
||||
|
||||
public void SetTarget(Vector3 target)
|
||||
{
|
||||
public void SetTarget(Vector3 target) {
|
||||
targetPosition = target;
|
||||
hasTarget = true;
|
||||
}
|
||||
|
||||
public void UnsetTarget()
|
||||
{
|
||||
public void UnsetTarget() {
|
||||
hasTarget = false;
|
||||
}
|
||||
|
||||
// Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
public override void _PhysicsProcess(float delta)
|
||||
{
|
||||
if (hasTarget)
|
||||
{
|
||||
if (targetPosition.IsEqualApprox(GlobalTransform.origin))
|
||||
{
|
||||
public override void _PhysicsProcess(float delta) {
|
||||
if (hasTarget) {
|
||||
if (targetPosition.IsEqualApprox(GlobalTransform.origin)) {
|
||||
targetPosition = GlobalTransform.origin;
|
||||
velocity = Vector3.Zero;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector3 targetDirection = (targetPosition - GlobalTransform.origin).Normalized();
|
||||
velocity = targetDirection * (velocity.Length() + 10 * delta);
|
||||
Transform = new Transform(this.Transform.basis.Rotated(Vector3.Up, delta * 2.0f), Transform.origin);
|
||||
}
|
||||
else
|
||||
{
|
||||
Transform = new Transform(Transform.basis.Rotated(Vector3.Up, delta * 2.0f), Transform.origin);
|
||||
} else {
|
||||
velocity.y = velocity.y - 9.81f * delta;
|
||||
}
|
||||
|
||||
velocity = MoveAndSlide(velocity, Vector3.Up);
|
||||
|
||||
if (IsOnFloor() || Mathf.Abs(Transform.origin.y) < 0.01)
|
||||
{
|
||||
if (IsOnFloor() || Mathf.Abs(Transform.origin.y) < 0.01) {
|
||||
// apply damping when on ground
|
||||
velocity = velocity - velocity.Normalized() * 0.9f * delta;
|
||||
}
|
||||
|
||||
if (velocity.LengthSquared() < 0.01)
|
||||
{
|
||||
|
||||
if (velocity.LengthSquared() < 0.01) {
|
||||
velocity = Vector3.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,14 +2,9 @@ using GodotComponentTest.components;
|
|||
|
||||
namespace GodotComponentTest.entities;
|
||||
|
||||
public interface IInteractionInterface
|
||||
{
|
||||
public interface IInteractionInterface {
|
||||
void OnInteractionStart();
|
||||
void OnInteractionEnd();
|
||||
|
||||
InteractionComponent InteractionComponent
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
InteractionComponent InteractionComponent { get; set; }
|
||||
}
|
|
@ -5,8 +5,7 @@ using GodotComponentTest.components;
|
|||
using GodotComponentTest.entities;
|
||||
using GodotComponentTest.utils;
|
||||
|
||||
public class Player : Entity, IInteractionInterface
|
||||
{
|
||||
public class Player : Entity, IInteractionInterface {
|
||||
// public members
|
||||
[Export] public NodePath WorldNode;
|
||||
|
||||
|
@ -30,8 +29,7 @@ public class Player : Entity, IInteractionInterface
|
|||
private BoneAttachment _toolAttachement;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_groundMotion = new GroundMotionComponent();
|
||||
_worldInfo = (WorldInfoComponent)FindNode("WorldInfo", false);
|
||||
NavigationComponent = (NavigationComponent)FindNode("Navigation", false);
|
||||
|
@ -39,56 +37,51 @@ public class Player : Entity, IInteractionInterface
|
|||
TaskQueueComponent = new TaskQueueComponent();
|
||||
|
||||
_itemAttractorArea = (Area)FindNode("ItemAttractorArea", false);
|
||||
if (_itemAttractorArea == null)
|
||||
{
|
||||
if (_itemAttractorArea == null) {
|
||||
GD.PushWarning("No ItemAttractorArea node found for " + GetClass());
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_itemAttractorArea.Connect("body_entered", this, nameof(OnItemAttractorBodyEntered));
|
||||
_itemAttractorArea.Connect("body_exited", this, nameof(OnItemAttractorBodyExited));
|
||||
}
|
||||
|
||||
_itemPickupArea = (Area)FindNode("ItemPickupArea", false);
|
||||
if (_itemPickupArea == null)
|
||||
if (_itemPickupArea == null) {
|
||||
GD.PushWarning("No ItemPickupArea node found for " + GetClass());
|
||||
else
|
||||
} else {
|
||||
_itemPickupArea.Connect("body_entered", this, nameof(OnItemPickupAreaBodyEntered));
|
||||
}
|
||||
|
||||
_playerAnimationPlayer = GetNode<AnimationPlayer>("Geometry/AnimationPlayer");
|
||||
Debug.Assert(_playerAnimationPlayer != null);
|
||||
_animationTree = GetNode<AnimationTree>("Geometry/AnimationTree");
|
||||
Debug.Assert(_animationTree != null);
|
||||
var stateMachine =
|
||||
AnimationNodeStateMachinePlayback stateMachine =
|
||||
(AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
|
||||
stateMachine.Start("Idle");
|
||||
|
||||
_toolAttachement = (BoneAttachment)FindNode("ToolAttachement");
|
||||
if (_toolAttachement == null) GD.PushWarning("No ToolAttachement found!");
|
||||
if (_toolAttachement == null) {
|
||||
GD.PushWarning("No ToolAttachement found!");
|
||||
}
|
||||
|
||||
_debugGeometry = (DebugGeometry)FindNode("DebugGeometry");
|
||||
}
|
||||
|
||||
|
||||
public override void _PhysicsProcess(float delta)
|
||||
{
|
||||
public override void _PhysicsProcess(float delta) {
|
||||
base._PhysicsProcess(delta);
|
||||
|
||||
if (NavigationComponent == null)
|
||||
{
|
||||
if (NavigationComponent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (TaskQueueComponent != null && TaskQueueComponent.Queue.Count > 0)
|
||||
{
|
||||
if (TaskQueueComponent != null && TaskQueueComponent.Queue.Count > 0) {
|
||||
TaskQueueComponent.Process(this, delta);
|
||||
|
||||
if (TaskQueueComponent.Queue.Count > 0)
|
||||
{
|
||||
var currentTask = TaskQueueComponent.Queue.Peek();
|
||||
if (TaskQueueComponent.Queue.Count > 0) {
|
||||
TaskQueueComponent.Task currentTask = TaskQueueComponent.Queue.Peek();
|
||||
TaskQueueComponent.NavigationTask navigationTask = currentTask as TaskQueueComponent.NavigationTask;
|
||||
if (navigationTask != null && navigationTask.PlanningComplete == false)
|
||||
{
|
||||
if (navigationTask != null && navigationTask.PlanningComplete == false) {
|
||||
// _navigationComponent.PlanGridPath(this, GlobalTransform, navigationTask.NavigationPoint);
|
||||
NavigationComponent.PlanSmoothedPath(this, GlobalTransform, navigationTask.NavigationPoint);
|
||||
|
||||
|
@ -100,24 +93,21 @@ public class Player : Entity, IInteractionInterface
|
|||
_groundMotion.PhysicsProcess(delta, this, NavigationComponent.CurrentGoalPositionWorld,
|
||||
NavigationComponent.CurrentGoalAngleWorld, _worldInfo.World);
|
||||
|
||||
if (NavigationComponent.IsGoalReached())
|
||||
if (NavigationComponent.IsGoalReached()) {
|
||||
navigationTask.NavigationPoint = new NavigationPoint(GlobalTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
if (NavigationComponent != null)
|
||||
{
|
||||
public override void _Process(float delta) {
|
||||
if (NavigationComponent != null) {
|
||||
NavigationComponent.UpdateCurrentGoal(GlobalTransform);
|
||||
}
|
||||
|
||||
foreach (Node node in _attractedItemList)
|
||||
{
|
||||
if (node is GoldBar)
|
||||
{
|
||||
foreach (Node node in _attractedItemList) {
|
||||
if (node is GoldBar) {
|
||||
GoldBar bar = (GoldBar)node;
|
||||
bar.SetTarget(GlobalTransform.origin);
|
||||
}
|
||||
|
@ -126,31 +116,25 @@ public class Player : Entity, IInteractionInterface
|
|||
UpdateDebugGeometry();
|
||||
}
|
||||
|
||||
public void UpdateDebugGeometry()
|
||||
{
|
||||
if (_debugGeometry == null || _debugGeometry.Visible == false)
|
||||
{
|
||||
public void UpdateDebugGeometry() {
|
||||
if (_debugGeometry == null || _debugGeometry.Visible == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
_debugGeometry.Clear();
|
||||
_debugGeometry.GlobalTransform = Transform.Identity;
|
||||
|
||||
if (NavigationComponent != null)
|
||||
{
|
||||
if (NavigationComponent != null) {
|
||||
NavigationComponent.DebugDraw(this, _debugGeometry);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnItemAttractorBodyEntered(Node node)
|
||||
{
|
||||
public void OnItemAttractorBodyEntered(Node node) {
|
||||
_attractedItemList.Add(node);
|
||||
}
|
||||
|
||||
public void OnItemAttractorBodyExited(Node node)
|
||||
{
|
||||
if (node is GoldBar)
|
||||
{
|
||||
public void OnItemAttractorBodyExited(Node node) {
|
||||
if (node is GoldBar) {
|
||||
GoldBar bar = (GoldBar)node;
|
||||
bar.UnsetTarget();
|
||||
}
|
||||
|
@ -158,17 +142,14 @@ public class Player : Entity, IInteractionInterface
|
|||
_attractedItemList.Remove(node);
|
||||
}
|
||||
|
||||
public void OnItemPickupAreaBodyEntered(Node body)
|
||||
{
|
||||
public void OnItemPickupAreaBodyEntered(Node body) {
|
||||
GD.Print("Picking up item: " + body.Name);
|
||||
|
||||
if (body is Axe)
|
||||
{
|
||||
if (body is Axe) {
|
||||
SetActiveTool("Axe");
|
||||
}
|
||||
|
||||
if (body is GoldBar)
|
||||
{
|
||||
if (body is GoldBar) {
|
||||
GoldCount++;
|
||||
EmitSignal("GoldCountChanged", GoldCount);
|
||||
}
|
||||
|
@ -176,39 +157,30 @@ public class Player : Entity, IInteractionInterface
|
|||
body.QueueFree();
|
||||
}
|
||||
|
||||
public void SetActiveTool(string toolName)
|
||||
{
|
||||
public void SetActiveTool(string toolName) {
|
||||
Debug.Assert(_toolAttachement != null);
|
||||
if (toolName == "Axe")
|
||||
{
|
||||
if (toolName == "Axe") {
|
||||
_toolAttachement.Visible = true;
|
||||
}
|
||||
else if (toolName == "")
|
||||
{
|
||||
} else if (toolName == "") {
|
||||
_toolAttachement.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnInteractionStart()
|
||||
{
|
||||
public void OnInteractionStart() {
|
||||
AnimationNodeStateMachinePlayback stateMachine =
|
||||
(AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
|
||||
Debug.Assert(stateMachine != null);
|
||||
|
||||
if (InteractionComponent.TargetEntity is Chest)
|
||||
{
|
||||
if (InteractionComponent.TargetEntity is Chest) {
|
||||
GD.Print("Player Opening Box");
|
||||
stateMachine.Travel("Interaction");
|
||||
}
|
||||
else if (InteractionComponent.TargetEntity is Tree)
|
||||
{
|
||||
} else if (InteractionComponent.TargetEntity is Tree) {
|
||||
GD.Print("Player Chopping Tree");
|
||||
stateMachine.Travel("Hit");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnInteractionEnd()
|
||||
{
|
||||
public void OnInteractionEnd() {
|
||||
GD.Print("Player Stopping Interaction");
|
||||
AnimationNodeStateMachinePlayback stateMachine =
|
||||
(AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
[gd_scene load_steps=14 format=2]
|
||||
[gd_scene load_steps=27 format=2]
|
||||
|
||||
[ext_resource path="res://entities/Player.cs" type="Script" id=1]
|
||||
[ext_resource path="res://components/NavigationComponent.cs" type="Script" id=2]
|
||||
[ext_resource path="res://materials/debug/PlayerPhysicsGeometry.tres" type="Material" id=3]
|
||||
[ext_resource path="res://assets/Characters/Pirate.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://assets/Objects/toolAxe.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://components/WorldInfoComponent.cs" type="Script" id=5]
|
||||
[ext_resource path="res://utils/DebugGeometry.cs" type="Script" id=6]
|
||||
[ext_resource path="res://components/MovableComponent.tscn" type="PackedScene" id=7]
|
||||
[ext_resource path="res://assets/CreatusPiratePack/Modified/Pirate1_Rigged.glb" type="PackedScene" id=8]
|
||||
|
||||
[sub_resource type="CapsuleShape" id=7]
|
||||
radius = 0.27
|
||||
|
@ -23,12 +24,315 @@ radius = 1.5
|
|||
[sub_resource type="SphereShape" id=23]
|
||||
radius = 0.1
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachinePlayback" id=28]
|
||||
|
||||
[sub_resource type="SpatialMaterial" id=25]
|
||||
flags_unshaded = true
|
||||
vertex_color_use_as_albedo = true
|
||||
|
||||
[sub_resource type="Animation" id=29]
|
||||
resource_name = "ArmatureAction"
|
||||
length = 0.791667
|
||||
tracks/0/type = "transform"
|
||||
tracks/0/path = NodePath("Armature/Skeleton:HandTip.R")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/keys = PoolRealArray( 0, 1, -6.33299e-08, 5.96046e-08, -8.72095e-09, 5.15244e-08, -0.167621, -2.38312e-08, 0.985852, 1, 1, 1, 0.791667, 1, -6.33299e-08, 5.96046e-08, -8.72095e-09, 5.15244e-08, -0.167621, -2.38312e-08, 0.985852, 1, 1, 1 )
|
||||
tracks/1/type = "transform"
|
||||
tracks/1/path = NodePath("Armature/Skeleton:LowerArm.R")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/keys = PoolRealArray( 0, 1, 2.98023e-08, 2.98023e-08, 1.02445e-07, 1.49012e-08, -2.98023e-08, -7.45058e-09, 1, 1, 1, 1, 0.0666667, 1, -1.49012e-08, 1.19209e-07, 9.31323e-09, 0.00109829, -8.64304e-05, 0.0102987, 0.999946, 1, 1, 1, 0.133333, 1, -4.47035e-08, -5.96046e-08, 8.56817e-08, 0.00783155, -0.00169418, 0.0734387, 0.997268, 1, 1, 1, 0.2, 1, -1.04308e-07, -1.19209e-07, 5.58794e-09, 0.018495, -0.0080773, 0.173433, 0.984639, 1, 1, 1, 0.266667, 1, -1.49012e-08, 8.9407e-08, -1.67638e-08, 0.0280373, -0.0229293, 0.262915, 0.964139, 1, 1, 1, 0.333333, 1, -1.3411e-07, 1.78814e-07, 1.15484e-07, 0.033043, -0.0493204, 0.309854, 0.948929, 1, 1, 1, 0.4, 1, -8.9407e-08, 5.96046e-08, 7.82311e-08, -0.15378, -0.132786, 0.29174, 0.93467, 1, 1, 1, 0.466667, 1, -1.19209e-07, -2.98023e-08, 3.35276e-08, -0.407158, -0.216318, 0.236834, 0.855184, 1, 1, 1, 0.533333, 1, -1.04308e-07, 5.96046e-08, 8.56817e-08, -0.452066, -0.143661, 0.218081, 0.8529, 1, 1, 1, 0.6, 1, -8.9407e-08, -5.96046e-08, 6.89179e-08, -0.315312, -0.00422263, 0.192105, 0.929331, 1, 1, 1, 0.666667, 1, -5.96046e-08, 5.96046e-08, 1.95578e-07, -0.071726, -0.000218779, 0.0546704, 0.995925, 1, 1, 1, 0.733333, 1, -8.9407e-08, 2.98023e-08, 2.98023e-08, 1.49012e-08, -2.98023e-08, 4.44089e-16, 1, 1, 1, 1, 0.791667, 1, 2.98023e-08, 2.98023e-08, 1.02445e-07, 1.49012e-08, -2.98023e-08, -7.45058e-09, 1, 1, 1, 1 )
|
||||
tracks/2/type = "transform"
|
||||
tracks/2/path = NodePath("Armature/Skeleton:UpperArm.R")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/keys = PoolRealArray( 0, 1, -2.98023e-08, -2.98023e-08, -5.96046e-08, -1.49012e-08, 0, 0, 1, 1, 1, 1, 0.0666667, 1, 1.49012e-08, -2.98023e-08, -4.47035e-08, 0.0108857, -6.76363e-05, 0.000112621, 0.999941, 1, 1, 1, 0.133333, 1, 0, -2.98023e-08, -5.96046e-08, 0.0781541, -0.00133826, 0.00222821, 0.996938, 1, 1, 1, 0.2, 1, 1.49012e-08, 2.98023e-08, -1.49012e-08, 0.185823, -0.00642065, 0.0106907, 0.982504, 1, 1, 1, 0.266667, 1, 2.98023e-08, 0, -2.98023e-08, 0.281247, -0.018186, 0.0302806, 0.958985, 1, 1, 1, 0.333333, 1, 1.19209e-07, 5.96046e-08, -5.96046e-08, 0.326813, -0.0385876, 0.0642504, 0.942113, 1, 1, 1, 0.4, 1, 0, 0, 0, 0.27597, -0.130105, 0.14414, 0.941348, 1, 1, 1, 0.466667, 1, 5.96046e-08, -5.96046e-08, 2.98023e-08, 0.155307, -0.238877, 0.223903, 0.932033, 1, 1, 1, 0.533333, 1, 8.9407e-08, 0, 0, 0.00938215, -0.220572, 0.130595, 0.966543, 1, 1, 1, 0.6, 1, 1.49012e-08, 2.98023e-08, -7.45058e-08, -0.0448046, -0.0741939, -0.0355394, 0.995603, 1, 1, 1, 0.666667, 1, -4.47035e-08, -2.98023e-08, 7.45058e-08, -0.0129521, -0.00546457, -0.0102737, 0.999848, 1, 1, 1, 0.733333, 1, -2.98023e-08, -1.19209e-07, 2.98023e-08, -1.49012e-08, 0, 0, 1, 1, 1, 1, 0.791667, 1, -2.98023e-08, -2.98023e-08, -5.96046e-08, -1.49012e-08, 0, 0, 1, 1, 1, 1 )
|
||||
tracks/3/type = "transform"
|
||||
tracks/3/path = NodePath("Armature/Skeleton:Shoulder.R")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/keys = PoolRealArray( 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0.0666667, 1, 4.25331e-10, 2.61906e-11, 0, 0.000588988, -0.00134978, -0.00209551, 0.999997, 1, 1, 1, 0.133333, 1, 3.42889e-09, -1.28054e-10, 0, 0.00420515, -0.00963742, -0.0149611, 0.999833, 1, 1, 1, 0.266667, 1, 1.60017e-08, 3.63217e-09, 1.19209e-07, 0.0152085, -0.0348548, -0.0541085, 0.997811, 1, 1, 1, 0.333333, 1, 1.38597e-08, -2.8136e-09, 0, 0.017721, -0.0406132, -0.0630476, 0.997026, 1, 1, 1, 0.4, 1, 4.95234e-10, -3.39933e-09, 0, -0.0677883, 0.0291052, 0.0488595, 0.996078, 1, 1, 1, 0.466667, 1, 3.0251e-08, 7.71792e-11, 0, -0.186396, 0.126963, 0.20584, 0.952243, 1, 1, 1, 0.533333, 1, 1.833e-08, 4.54755e-09, 1.19209e-07, -0.188148, 0.128888, 0.242103, 0.943066, 1, 1, 1, 0.6, 1, 8.41146e-09, -9.31308e-11, 0, -0.0808999, 0.0423329, 0.227882, 0.969398, 1, 1, 1, 0.666667, 1, 6.40912e-09, 7.10543e-15, 1.19209e-07, -0.00230095, -0.0193147, 0.175059, 0.984366, 1, 1, 1, 0.733333, 1, -4.16577e-10, 0, 0, -0.000324101, -0.00873649, 0.0635702, 0.997939, 1, 1, 1, 0.791667, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 )
|
||||
tracks/4/type = "transform"
|
||||
tracks/4/path = NodePath("Armature/Skeleton:HandTip.L")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/keys = PoolRealArray( 0, 1, 0, 0, 3.81116e-09, -1.86265e-09, 7.45058e-09, -1.17579e-08, 1, 1, 1, 1, 0.791667, 1, 0, 0, 3.81116e-09, -1.86265e-09, 7.45058e-09, -1.17579e-08, 1, 1, 1, 1 )
|
||||
tracks/5/type = "transform"
|
||||
tracks/5/path = NodePath("Armature/Skeleton:LowerArm.L")
|
||||
tracks/5/interp = 1
|
||||
tracks/5/loop_wrap = true
|
||||
tracks/5/imported = false
|
||||
tracks/5/enabled = true
|
||||
tracks/5/keys = PoolRealArray( 0, 1, -8.9407e-08, 2.98023e-08, 1.02445e-07, -1.49012e-08, -1.49012e-08, -2.98023e-08, 1, 1, 1, 1, 0.791667, 1, -8.9407e-08, 2.98023e-08, 1.02445e-07, -1.49012e-08, -1.49012e-08, -2.98023e-08, 1, 1, 1, 1 )
|
||||
tracks/6/type = "transform"
|
||||
tracks/6/path = NodePath("Armature/Skeleton:UpperArm.L")
|
||||
tracks/6/interp = 1
|
||||
tracks/6/loop_wrap = true
|
||||
tracks/6/imported = false
|
||||
tracks/6/enabled = true
|
||||
tracks/6/keys = PoolRealArray( 0, 1, -4.47035e-08, -2.98023e-08, 1.49012e-08, -1.49012e-08, -5.21541e-08, 1.49012e-08, 1, 1, 1, 1, 0.791667, 1, -4.47035e-08, -2.98023e-08, 1.49012e-08, -1.49012e-08, -5.21541e-08, 1.49012e-08, 1, 1, 1, 1 )
|
||||
tracks/7/type = "transform"
|
||||
tracks/7/path = NodePath("Armature/Skeleton:Shoulder.L")
|
||||
tracks/7/interp = 1
|
||||
tracks/7/loop_wrap = true
|
||||
tracks/7/imported = false
|
||||
tracks/7/enabled = true
|
||||
tracks/7/keys = PoolRealArray( 0, 1, 2.97255e-31, -2.64698e-23, 0, 0, 0, 0, 1, 1, 1, 1, 0.791667, 1, 2.97255e-31, -2.64698e-23, 0, 0, 0, 0, 1, 1, 1, 1 )
|
||||
tracks/8/type = "transform"
|
||||
tracks/8/path = NodePath("Armature/Skeleton:Base")
|
||||
tracks/8/interp = 1
|
||||
tracks/8/loop_wrap = true
|
||||
tracks/8/imported = false
|
||||
tracks/8/enabled = true
|
||||
tracks/8/keys = PoolRealArray( 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0.0666667, 1, 0, 0, 0, -0.00262969, -0.00462533, -7.91099e-05, 0.999986, 1, 1, 1, 0.133333, 1, 0, 0, 0, -0.0187834, -0.0330379, -0.000768041, 0.999277, 1, 1, 1, 0.266667, 1, 0, 0, 0, -0.0678217, -0.119291, -0.00597111, 0.990522, 1, 1, 1, 0.333333, 1, 0, 0, 0, -0.0791032, -0.139134, -0.0111504, 0.987046, 1, 1, 1, 0.4, 1, 0, 0, 0, 0.00167779, -0.0294607, -0.0182862, 0.999397, 1, 1, 1, 0.466667, 1, 0, 0, 0, 0.116381, 0.127423, -0.0233002, 0.984721, 1, 1, 1, 0.533333, 1, 0, 0, 0, 0.120038, 0.144348, -0.0211955, 0.981991, 1, 1, 1, 0.6, 1, 0, 0, 0, 0.0228862, 0.060128, -0.00882898, 0.997889, 1, 1, 1, 0.666667, 1, 0, 0, 0, -0.0459424, -8.28055e-25, 1.02013e-17, 0.998944, 1, 1, 1, 0.733333, 1, 0, 0, 0, -0.00918794, -3.32825e-25, 4.08026e-18, 0.999958, 1, 1, 1, 0.791667, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 )
|
||||
|
||||
[sub_resource type="Animation" id=30]
|
||||
resource_name = "Hit-loop"
|
||||
length = 0.791667
|
||||
loop = true
|
||||
tracks/0/type = "transform"
|
||||
tracks/0/path = NodePath("Armature/Skeleton:HandTip.R")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/keys = PoolRealArray( 0, 1, -6.33299e-08, 5.96046e-08, -8.72095e-09, 5.15244e-08, -0.167621, -2.38312e-08, 0.985852, 1, 1, 1, 0.333333, 1, -4.84288e-08, 8.9407e-08, -6.55356e-08, 2.541e-08, -0.167621, -2.04777e-08, 0.985852, 1, 1, 1, 0.4, 1, -4.84288e-08, 5.96046e-08, -1.18914e-08, 0.0547672, -0.0111317, -0.0100956, 0.998386, 1, 1, 1, 0.466667, 1, -3.72529e-08, 5.96046e-08, -7.89466e-08, 0.130055, 0.212042, -0.0239739, 0.968271, 1, 1, 1, 0.533333, 1, -6.70552e-08, 8.9407e-08, -3.72234e-08, 0.146974, 0.263647, -0.0270928, 0.952971, 1, 1, 1, 0.791667, 1, -6.33299e-08, 5.96046e-08, -8.72095e-09, 0.146974, 0.263647, -0.0270928, 0.952971, 1, 1, 1 )
|
||||
tracks/1/type = "transform"
|
||||
tracks/1/path = NodePath("Armature/Skeleton:LowerArm.R")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/keys = PoolRealArray( 0, 1, 2.98023e-08, 2.98023e-08, 1.02445e-07, 1.49012e-08, -2.98023e-08, -7.45058e-09, 1, 1, 1, 1, 0.0666667, 1, -1.49012e-08, 0, 7.63685e-08, -0.00586834, 0.0157643, 0.00645119, 0.999838, 1, 1, 1, 0.133333, 1, -1.49012e-07, 1.19209e-07, 1.21072e-07, -0.0437508, 0.117176, 0.0471372, 0.991027, 1, 1, 1, 0.2, 1, -1.04308e-07, 0, 1.86265e-09, -0.108414, 0.289036, 0.113213, 0.944398, 1, 1, 1, 0.266667, 1, -1.49012e-07, -2.98023e-08, 1.47149e-07, -0.1704, 0.450991, 0.168978, 0.859661, 1, 1, 1, 0.333333, 1, 2.98023e-08, 2.98023e-08, 3.91155e-08, -0.211609, 0.553687, 0.192556, 0.782032, 1, 1, 1, 0.4, 1, -7.45058e-08, 5.96046e-08, 1.49012e-08, -0.230545, 0.604045, 0.0585778, 0.760623, 1, 1, 1, 0.466667, 1, -5.96046e-08, 5.96046e-08, 7.26432e-08, -0.254046, 0.611523, -0.134534, 0.737158, 1, 1, 1, 0.533333, 1, -8.9407e-08, 0, 7.26432e-08, -0.3508, 0.55588, -0.0965608, 0.747404, 1, 1, 1, 0.6, 1, -7.45058e-08, 8.9407e-08, 8.56817e-08, -0.389927, 0.324616, 0.0259209, 0.861342, 1, 1, 1, 0.666667, 1, -1.49012e-08, -8.9407e-08, 8.00937e-08, -0.113728, 0.0644829, 0.00756021, 0.991388, 1, 1, 1, 0.733333, 1, -4.47035e-08, 8.9407e-08, 5.02914e-08, 2.98023e-08, -7.45058e-08, -7.45058e-09, 1, 1, 1, 1, 0.791667, 1, 2.98023e-08, 2.98023e-08, 1.02445e-07, 1.49012e-08, -2.98023e-08, -7.45058e-09, 1, 1, 1, 1 )
|
||||
tracks/2/type = "transform"
|
||||
tracks/2/path = NodePath("Armature/Skeleton:UpperArm.R")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/keys = PoolRealArray( 0, 1, -2.98023e-08, -2.98023e-08, -5.96046e-08, -1.49012e-08, 0, 0, 1, 1, 1, 1, 0.0666667, 1, 4.47035e-08, 0, -7.45058e-08, 0.011767, 0.0105079, 0.00820402, 0.999842, 1, 1, 1, 0.133333, 1, -8.9407e-08, -1.49012e-07, 4.47035e-08, 0.0859668, 0.0767673, 0.0602297, 0.991508, 1, 1, 1, 0.2, 1, 2.98023e-08, -1.19209e-07, 5.96046e-08, 0.206183, 0.184119, 0.145576, 0.949945, 1, 1, 1, 0.266667, 1, 7.45058e-08, -5.96046e-08, 7.45058e-08, 0.307592, 0.274676, 0.220059, 0.884033, 1, 1, 1, 0.333333, 1, -1.78814e-07, -1.19209e-07, 0, 0.351106, 0.313534, 0.257053, 0.844006, 1, 1, 1, 0.4, 1, 8.9407e-08, -5.96046e-08, 7.45058e-08, 0.188191, 0.208628, 0.276531, 0.919015, 1, 1, 1, 0.466667, 1, 2.98023e-08, 0, -2.98023e-08, -0.0637092, 0.0115809, 0.273677, 0.959639, 1, 1, 1, 0.533333, 1, 5.96046e-08, 0, -2.98023e-08, -0.101567, -0.0901974, 0.143595, 0.98027, 1, 1, 1, 0.6, 1, 2.98023e-08, -2.98023e-08, -2.98023e-08, -0.0373082, -0.0907643, -0.0355061, 0.99454, 1, 1, 1, 0.666667, 1, -4.47035e-08, -2.98023e-08, 7.45058e-08, -0.00362256, -0.0262561, -0.0102711, 0.999596, 1, 1, 1, 0.733333, 1, 2.98023e-08, -5.96046e-08, 2.98023e-08, -1.49012e-08, -1.49012e-08, 1.49012e-08, 1, 1, 1, 1, 0.791667, 1, -2.98023e-08, -2.98023e-08, -5.96046e-08, -1.49012e-08, 0, 0, 1, 1, 1, 1 )
|
||||
tracks/3/type = "transform"
|
||||
tracks/3/path = NodePath("Armature/Skeleton:Shoulder.R")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/keys = PoolRealArray( 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0.0666667, 1, 4.25331e-10, 2.61906e-11, 0, 0.00658544, 0.00890813, -0.000488712, 0.999939, 1, 1, 1, 0.133333, 1, 3.42889e-09, -1.28054e-10, 0, 0.0472153, 0.0638686, -0.0035038, 0.996835, 1, 1, 1, 0.2, 1, -1.0298e-09, 1.26893e-09, 0, 0.112056, 0.15158, -0.0083152, 0.982038, 1, 1, 1, 0.266667, 1, 1.60017e-08, 3.63217e-09, 1.19209e-07, 0.169552, 0.229355, -0.0125817, 0.958379, 1, 1, 1, 0.333333, 1, 1.38597e-08, -2.8136e-09, 0, 0.197783, 0.267544, -0.0146766, 0.942914, 1, 1, 1, 0.4, 1, 4.95234e-10, -3.39933e-09, 0, 0.0396571, 0.273067, 0.068117, 0.95876, 1, 1, 1, 0.466667, 1, 3.0251e-08, 7.71792e-11, 0, -0.187959, 0.251319, 0.181668, 0.931937, 1, 1, 1, 0.533333, 1, 1.833e-08, 4.54755e-09, 1.19209e-07, -0.213406, 0.19015, 0.209136, 0.935181, 1, 1, 1, 0.6, 1, 8.41146e-09, -9.31308e-11, 0, -0.0919332, 0.0630301, 0.203615, 0.972685, 1, 1, 1, 0.666667, 1, 6.40912e-09, 7.10543e-15, 1.19209e-07, -0.00230095, -0.0193147, 0.175059, 0.984366, 1, 1, 1, 0.733333, 1, -4.16577e-10, 0, 0, -0.000323432, -0.00872148, 0.0715194, 0.997401, 1, 1, 1, 0.791667, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 )
|
||||
tracks/4/type = "transform"
|
||||
tracks/4/path = NodePath("Armature/Skeleton:HandTip.L")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/keys = PoolRealArray( 0, 1, 0, 0, 3.81116e-09, -1.86265e-09, 7.45058e-09, -1.17579e-08, 1, 1, 1, 1, 0.791667, 1, 0, 0, 3.81116e-09, -1.86265e-09, 7.45058e-09, -1.17579e-08, 1, 1, 1, 1 )
|
||||
tracks/5/type = "transform"
|
||||
tracks/5/path = NodePath("Armature/Skeleton:LowerArm.L")
|
||||
tracks/5/interp = 1
|
||||
tracks/5/loop_wrap = true
|
||||
tracks/5/imported = false
|
||||
tracks/5/enabled = true
|
||||
tracks/5/keys = PoolRealArray( 0, 1, -8.9407e-08, 2.98023e-08, 1.02445e-07, -1.49012e-08, -1.49012e-08, -2.98023e-08, 1, 1, 1, 1, 0.0666667, 1, -5.96046e-08, 1.19209e-07, 9.12696e-08, -0.00935066, 2.03391e-05, 0.000315729, 0.999956, 1, 1, 1, 0.133333, 1, -1.49012e-08, 2.98023e-08, 8.56817e-08, -0.0671479, 0.000401975, 0.00227173, 0.99774, 1, 1, 1, 0.266667, 1, -5.96046e-08, 5.96046e-08, 1.00583e-07, -0.242279, 0.00547677, 0.0082618, 0.970156, 1, 1, 1, 0.333333, 1, 1.49012e-08, 5.96046e-08, 1.69501e-07, -0.280737, 0.0115882, 0.00965797, 0.959666, 1, 1, 1, 0.4, 1, -2.98023e-08, 5.96046e-08, 6.51926e-08, -0.211918, 0.0208799, 0.00983568, 0.977015, 1, 1, 1, 0.466667, 1, 2.98023e-08, 5.96046e-08, 9.12696e-08, -0.0968075, 0.0283259, 0.00989634, 0.994851, 1, 1, 1, 0.533333, 1, 5.96046e-08, 5.96046e-08, 4.47035e-08, -0.0323694, 0.0271555, 0.0090094, 0.999066, 1, 1, 1, 0.6, 1, -1.04308e-07, 2.98023e-08, 3.53903e-08, -0.00820132, 0.0156167, 0.00518115, 0.999831, 1, 1, 1, 0.666667, 1, 1.49012e-08, 0, -9.49949e-08, -0.000421983, 0.00306127, 0.00101563, 0.999995, 1, 1, 1, 0.733333, 1, -2.98023e-08, 0, 9.31323e-08, -2.98023e-08, 4.47035e-08, -4.47035e-08, 1, 1, 1, 1, 0.791667, 1, -8.9407e-08, 2.98023e-08, 1.02445e-07, -1.49012e-08, -1.49012e-08, -2.98023e-08, 1, 1, 1, 1 )
|
||||
tracks/6/type = "transform"
|
||||
tracks/6/path = NodePath("Armature/Skeleton:UpperArm.L")
|
||||
tracks/6/interp = 1
|
||||
tracks/6/loop_wrap = true
|
||||
tracks/6/imported = false
|
||||
tracks/6/enabled = true
|
||||
tracks/6/keys = PoolRealArray( 0, 1, -4.47035e-08, -2.98023e-08, 1.49012e-08, -1.49012e-08, -5.21541e-08, 1.49012e-08, 1, 1, 1, 1, 0.0666667, 1, -8.9407e-08, -8.9407e-08, -1.49012e-08, -0.00947541, -0.00323637, -0.00573202, 0.999934, 1, 1, 1, 0.133333, 1, -8.9407e-08, -8.9407e-08, -2.98023e-08, -0.0679954, -0.0232241, -0.0411327, 0.996567, 1, 1, 1, 0.2, 1, -7.45058e-08, 5.96046e-08, -5.96046e-08, -0.16145, -0.0551437, -0.0976665, 0.980487, 1, 1, 1, 0.266667, 1, -2.98023e-08, 0, -5.96046e-08, -0.244128, -0.0833825, -0.147681, 0.954798, 1, 1, 1, 0.333333, 1, 2.98023e-08, -8.9407e-08, -2.98023e-08, -0.284491, -0.0971685, -0.172098, 0.938086, 1, 1, 1, 0.4, 1, -5.96046e-08, -8.9407e-08, -2.98023e-08, -0.0658813, 0.00482479, -0.0859779, 0.994105, 1, 1, 1, 0.466667, 1, 7.45058e-08, 0, 4.47035e-08, 0.258148, 0.151193, 0.0735815, 0.95136, 1, 1, 1, 0.533333, 1, -4.47035e-08, 0, -7.45058e-08, 0.266396, 0.172662, 0.156906, 0.935201, 1, 1, 1, 0.6, 1, 2.98023e-08, -2.98023e-08, 2.98023e-08, 0.0838445, 0.112623, 0.14957, 0.978731, 1, 1, 1, 0.666667, 1, 2.98023e-08, 2.98023e-08, -2.98023e-08, 0.00431782, 0.0243932, 0.0432344, 0.998758, 1, 1, 1, 0.733333, 1, -4.47035e-08, -8.9407e-08, 1.49012e-08, -1.49012e-08, -8.19564e-08, 1.49012e-08, 1, 1, 1, 1, 0.791667, 1, -4.47035e-08, -2.98023e-08, 1.49012e-08, -1.49012e-08, -5.21541e-08, 1.49012e-08, 1, 1, 1, 1 )
|
||||
tracks/7/type = "transform"
|
||||
tracks/7/path = NodePath("Armature/Skeleton:Shoulder.L")
|
||||
tracks/7/interp = 1
|
||||
tracks/7/loop_wrap = true
|
||||
tracks/7/imported = false
|
||||
tracks/7/enabled = true
|
||||
tracks/7/keys = PoolRealArray( 0, 1, 2.97255e-31, -2.64698e-23, 0, 0, 0, 0, 1, 1, 1, 1, 0.791667, 1, 2.97255e-31, -2.64698e-23, 0, 0, 0, 0, 1, 1, 1, 1 )
|
||||
tracks/8/type = "transform"
|
||||
tracks/8/path = NodePath("Armature/Skeleton:Base")
|
||||
tracks/8/interp = 1
|
||||
tracks/8/loop_wrap = true
|
||||
tracks/8/imported = false
|
||||
tracks/8/enabled = true
|
||||
tracks/8/keys = PoolRealArray( 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0.0666667, 1, 0, 0, 0, -0.00262969, -0.00462533, -7.91099e-05, 0.999986, 1, 1, 1, 0.133333, 1, 0, 0, 0, -0.0187834, -0.0330379, -0.000768041, 0.999277, 1, 1, 1, 0.266667, 1, 0, 0, 0, -0.0678217, -0.119291, -0.00597111, 0.990522, 1, 1, 1, 0.333333, 1, 0, 0, 0, -0.0791032, -0.139134, -0.0111504, 0.987046, 1, 1, 1, 0.4, 1, 0, 0, 0, 0.00167779, -0.0294607, -0.0182862, 0.999397, 1, 1, 1, 0.466667, 1, 0, 0, 0, 0.116381, 0.127423, -0.0233002, 0.984721, 1, 1, 1, 0.533333, 1, 0, 0, 0, 0.120038, 0.144348, -0.0211955, 0.981991, 1, 1, 1, 0.6, 1, 0, 0, 0, 0.0228862, 0.060128, -0.00882898, 0.997889, 1, 1, 1, 0.666667, 1, 0, 0, 0, -0.0459424, -8.28055e-25, 1.02013e-17, 0.998944, 1, 1, 1, 0.733333, 1, 0, 0, 0, -0.00918794, -3.32825e-25, 4.08026e-18, 0.999958, 1, 1, 1, 0.791667, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 )
|
||||
|
||||
[sub_resource type="Animation" id=31]
|
||||
resource_name = "Idle-loop"
|
||||
length = 0.333333
|
||||
loop = true
|
||||
tracks/0/type = "transform"
|
||||
tracks/0/path = NodePath("Armature/Skeleton:HandTip.R")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/keys = PoolRealArray( 0, 1, -6.33299e-08, 5.96046e-08, -8.72095e-09, -4.65661e-10, -3.72529e-09, -1.80444e-09, 1, 1, 1, 1, 0.333333, 1, -6.33299e-08, 5.96046e-08, -8.72095e-09, -4.65661e-10, -3.72529e-09, -1.80444e-09, 1, 1, 1, 1 )
|
||||
tracks/1/type = "transform"
|
||||
tracks/1/path = NodePath("Armature/Skeleton:LowerArm.R")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/keys = PoolRealArray( 0, 1, 2.98023e-08, 2.98023e-08, 1.02445e-07, 1.49012e-08, -2.98023e-08, -7.45058e-09, 1, 1, 1, 1, 0.333333, 1, 2.98023e-08, 2.98023e-08, 1.02445e-07, 1.49012e-08, -2.98023e-08, -7.45058e-09, 1, 1, 1, 1 )
|
||||
tracks/2/type = "transform"
|
||||
tracks/2/path = NodePath("Armature/Skeleton:UpperArm.R")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/keys = PoolRealArray( 0, 1, -2.98023e-08, -2.98023e-08, -5.96046e-08, -1.49012e-08, 0, 0, 1, 1, 1, 1, 0.333333, 1, -2.98023e-08, -2.98023e-08, -5.96046e-08, -1.49012e-08, 0, 0, 1, 1, 1, 1 )
|
||||
tracks/3/type = "transform"
|
||||
tracks/3/path = NodePath("Armature/Skeleton:Shoulder.R")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/keys = PoolRealArray( 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0.333333, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 )
|
||||
tracks/4/type = "transform"
|
||||
tracks/4/path = NodePath("Armature/Skeleton:HandTip.L")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/keys = PoolRealArray( 0, 1, 0, 0, 3.81116e-09, -1.86265e-09, 7.45058e-09, -1.17579e-08, 1, 1, 1, 1, 0.333333, 1, 0, 0, 3.81116e-09, -1.86265e-09, 7.45058e-09, -1.17579e-08, 1, 1, 1, 1 )
|
||||
tracks/5/type = "transform"
|
||||
tracks/5/path = NodePath("Armature/Skeleton:LowerArm.L")
|
||||
tracks/5/interp = 1
|
||||
tracks/5/loop_wrap = true
|
||||
tracks/5/imported = false
|
||||
tracks/5/enabled = true
|
||||
tracks/5/keys = PoolRealArray( 0, 1, -8.9407e-08, 2.98023e-08, 1.02445e-07, -1.49012e-08, -1.49012e-08, -2.98023e-08, 1, 1, 1, 1, 0.333333, 1, -8.9407e-08, 2.98023e-08, 1.02445e-07, -1.49012e-08, -1.49012e-08, -2.98023e-08, 1, 1, 1, 1 )
|
||||
tracks/6/type = "transform"
|
||||
tracks/6/path = NodePath("Armature/Skeleton:UpperArm.L")
|
||||
tracks/6/interp = 1
|
||||
tracks/6/loop_wrap = true
|
||||
tracks/6/imported = false
|
||||
tracks/6/enabled = true
|
||||
tracks/6/keys = PoolRealArray( 0, 1, -4.47035e-08, -2.98023e-08, 1.49012e-08, -1.49012e-08, -5.21541e-08, 1.49012e-08, 1, 1, 1, 1, 0.333333, 1, -4.47035e-08, -2.98023e-08, 1.49012e-08, -1.49012e-08, -5.21541e-08, 1.49012e-08, 1, 1, 1, 1 )
|
||||
tracks/7/type = "transform"
|
||||
tracks/7/path = NodePath("Armature/Skeleton:Shoulder.L")
|
||||
tracks/7/interp = 1
|
||||
tracks/7/loop_wrap = true
|
||||
tracks/7/imported = false
|
||||
tracks/7/enabled = true
|
||||
tracks/7/keys = PoolRealArray( 0, 1, 2.97255e-31, -2.64698e-23, 0, 0, 0, 0, 1, 1, 1, 1, 0.333333, 1, 2.97255e-31, -2.64698e-23, 0, 0, 0, 0, 1, 1, 1, 1 )
|
||||
tracks/8/type = "transform"
|
||||
tracks/8/path = NodePath("Armature/Skeleton:Base")
|
||||
tracks/8/interp = 1
|
||||
tracks/8/loop_wrap = true
|
||||
tracks/8/imported = false
|
||||
tracks/8/enabled = true
|
||||
tracks/8/keys = PoolRealArray( 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0.333333, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 )
|
||||
|
||||
[sub_resource type="Animation" id=32]
|
||||
resource_name = "Interaction-loop"
|
||||
length = 1.04167
|
||||
loop = true
|
||||
tracks/0/type = "transform"
|
||||
tracks/0/path = NodePath("Armature/Skeleton:HandTip.R")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/keys = PoolRealArray( 0, 1, -3.35276e-08, 0, -1.23743e-07, -0.0397685, -0.000299317, -0.0326481, 0.998675, 1, 1, 1, 0.0666667, 1, -4.09782e-08, 5.96046e-08, -4.10418e-08, -0.0388719, -0.000223445, -0.0301956, 0.998788, 1, 1, 1, 0.2, 1, -7.45058e-08, 8.9407e-08, -7.08441e-08, -0.0304912, 0.000484843, -0.00729624, 0.999508, 1, 1, 1, 0.266667, 1, -2.23517e-08, 5.96046e-08, -4.59312e-08, -0.0351766, 0.000270068, -0.0172153, 0.999233, 1, 1, 1, 0.333333, 1, -5.96046e-08, 5.96046e-08, -2.57215e-08, -0.0444978, -0.000179588, -0.0373135, 0.998312, 1, 1, 1, 0.4, 1, -2.98023e-08, 5.96046e-08, 6.6526e-08, -0.0451622, -0.000199814, -0.0386437, 0.998232, 1, 1, 1, 0.533333, 1, -2.23517e-08, 5.96046e-08, 4.92034e-08, -0.026639, 0.000803509, 0.00223312, 0.999642, 1, 1, 1, 0.6, 1, -4.84288e-08, 5.96046e-08, 4.51055e-08, -0.0276825, 0.000774615, 0.00157664, 0.999615, 1, 1, 1, 0.666667, 1, -8.56817e-08, 8.9407e-08, 6.34526e-08, -0.0308762, 0.000653472, -0.00238591, 0.99952, 1, 1, 1, 0.733333, 1, -3.72529e-08, 5.96046e-08, 2.53151e-08, -0.0314008, 0.000622581, -0.0031118, 0.999502, 1, 1, 1, 0.866667, 1, -5.21541e-08, 5.96046e-08, -4.25319e-08, -0.0278308, 0.00065537, 0.000619829, 0.999612, 1, 1, 1, 0.933333, 1, -4.84288e-08, 0, -2.25217e-09, -0.0312516, 0.000375793, -0.0090599, 0.99947, 1, 1, 1, 1, 1, -6.33299e-08, 0, 6.67123e-08, -0.0378865, -0.000149982, -0.0274314, 0.998905, 1, 1, 1, 1.04167, 1, -3.35276e-08, 0, -1.23743e-07, -0.0397685, -0.000299317, -0.0326481, 0.998675, 1, 1, 1 )
|
||||
tracks/1/type = "transform"
|
||||
tracks/1/path = NodePath("Armature/Skeleton:LowerArm.R")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/keys = PoolRealArray( 0, 1, -8.9407e-08, -5.96046e-08, -5.02914e-08, -0.182251, -0.00221143, -0.121182, 0.975753, 1, 1, 1, 0.0666667, 1, -5.96046e-08, 5.96046e-08, -5.58794e-09, -0.178429, -0.000926142, -0.112629, 0.977485, 1, 1, 1, 0.2, 1, -1.49012e-08, 0, 3.72529e-09, -0.141964, 0.0110719, -0.0323065, 0.989282, 1, 1, 1, 0.266667, 1, -1.04308e-07, 1.49012e-07, 6.51926e-08, -0.162254, 0.00780114, -0.065411, 0.984548, 1, 1, 1, 0.333333, 1, -1.49012e-08, 8.9407e-08, 2.47732e-07, -0.201968, 0.000834197, -0.132512, 0.970386, 1, 1, 1, 0.4, 1, 0, 2.98023e-08, 9.12696e-08, -0.204438, 0.000619536, -0.136288, 0.969345, 1, 1, 1, 0.533333, 1, -5.96046e-08, -2.98023e-08, -2.04891e-08, -0.121433, 0.0170418, 0.00665036, 0.992431, 1, 1, 1, 0.6, 1, -1.49012e-08, 0, 3.35276e-08, -0.127274, 0.0164745, 0.00237392, 0.991728, 1, 1, 1, 0.666667, 1, -4.47035e-08, -2.98023e-08, 4.09782e-08, -0.143827, 0.0142825, -0.015193, 0.989383, 1, 1, 1, 0.733333, 1, -5.96046e-08, 2.98023e-08, 1.11759e-08, -0.146947, 0.0135418, -0.0191313, 0.988867, 1, 1, 1, 0.866667, 1, -7.45058e-08, -5.96046e-08, -2.42144e-08, -0.132294, 0.0134387, -0.00933063, 0.991075, 1, 1, 1, 0.933333, 1, -5.96046e-08, 8.9407e-08, 2.42144e-08, -0.146841, 0.0087808, -0.0420172, 0.988228, 1, 1, 1, 1, 1, -2.98023e-08, 8.9407e-08, 1.13621e-07, -0.174543, 0.000209678, -0.103758, 0.979168, 1, 1, 1, 1.04167, 1, -8.9407e-08, -5.96046e-08, -5.02914e-08, -0.182251, -0.00221143, -0.121182, 0.975753, 1, 1, 1 )
|
||||
tracks/2/type = "transform"
|
||||
tracks/2/path = NodePath("Armature/Skeleton:UpperArm.R")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/keys = PoolRealArray( 0, 1, 4.47035e-08, -2.98023e-08, 0, -0.257278, 0.0958797, 0.0591961, 0.959745, 1, 1, 1, 0.0666667, 1, 1.04308e-07, 5.96046e-08, -4.47035e-08, -0.252958, 0.0959003, 0.0594266, 0.960877, 1, 1, 1, 0.2, 1, 5.96046e-08, -2.98023e-08, 0, -0.212377, 0.0968744, 0.0615156, 0.970426, 1, 1, 1, 0.266667, 1, -4.47035e-08, -5.96046e-08, 4.47035e-08, -0.233182, 0.102396, 0.0611982, 0.965089, 1, 1, 1, 0.333333, 1, 7.45058e-08, -2.98023e-08, -4.47035e-08, -0.274556, 0.111221, 0.060385, 0.953206, 1, 1, 1, 0.4, 1, 4.47035e-08, -2.98023e-08, -1.49012e-08, -0.274427, 0.112329, 0.0606839, 0.953095, 1, 1, 1, 0.533333, 1, -1.49012e-08, -5.96046e-08, -7.45058e-08, -0.162406, 0.0994839, 0.0673923, 0.97938, 1, 1, 1, 0.6, 1, 5.96046e-08, 2.98023e-08, -8.9407e-08, -0.177495, 0.10122, 0.0696684, 0.97642, 1, 1, 1, 0.666667, 1, 1.04308e-07, 1.19209e-07, -1.49012e-08, -0.213174, 0.105294, 0.0704232, 0.968768, 1, 1, 1, 0.733333, 1, -2.98023e-08, -8.9407e-08, 0, -0.221933, 0.105306, 0.070184, 0.966815, 1, 1, 1, 0.8, 1, 1.78814e-07, 2.98023e-08, -1.19209e-07, -0.215222, 0.0996311, 0.068472, 0.969054, 1, 1, 1, 0.866667, 1, 4.47035e-08, 0, -4.47035e-08, -0.209579, 0.0948555, 0.065478, 0.970975, 1, 1, 1, 0.933333, 1, 1.49012e-08, 5.96046e-08, 1.49012e-08, -0.223354, 0.0949247, 0.0622329, 0.968106, 1, 1, 1, 1, 1, 4.47035e-08, 2.98023e-08, -4.47035e-08, -0.249803, 0.0956794, 0.0597299, 0.961705, 1, 1, 1, 1.04167, 1, 4.47035e-08, -2.98023e-08, 0, -0.257278, 0.0958797, 0.0591961, 0.959745, 1, 1, 1 )
|
||||
tracks/3/type = "transform"
|
||||
tracks/3/path = NodePath("Armature/Skeleton:Shoulder.R")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/keys = PoolRealArray( 0, 1, -1.05356e-08, -1.08299e-08, -1.19209e-07, -0.0304198, 0.217476, 0.165777, 0.961404, 1, 1, 1, 0.0666667, 1, -4.63332e-09, -1.65752e-09, 0, -0.0383344, 0.214758, 0.17136, 0.960752, 1, 1, 1, 0.2, 1, 3.24177e-08, 9.07121e-10, 0, -0.112003, 0.188337, 0.22262, 0.94996, 1, 1, 1, 0.266667, 1, 3.84752e-08, 2.0227e-10, 1.19209e-07, -0.0862053, 0.207715, 0.198912, 0.953864, 1, 1, 1, 0.333333, 1, 1.60653e-08, 5.66796e-09, -1.19209e-07, -0.0324234, 0.244687, 0.149931, 0.957391, 1, 1, 1, 0.4, 1, 3.37837e-08, 3.68154e-10, 0, -0.0242774, 0.246734, 0.139153, 0.958733, 1, 1, 1, 0.466667, 1, 1.92551e-08, -2.56851e-09, 0, -0.0624877, 0.207136, 0.15993, 0.963126, 1, 1, 1, 0.533333, 1, -4.49364e-09, 9.36211e-11, 0, -0.101882, 0.172775, 0.189807, 0.961115, 1, 1, 1, 0.6, 1, 2.33879e-08, -1.31112e-09, 0, -0.114725, 0.179187, 0.214338, 0.953305, 1, 1, 1, 0.666667, 1, 8.36008e-09, -5.16586e-10, 1.19209e-07, -0.118628, 0.197342, 0.233035, 0.944816, 1, 1, 1, 0.733333, 1, 8.60599e-09, -2.88125e-10, 0, -0.120042, 0.200139, 0.246325, 0.940669, 1, 1, 1, 0.8, 1, 2.80561e-09, 3.76021e-09, 0, -0.122382, 0.189051, 0.256239, 0.940013, 1, 1, 1, 0.866667, 1, -1.72062e-08, 6.89179e-09, 0, -0.12399, 0.17982, 0.260764, 0.940369, 1, 1, 1, 0.933333, 1, -6.63562e-10, 1.54396e-09, 0, -0.0967781, 0.190769, 0.233545, 0.948524, 1, 1, 1, 1, 1, 1.62981e-08, -1.06611e-08, 0, -0.0451179, 0.211756, 0.180902, 0.959374, 1, 1, 1, 1.04167, 1, -1.05356e-08, -1.10055e-08, -1.19209e-07, -0.0304198, 0.217476, 0.165777, 0.961404, 1, 1, 1 )
|
||||
tracks/4/type = "transform"
|
||||
tracks/4/path = NodePath("Armature/Skeleton:HandTip.L")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/keys = PoolRealArray( 0, 1, -4.47035e-08, 0, 4.84288e-08, -0.0259765, -0.000839302, -0.003693, 0.999655, 1, 1, 1, 0.0666667, 1, -2.23517e-08, -2.98023e-08, 5.06639e-08, -0.027443, -0.000736854, -0.000142364, 0.999623, 1, 1, 1, 0.2, 1, 5.21541e-08, 0, 3.94881e-08, -0.0411107, 0.000219808, 0.0329958, 0.99861, 1, 1, 1, 0.266667, 1, 4.47035e-08, 0, 8.38184e-09, -0.0392144, 0.000149269, 0.0294237, 0.998798, 1, 1, 1, 0.333333, 1, 1.49012e-08, 0, -1.00583e-07, -0.0347486, -4.67662e-05, 0.0205185, 0.999185, 1, 1, 1, 0.4, 1, 7.45058e-09, 5.96046e-08, 3.85568e-08, -0.0338174, -7.52744e-05, 0.0188424, 0.99925, 1, 1, 1, 0.466667, 1, -6.70552e-08, -2.98023e-08, -1.9744e-08, -0.0359106, 7.82064e-05, 0.0239558, 0.999068, 1, 1, 1, 0.6, 1, 2.98023e-08, 5.96046e-08, 1.57392e-08, -0.0426272, 0.000386088, 0.0380744, 0.998365, 1, 1, 1, 0.666667, 1, -6.70552e-08, 5.96046e-08, 7.91624e-09, -0.0449463, 0.000421882, 0.0419609, 0.998108, 1, 1, 1, 0.733333, 1, 3.72529e-08, 0, 2.37488e-08, -0.0453679, 0.000406673, 0.0422226, 0.998078, 1, 1, 1, 0.8, 1, 2.98023e-08, 5.96046e-08, 2.46684e-08, -0.0446239, 0.000279515, 0.0385421, 0.99826, 1, 1, 1, 0.866667, 1, 5.96046e-08, 1.19209e-07, 8.74277e-09, -0.0416562, -2.0318e-06, 0.0290418, 0.99871, 1, 1, 1, 1, 1, 8.9407e-08, 5.96046e-08, 4.47035e-08, -0.0277544, -0.000759324, -0.000433974, 0.999614, 1, 1, 1, 1.04167, 1, -4.47035e-08, 0, -7.45058e-09, -0.0259765, -0.000839302, -0.003693, 0.999655, 1, 1, 1 )
|
||||
tracks/5/type = "transform"
|
||||
tracks/5/path = NodePath("Armature/Skeleton:LowerArm.L")
|
||||
tracks/5/interp = 1
|
||||
tracks/5/loop_wrap = true
|
||||
tracks/5/imported = false
|
||||
tracks/5/enabled = true
|
||||
tracks/5/keys = PoolRealArray( 0, 1, -5.96046e-08, 0, -4.65661e-08, -0.118403, -0.0176198, -0.0117551, 0.99274, 1, 1, 1, 0.0666667, 1, -4.47035e-08, 2.98023e-08, 4.28408e-08, -0.125346, -0.0159979, 0.000566965, 0.991984, 1, 1, 1, 0.2, 1, -4.47035e-08, 5.96046e-08, 8.75443e-08, -0.188895, -0.000707762, 0.115526, 0.975178, 1, 1, 1, 0.266667, 1, 1.49012e-08, 1.49012e-07, 1.24797e-07, -0.180412, -0.00092285, 0.105994, 0.977863, 1, 1, 1, 0.333333, 1, 1.04308e-07, 5.96046e-08, 1.47149e-07, -0.16024, -0.00234829, 0.0804372, 0.983792, 1, 1, 1, 0.4, 1, 0, 2.98023e-08, 7.63685e-08, -0.155967, -0.00228733, 0.076109, 0.984823, 1, 1, 1, 0.466667, 1, -2.98023e-08, 2.98023e-08, 3.91155e-08, -0.165189, 7.06846e-05, 0.0933881, 0.981831, 1, 1, 1, 0.533333, 1, -1.49012e-08, 0, 3.72529e-09, -0.18027, 0.00205633, 0.118129, 0.976496, 1, 1, 1, 0.6, 1, 4.47035e-08, 8.9407e-08, 5.21541e-08, -0.195105, 0.00211556, 0.136242, 0.971271, 1, 1, 1, 0.666667, 1, -1.04308e-07, 5.96046e-08, 1.2666e-07, -0.205658, 0.00164892, 0.145659, 0.967722, 1, 1, 1, 0.733333, 1, -1.49012e-08, 0, 1.06171e-07, -0.207614, 0.000328147, 0.145968, 0.967259, 1, 1, 1, 0.8, 1, 7.45058e-08, 2.98023e-08, 2.98023e-08, -0.204855, -0.00210787, 0.13512, 0.969419, 1, 1, 1, 0.866667, 1, -4.47035e-08, 2.98023e-08, 1.13621e-07, -0.194142, -0.00615519, 0.104122, 0.975413, 1, 1, 1, 0.933333, 1, -1.49012e-08, 8.9407e-08, 4.65661e-08, -0.164634, -0.0117041, 0.0507141, 0.984981, 1, 1, 1, 1, 1, -2.98023e-08, 1.19209e-07, 7.45058e-08, -0.127867, -0.0165417, 8.73655e-06, 0.991653, 1, 1, 1, 1.04167, 1, -5.96046e-08, 0, -4.65661e-08, -0.118403, -0.0176198, -0.0117551, 0.99274, 1, 1, 1 )
|
||||
tracks/6/type = "transform"
|
||||
tracks/6/path = NodePath("Armature/Skeleton:UpperArm.L")
|
||||
tracks/6/interp = 1
|
||||
tracks/6/loop_wrap = true
|
||||
tracks/6/imported = false
|
||||
tracks/6/enabled = true
|
||||
tracks/6/keys = PoolRealArray( 0, 1, -7.45058e-08, -5.96046e-08, -7.45058e-08, -0.158361, -0.0989989, -0.0678321, 0.980061, 1, 1, 1, 0.0666667, 1, -1.49012e-08, -2.98023e-08, -1.49012e-08, -0.167793, -0.0992559, -0.0671212, 0.978513, 1, 1, 1, 0.2, 1, 4.47035e-08, -8.9407e-08, 7.45058e-08, -0.255067, -0.101213, -0.060189, 0.959726, 1, 1, 1, 0.266667, 1, 7.45058e-08, 0, 1.49012e-08, -0.249214, -0.0988195, -0.0599973, 0.961524, 1, 1, 1, 0.333333, 1, 0, -2.98023e-08, 0, -0.232425, -0.0942096, -0.0601037, 0.966173, 1, 1, 1, 0.4, 1, 1.49012e-08, -2.98023e-08, -2.98023e-08, -0.229419, -0.0929231, -0.060043, 0.96702, 1, 1, 1, 0.466667, 1, 5.96046e-08, -1.78814e-07, 2.98023e-08, -0.239933, -0.0934467, -0.0596002, 0.964442, 1, 1, 1, 0.533333, 1, -5.96046e-08, 2.98023e-08, -2.98023e-08, -0.255351, -0.0955354, -0.0592259, 0.960292, 1, 1, 1, 0.6, 1, -1.49012e-08, -5.96046e-08, 2.98023e-08, -0.267343, -0.100811, -0.0595827, 0.95646, 1, 1, 1, 0.666667, 1, 0, 1.19209e-07, -1.19209e-07, -0.274072, -0.107058, -0.0604036, 0.953821, 1, 1, 1, 0.733333, 1, 0, -1.78814e-07, 2.98023e-08, -0.275161, -0.108825, -0.0609397, 0.953273, 1, 1, 1, 0.8, 1, 8.9407e-08, 0, 0, -0.274679, -0.108954, -0.0611182, 0.953386, 1, 1, 1, 0.866667, 1, -4.47035e-08, 2.98023e-08, 1.49012e-08, -0.272769, -0.10898, -0.061592, 0.953901, 1, 1, 1, 0.933333, 1, 5.96046e-08, -5.96046e-08, 1.49012e-08, -0.238162, -0.106197, -0.0639192, 0.963284, 1, 1, 1, 1, 1, -4.47035e-08, 0, -4.47035e-08, -0.175957, -0.100647, -0.0670489, 0.976941, 1, 1, 1, 1.04167, 1, -7.45058e-08, -5.96046e-08, -7.45058e-08, -0.158361, -0.0989989, -0.0678321, 0.980061, 1, 1, 1 )
|
||||
tracks/7/type = "transform"
|
||||
tracks/7/path = NodePath("Armature/Skeleton:Shoulder.L")
|
||||
tracks/7/interp = 1
|
||||
tracks/7/loop_wrap = true
|
||||
tracks/7/imported = false
|
||||
tracks/7/enabled = true
|
||||
tracks/7/keys = PoolRealArray( 0, 1, 2.79397e-08, 1.01133e-08, -1.19209e-07, -0.105738, -0.170004, -0.193499, 0.960456, 1, 1, 1, 0.0666667, 1, 2.18279e-08, 1.09526e-09, 0, -0.0988958, -0.175343, -0.189677, 0.960988, 1, 1, 1, 0.2, 1, -3.05499e-09, -1.92449e-10, 0, -0.0346134, -0.224405, -0.153187, 0.961758, 1, 1, 1, 0.266667, 1, -1.02678e-08, -1.61381e-09, 1.19209e-07, -0.0408083, -0.217599, -0.164468, 0.961216, 1, 1, 1, 0.333333, 1, 1.15833e-08, -1.52068e-09, -1.19209e-07, -0.0566848, -0.201456, -0.18794, 0.959625, 1, 1, 1, 0.4, 1, -6.43776e-09, -4.3874e-10, 0, -0.0594242, -0.197827, -0.193253, 0.959159, 1, 1, 1, 0.466667, 1, 7.97445e-09, 2.0726e-09, 0, -0.0488153, -0.204288, -0.184498, 0.960127, 1, 1, 1, 0.533333, 1, 3.16766e-08, -7.96166e-10, 0, -0.0325078, -0.215894, -0.168064, 0.961295, 1, 1, 1, 0.6, 1, 4.29571e-09, 1.32412e-10, 0, -0.0183872, -0.228989, -0.148323, 0.961887, 1, 1, 1, 0.666667, 1, 5.67524e-09, 9.16771e-10, 1.19209e-07, -0.00943251, -0.239133, -0.132293, 0.961886, 1, 1, 1, 0.733333, 1, 6.72954e-09, 7.77073e-10, 0, -0.0118449, -0.241292, -0.13514, 0.960924, 1, 1, 1, 0.8, 1, 1.55997e-09, -4.59549e-09, 0, -0.0356173, -0.240445, -0.167061, 0.955515, 1, 1, 1, 0.866667, 1, 2.2212e-08, -8.7166e-09, 0, -0.0691231, -0.236236, -0.193717, 0.949678, 1, 1, 1, 0.933333, 1, 1.78698e-08, -1.38971e-09, 0, -0.0926686, -0.21401, -0.195148, 0.952643, 1, 1, 1, 1, 1, 1.10595e-09, 1.00945e-08, 0, -0.104118, -0.179463, -0.193885, 0.958833, 1, 1, 1, 1.04167, 1, 2.79397e-08, 1.02888e-08, -1.19209e-07, -0.105738, -0.170004, -0.193499, 0.960456, 1, 1, 1 )
|
||||
tracks/8/type = "transform"
|
||||
tracks/8/path = NodePath("Armature/Skeleton:Base")
|
||||
tracks/8/interp = 1
|
||||
tracks/8/loop_wrap = true
|
||||
tracks/8/imported = false
|
||||
tracks/8/enabled = true
|
||||
tracks/8/keys = PoolRealArray( 0, 1, 0, 0, -0.3, 0.0998068, -0.00311413, -0.0310306, 0.994518, 1, 1, 1, 0.0666667, 1, 0, 0, -0.3, 0.0978242, -0.00285651, -0.0286044, 0.994788, 1, 1, 1, 0.133333, 1, 0, 0, -0.3, 0.087763, -0.00136632, -0.0144903, 0.996035, 1, 1, 1, 0.2, 1, 0, 0, -0.3, 0.0792657, 0.000687168, 0.00526144, 0.996839, 1, 1, 1, 0.266667, 1, 0, 0, -0.3, 0.0804652, 0.00203443, 0.0188723, 0.996577, 1, 1, 1, 0.333333, 1, 0, 0, -0.3, 0.0853018, 0.00266966, 0.0259549, 0.996013, 1, 1, 1, 0.4, 1, 0, 0, -0.3, 0.091536, 0.00291421, 0.0289664, 0.995376, 1, 1, 1, 0.466667, 1, 0, 0, -0.3, 0.0969729, 0.00305717, 0.030523, 0.994814, 1, 1, 1, 0.533333, 1, 0, 0, -0.3, 0.0996245, 0.0031108, 0.0310037, 0.994537, 1, 1, 1, 0.6, 1, 0, 0, -0.3, 0.0867901, 0.00250436, 0.0249545, 0.995911, 1, 1, 1, 0.666667, 1, 0, 0, -0.3, 0.0623626, 0.00103457, 0.0103089, 0.998, 1, 1, 1, 0.733333, 1, 0, 0, -0.3, 0.0565602, -0.000527597, -0.00525721, 0.998385, 1, 1, 1, 0.8, 1, 0, 0, -0.3, 0.0637818, -0.0016911, -0.0168509, 0.99782, 1, 1, 1, 0.866667, 1, 0, 0, -0.3, 0.0759985, -0.00245039, -0.0244168, 0.996806, 1, 1, 1, 0.933333, 1, 0, 0, -0.3, 0.0886202, -0.00288556, -0.028753, 0.995646, 1, 1, 1, 1, 1, 0, 0, -0.3, 0.0979029, -0.00308691, -0.0307594, 0.994716, 1, 1, 1, 1.04167, 1, 0, 0, -0.3, 0.0998068, -0.00311413, -0.0310306, 0.994518, 1, 1, 1 )
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id=1]
|
||||
animation = "Hit-loop"
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id=2]
|
||||
animation = "Idle-loop"
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id=3]
|
||||
animation = "Interaction-loop"
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id=4]
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id=5]
|
||||
switch_mode = 2
|
||||
xfade_time = 0.2
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id=6]
|
||||
xfade_time = 0.1
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id=33]
|
||||
switch_mode = 2
|
||||
xfade_time = 0.3
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachine" id=8]
|
||||
states/Hit/node = SubResource( 1 )
|
||||
states/Hit/position = Vector2( 415, 45 )
|
||||
states/Idle/node = SubResource( 2 )
|
||||
states/Idle/position = Vector2( 149, 39 )
|
||||
states/Interaction/node = SubResource( 3 )
|
||||
states/Interaction/position = Vector2( 176, 157 )
|
||||
transitions = [ "Idle", "Hit", SubResource( 4 ), "Hit", "Idle", SubResource( 5 ), "Idle", "Interaction", SubResource( 6 ), "Interaction", "Idle", SubResource( 33 ) ]
|
||||
start_node = "Idle"
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachinePlayback" id=34]
|
||||
|
||||
[node name="Player" type="KinematicBody"]
|
||||
collision_mask = 0
|
||||
input_ray_pickable = false
|
||||
|
@ -53,7 +357,6 @@ material/0 = ExtResource( 3 )
|
|||
|
||||
[node name="WorldInfo" type="Node" parent="."]
|
||||
script = ExtResource( 5 )
|
||||
World = NodePath("../../TileWorld")
|
||||
|
||||
[node name="Navigation" type="Spatial" parent="."]
|
||||
visible = false
|
||||
|
@ -76,16 +379,9 @@ input_ray_pickable = false
|
|||
monitorable = false
|
||||
|
||||
[node name="CollisionShape" type="CollisionShape" parent="ItemPickupArea"]
|
||||
visible = false
|
||||
shape = SubResource( 23 )
|
||||
|
||||
[node name="Geometry" parent="." groups=["GameGeometry"] instance=ExtResource( 4 )]
|
||||
|
||||
[node name="ToolAttachement" parent="Geometry/Armature/Skeleton" index="5"]
|
||||
transform = Transform( 1, 8.68458e-08, -1.04308e-07, 1.74623e-07, -1, -1.30385e-07, 1.41561e-07, 1.50874e-07, -1, -0.72, 0.45, 3.28113e-08 )
|
||||
|
||||
[node name="AnimationTree" parent="Geometry" index="2"]
|
||||
parameters/playback = SubResource( 28 )
|
||||
|
||||
[node name="DebugGeometry" type="Spatial" parent="."]
|
||||
script = ExtResource( 6 )
|
||||
|
||||
|
@ -94,4 +390,35 @@ material_override = SubResource( 25 )
|
|||
cast_shadow = 0
|
||||
generate_lightmap = false
|
||||
|
||||
[editable path="Geometry"]
|
||||
[node name="ImmediateGeometry" type="ImmediateGeometry" parent="."]
|
||||
|
||||
[node name="Geometry" type="Spatial" parent="." groups=["GameGeometry"]]
|
||||
|
||||
[node name="PirateAsset" parent="Geometry" instance=ExtResource( 8 )]
|
||||
transform = Transform( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0 )
|
||||
|
||||
[node name="Skeleton" parent="Geometry/PirateAsset/Armature" index="0"]
|
||||
bones/4/bound_children = [ NodePath("ToolAttachement") ]
|
||||
|
||||
[node name="ToolAttachement" type="BoneAttachment" parent="Geometry/PirateAsset/Armature/Skeleton" index="5"]
|
||||
transform = Transform( 1, 7.13626e-08, -4.47035e-08, 1.64262e-07, -1, -1.00583e-07, 1.19209e-07, 1.18278e-07, -1, -0.72, 0.45, 1.78362e-08 )
|
||||
visible = false
|
||||
bone_name = "HandTip.R"
|
||||
|
||||
[node name="toolAxe" parent="Geometry/PirateAsset/Armature/Skeleton/ToolAttachement" instance=ExtResource( 4 )]
|
||||
transform = Transform( -6.98781e-14, 7.86805e-08, -1.2, 1.8, -7.86805e-08, -4.88782e-14, -7.86805e-08, -1.8, -5.24537e-08, 0.0240936, -0.144196, 0.560397 )
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="Geometry"]
|
||||
root_node = NodePath("../PirateAsset")
|
||||
anims/ArmatureAction = SubResource( 29 )
|
||||
anims/Hit-loop = SubResource( 30 )
|
||||
anims/Idle-loop = SubResource( 31 )
|
||||
anims/Interaction-loop = SubResource( 32 )
|
||||
|
||||
[node name="AnimationTree" type="AnimationTree" parent="Geometry"]
|
||||
tree_root = SubResource( 8 )
|
||||
anim_player = NodePath("../AnimationPlayer")
|
||||
active = true
|
||||
parameters/playback = SubResource( 34 )
|
||||
|
||||
[editable path="Geometry/PirateAsset"]
|
||||
|
|
|
@ -4,8 +4,7 @@ using Godot;
|
|||
using GodotComponentTest.components;
|
||||
using GodotComponentTest.entities;
|
||||
|
||||
public class Tree : StaticBody, IInteractionInterface
|
||||
{
|
||||
public class Tree : StaticBody, IInteractionInterface {
|
||||
[Export] public float ChopDuration = 2;
|
||||
public bool IsMouseOver;
|
||||
public InteractionComponent InteractionComponent { get; set; }
|
||||
|
@ -18,9 +17,11 @@ public class Tree : StaticBody, IInteractionInterface
|
|||
[Signal]
|
||||
public delegate void EntityClicked(Entity entity);
|
||||
|
||||
[Signal]
|
||||
public delegate void TreeChopped(Tree entity);
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_geometry = GetNode<MeshInstance>("Geometry/tree");
|
||||
Debug.Assert(_geometry != null);
|
||||
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
|
||||
|
@ -33,56 +34,44 @@ public class Tree : StaticBody, IInteractionInterface
|
|||
Connect("mouse_exited", this, nameof(OnAreaMouseExited));
|
||||
}
|
||||
|
||||
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
public override void _Process(float delta) {
|
||||
base._Process(delta);
|
||||
|
||||
if (_isBeingChopped)
|
||||
{
|
||||
if (_isBeingChopped) {
|
||||
_health = Math.Max(0, _health - delta * 100 / ChopDuration);
|
||||
}
|
||||
|
||||
if (_health == 0)
|
||||
{
|
||||
if (_health == 0) {
|
||||
InteractionComponent.EndInteraction();
|
||||
InteractionComponent.TargetEntity = null;
|
||||
QueueFree();
|
||||
GD.Print("Tree chopped!");
|
||||
EmitSignal("TreeChopped", this);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||
int shapeIndex)
|
||||
{
|
||||
if (IsMouseOver && inputEvent is InputEventMouseButton)
|
||||
{
|
||||
int shapeIndex) {
|
||||
if (IsMouseOver && inputEvent is InputEventMouseButton) {
|
||||
InputEventMouseButton mouseButtonEvent = (InputEventMouseButton)inputEvent;
|
||||
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed)
|
||||
{
|
||||
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed) {
|
||||
EmitSignal("EntityClicked", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnAreaMouseEntered()
|
||||
{
|
||||
public void OnAreaMouseEntered() {
|
||||
IsMouseOver = true;
|
||||
SpatialMaterial overrideMaterial = new SpatialMaterial();
|
||||
SpatialMaterial overrideMaterial = new();
|
||||
overrideMaterial.AlbedoColor = new Color(1, 0, 0);
|
||||
_geometry.MaterialOverride = overrideMaterial;
|
||||
}
|
||||
|
||||
|
||||
public void OnAreaMouseExited()
|
||||
{
|
||||
public void OnAreaMouseExited() {
|
||||
IsMouseOver = false;
|
||||
_geometry.MaterialOverride = null;
|
||||
}
|
||||
|
||||
|
||||
public void OnInteractionStart()
|
||||
{
|
||||
public void OnInteractionStart() {
|
||||
GD.Print("Starting tree animationplayer");
|
||||
_animationPlayer.CurrentAnimation = "TreeShake";
|
||||
_animationPlayer.Seek(0);
|
||||
|
@ -90,11 +79,10 @@ public class Tree : StaticBody, IInteractionInterface
|
|||
_isBeingChopped = true;
|
||||
}
|
||||
|
||||
public void OnInteractionEnd()
|
||||
{
|
||||
public void OnInteractionEnd() {
|
||||
_animationPlayer.CurrentAnimation = "Idle";
|
||||
_animationPlayer.Seek(0);
|
||||
_animationPlayer.Stop();
|
||||
_isBeingChopped = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -88,6 +88,7 @@ script = ExtResource( 3 )
|
|||
|
||||
[node name="MountPoint" type="Spatial" parent="."]
|
||||
transform = Transform( -0.524001, 0, -0.851718, 0, 1, 0, 0.851718, 0, -0.524001, 0.717306, 0, 0.400936 )
|
||||
visible = false
|
||||
|
||||
[node name="Arrow" type="Spatial" parent="MountPoint"]
|
||||
transform = Transform( -1, 0, -8.74227e-08, 0, 1, 0, 8.74227e-08, 0, -1, 2.38419e-07, 0, 0 )
|
||||
|
|
|
@ -30,7 +30,7 @@ keystore/release="/home/martin/projects/GodotComponentTest/android/keystore/debu
|
|||
keystore/release_user="androiddebugkey"
|
||||
keystore/release_password="android"
|
||||
one_click_deploy/clear_previous_install=true
|
||||
version/code=1
|
||||
version/code=5
|
||||
version/name="1.0"
|
||||
package/unique_name="org.godotengine.$genname"
|
||||
package/name=""
|
||||
|
|
|
@ -134,5 +134,9 @@ common/enable_pause_aware_picking=true
|
|||
|
||||
quality/directional_shadow/size.mobile=512
|
||||
quality/shadow_atlas/size.mobile=1024
|
||||
quality/shadow_atlas/quadrant_0_subdiv=0
|
||||
quality/shadow_atlas/quadrant_1_subdiv=0
|
||||
quality/shadow_atlas/quadrant_2_subdiv=0
|
||||
quality/shadow_atlas/quadrant_3_subdiv=0
|
||||
quality/subsurface_scattering/quality=0
|
||||
environment/default_environment="res://default_env.tres"
|
||||
|
|
171
scenes/Game.cs
171
scenes/Game.cs
|
@ -1,8 +1,7 @@
|
|||
using System.Diagnostics;
|
||||
using Godot;
|
||||
|
||||
public class Game : Spatial
|
||||
{
|
||||
public class Game : Spatial {
|
||||
private ImageTexture _blackWhitePatternTexture;
|
||||
private Camera _camera;
|
||||
private Vector3 _cameraOffset;
|
||||
|
@ -13,57 +12,45 @@ public class Game : Spatial
|
|||
// ui elements
|
||||
private Label _framesPerSecondLabel;
|
||||
private Control _gameUi;
|
||||
private Button _generateWorldButton;
|
||||
private Label _goldCountLabel;
|
||||
private TextureRect _heightTextureRect;
|
||||
|
||||
// other members
|
||||
private HexGrid _hexGrid;
|
||||
private InteractionSystem _interactionSystem;
|
||||
private HexCell _lastTile;
|
||||
private Label _mouseTileCubeLabel;
|
||||
private Label _mouseTileAxialLabel;
|
||||
private Spatial _mouseTileHighlight;
|
||||
private Label _mouseTileOffsetLabel;
|
||||
private Label _mouseWorldLabel;
|
||||
private Label _numCoordsAddedLabel;
|
||||
private Label _numCoordsRemovedLabel;
|
||||
private Label _numTilesLabel;
|
||||
private Player _player;
|
||||
|
||||
// scene nodes
|
||||
private Spatial _tileHighlight;
|
||||
|
||||
// Resources
|
||||
private PackedScene _tileHighlightScene;
|
||||
private TileInstanceManager _tileInstanceManager;
|
||||
private ShaderMaterial _tileMaterial;
|
||||
private Label _tileOffsetLabel;
|
||||
private World _world;
|
||||
private TextureRect _worldTextureRect;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
// debugStatsContainer
|
||||
var debugStatsContainer = (Container)FindNode("DebugStatsContainer");
|
||||
Container debugStatsContainer = (Container)FindNode("DebugStatsContainer");
|
||||
|
||||
_framesPerSecondLabel = debugStatsContainer.GetNode<Label>("fps_label");
|
||||
_centerLabel = debugStatsContainer.GetNode<Label>("center_label");
|
||||
_tileOffsetLabel = debugStatsContainer.GetNode<Label>("tile_offset_label");
|
||||
_numTilesLabel = debugStatsContainer.GetNode<Label>("num_tiles_label");
|
||||
_mouseWorldLabel = debugStatsContainer.GetNode<Label>("mouse_world_label");
|
||||
_mouseTileOffsetLabel = debugStatsContainer.GetNode<Label>("mouse_tile_offset_label");
|
||||
_mouseTileCubeLabel = debugStatsContainer.GetNode<Label>("mouse_tile_cube_label");
|
||||
_mouseTileAxialLabel = debugStatsContainer.GetNode<Label>("mouse_tile_axial_label");
|
||||
_numCoordsAddedLabel = debugStatsContainer.GetNode<Label>("num_coords_added_label");
|
||||
_numCoordsRemovedLabel = debugStatsContainer.GetNode<Label>("num_coords_removed_label");
|
||||
|
||||
// UI elements
|
||||
var worldGeneratorContainer = (Container)FindNode("WorldGeneratorContainer");
|
||||
_worldTextureRect = worldGeneratorContainer.GetNode<TextureRect>("WorldTextureRect");
|
||||
_heightTextureRect = worldGeneratorContainer.GetNode<TextureRect>("HeightTextureRect");
|
||||
_generateWorldButton = worldGeneratorContainer.GetNode<Button>("WorldGenerateButton");
|
||||
Container worldGeneratorWidget = (Container)FindNode("WorldGeneratorWidget");
|
||||
_worldTextureRect = worldGeneratorWidget.GetNode<TextureRect>("WorldTextureRect");
|
||||
_heightTextureRect = worldGeneratorWidget.GetNode<TextureRect>("HeightTextureRect");
|
||||
_gameUi = (Control)FindNode("GameUI");
|
||||
_goldCountLabel = _gameUi.GetNode<Label>("GoldCount");
|
||||
Debug.Assert(_goldCountLabel != null);
|
||||
|
@ -77,75 +64,88 @@ public class Game : Spatial
|
|||
_cameraOffset = _camera.GlobalTranslation - _player.GlobalTranslation;
|
||||
|
||||
_world = (World)FindNode("World");
|
||||
_tileInstanceManager = (TileInstanceManager)FindNode("TileInstanceManager");
|
||||
|
||||
// populate UI values
|
||||
var generatorWorldSizeSlider = worldGeneratorContainer.GetNode<Slider>("HBoxContainer/WorldSizeSlider");
|
||||
|
||||
// resources
|
||||
_tileHighlightScene = GD.Load<PackedScene>("utils/TileHighlight.tscn");
|
||||
_tileMaterial = GD.Load<ShaderMaterial>("materials/HexTileTextureLookup.tres");
|
||||
Debug.Assert(_tileMaterial != null);
|
||||
|
||||
_blackWhitePatternTexture = new ImageTexture();
|
||||
var image = new Image();
|
||||
Image image = new();
|
||||
image.Load("assets/4x4checker.png");
|
||||
_blackWhitePatternTexture.CreateFromImage(image, (uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
|
||||
// other members
|
||||
_lastTile = new HexCell();
|
||||
_currentTile = new HexCell();
|
||||
_hexGrid = new HexGrid();
|
||||
_interactionSystem = GetNode<InteractionSystem>("InteractionSystem");
|
||||
Debug.Assert(_interactionSystem != null);
|
||||
|
||||
// connect signals
|
||||
_generateWorldButton.Connect("pressed", this, nameof(OnGenerateButton));
|
||||
_player.TaskQueueComponent.Connect("StartInteraction", _interactionSystem,
|
||||
nameof(_interactionSystem.OnStartInteraction));
|
||||
_player.Connect("GoldCountChanged", this, nameof(OnGoldCountChanged));
|
||||
_tileInstanceManager.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
_tileInstanceManager.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
_world.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
_world.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
_world.Connect("OnWorldViewTileTypeImageChanged", this, nameof(OnWorldViewTileTypeImageChanged));
|
||||
_world.Connect("OnHeightmapImageChanged", this, nameof(OnHeightmapImageChanged));
|
||||
|
||||
// register entity events
|
||||
foreach (Node node in GetNode("Entities").GetChildren())
|
||||
if (node.HasSignal("EntityClicked"))
|
||||
foreach (Node node in GetNode("Entities").GetChildren()) {
|
||||
if (node.HasSignal("EntityClicked")) {
|
||||
node.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
||||
}
|
||||
}
|
||||
|
||||
_world.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
||||
|
||||
// perform dependency injection
|
||||
//_streamContainer.SetWorld(_tileWorld);Clicked
|
||||
var worldInfoComponent = _player.GetNode<WorldInfoComponent>("WorldInfo");
|
||||
WorldInfoComponent worldInfoComponent = _player.GetNode<WorldInfoComponent>("WorldInfo");
|
||||
|
||||
UpdateCurrentTile();
|
||||
|
||||
StartNewGame(123, 12);
|
||||
}
|
||||
|
||||
|
||||
public override void _Input(InputEvent inputEvent)
|
||||
{
|
||||
if (inputEvent.IsAction("Forward")) GD.Print("Forward");
|
||||
public override void _Input(InputEvent inputEvent) {
|
||||
if (inputEvent.IsAction("Forward")) {
|
||||
GD.Print("Forward");
|
||||
}
|
||||
|
||||
if (inputEvent.IsAction("Back")) GD.Print("Back");
|
||||
if (inputEvent.IsAction("Back")) {
|
||||
GD.Print("Back");
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateCurrentTile()
|
||||
{
|
||||
public void StartNewGame(int seed, int chunkSize) {
|
||||
_world.Seed = seed;
|
||||
_world.ChunkSize = chunkSize;
|
||||
_world.InitNoiseGenerator();
|
||||
|
||||
ResetGame();
|
||||
|
||||
_world.UpdateCenterChunkFromPlaneCoord(Vector2.Zero);
|
||||
}
|
||||
|
||||
public void ResetGame() {
|
||||
_player.GlobalTranslation = Vector3.Zero;
|
||||
_player.PlaneAngle = -Mathf.Pi * 0.5f;
|
||||
|
||||
_world.Reset();
|
||||
}
|
||||
|
||||
public void UpdateCurrentTile() {
|
||||
// cast a ray from the camera to center
|
||||
var cameraNormal = _camera.ProjectRayNormal(_camera.GetViewport().Size * 0.5f);
|
||||
var cameraPosition = _camera.ProjectRayOrigin(_camera.GetViewport().Size * 0.5f);
|
||||
var cameraDir = cameraNormal - cameraPosition;
|
||||
Vector3 cameraNormal = _camera.ProjectRayNormal(_camera.GetViewport().Size * 0.5f);
|
||||
Vector3 cameraPosition = _camera.ProjectRayOrigin(_camera.GetViewport().Size * 0.5f);
|
||||
Vector3 cameraDir = cameraNormal - cameraPosition;
|
||||
|
||||
Vector3 centerCoord;
|
||||
|
||||
if (Mathf.Abs(cameraDir.y) > Globals.EpsPosition)
|
||||
{
|
||||
if (Mathf.Abs(cameraDir.y) > Globals.EpsPosition) {
|
||||
centerCoord = cameraPosition + cameraNormal * (-cameraPosition.y / cameraNormal.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
centerCoord = _camera.GlobalTranslation;
|
||||
centerCoord.y = 0;
|
||||
}
|
||||
|
@ -159,38 +159,26 @@ public class Game : Spatial
|
|||
}
|
||||
|
||||
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
public override void _Process(float delta) {
|
||||
_framesPerSecondLabel.Text = Engine.GetFramesPerSecond().ToString();
|
||||
_lastTile = _currentTile;
|
||||
|
||||
UpdateCurrentTile();
|
||||
|
||||
var tileHighlightTransform = Transform.Identity;
|
||||
var currentTileCenter = _hexGrid.GetHexCenter(_currentTile);
|
||||
Transform tileHighlightTransform = Transform.Identity;
|
||||
Vector2 currentTileCenter = _hexGrid.GetHexCenter(_currentTile);
|
||||
tileHighlightTransform.origin.x = currentTileCenter.x;
|
||||
tileHighlightTransform.origin.z = currentTileCenter.y;
|
||||
_tileHighlight.Transform = tileHighlightTransform;
|
||||
|
||||
var cameraTransform = _camera.Transform;
|
||||
Transform cameraTransform = _camera.Transform;
|
||||
cameraTransform.origin = _player.GlobalTranslation + _cameraOffset;
|
||||
_camera.Transform = cameraTransform;
|
||||
}
|
||||
|
||||
|
||||
public void OnGenerateButton()
|
||||
{
|
||||
GD.Print("Generating");
|
||||
var worldSizeSlider = (Slider)FindNode("WorldSizeSlider");
|
||||
if (worldSizeSlider == null) GD.PrintErr("Could not find WorldSizeSlider!");
|
||||
}
|
||||
|
||||
|
||||
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||
int shapeIndex)
|
||||
{
|
||||
var cellAtCursor = _hexGrid.GetHexAt(new Vector2(position.x, position.z));
|
||||
var highlightTransform = Transform.Identity;
|
||||
int shapeIndex) {
|
||||
HexCell cellAtCursor = _hexGrid.GetHexAt(new Vector2(position.x, position.z));
|
||||
Transform highlightTransform = Transform.Identity;
|
||||
|
||||
_mouseWorldLabel.Text = position.ToString("F3");
|
||||
_mouseTileOffsetLabel.Text = cellAtCursor.OffsetCoords.ToString("N");
|
||||
|
@ -200,20 +188,22 @@ public class Game : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void OnTileClicked(HexTile3D tile)
|
||||
{
|
||||
if (_player == null) return;
|
||||
public void OnTileClicked(HexTile3D tile) {
|
||||
if (_player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player.InteractionComponent != null) _player.InteractionComponent.EmitSignal("InteractionEnd");
|
||||
if (_player.InteractionComponent != null) {
|
||||
_player.InteractionComponent.EmitSignal("InteractionEnd");
|
||||
}
|
||||
|
||||
_player.TaskQueueComponent.Reset();
|
||||
_player.TaskQueueComponent.Queue.Enqueue(new TaskQueueComponent.NavigationTask(
|
||||
new NavigationPoint(tile.GlobalTranslation)));
|
||||
}
|
||||
|
||||
public void OnTileHovered(HexTile3D tile)
|
||||
{
|
||||
var highlightTransform = tile.GlobalTransform;
|
||||
public void OnTileHovered(HexTile3D tile) {
|
||||
Transform highlightTransform = tile.GlobalTransform;
|
||||
_mouseTileHighlight.Transform = highlightTransform;
|
||||
_mouseWorldLabel.Text = highlightTransform.origin.ToString("F3");
|
||||
_mouseTileOffsetLabel.Text = tile.OffsetCoords.ToString("N");
|
||||
|
@ -222,13 +212,11 @@ public class Game : Spatial
|
|||
_player.NavigationComponent.FindPath(_player, _player.GlobalTranslation, tile.GlobalTranslation);
|
||||
}
|
||||
|
||||
public void OnEntityClicked(Entity entity)
|
||||
{
|
||||
public void OnEntityClicked(Entity entity) {
|
||||
GD.Print("Clicked on entity at " + entity.GlobalTranslation);
|
||||
|
||||
var mountPoint = (Spatial)entity.FindNode("MountPoint");
|
||||
if (mountPoint != null)
|
||||
{
|
||||
Spatial mountPoint = (Spatial)entity.FindNode("MountPoint");
|
||||
if (mountPoint != null) {
|
||||
_player.TaskQueueComponent.Reset();
|
||||
_player.TaskQueueComponent.Queue.Enqueue(new TaskQueueComponent.NavigationTask(
|
||||
new NavigationPoint(mountPoint.GlobalTransform)));
|
||||
|
@ -237,9 +225,8 @@ public class Game : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void ResetGameState()
|
||||
{
|
||||
var playerStartTransform = Transform.Identity;
|
||||
public void ResetGameState() {
|
||||
Transform playerStartTransform = Transform.Identity;
|
||||
playerStartTransform.origin.y = 0;
|
||||
_player.Transform = playerStartTransform;
|
||||
_player.TaskQueueComponent.Reset();
|
||||
|
@ -248,28 +235,25 @@ public class Game : Spatial
|
|||
|
||||
_goldCountLabel.Text = "0";
|
||||
|
||||
foreach (Spatial entity in GetNode("Entities").GetChildren())
|
||||
{
|
||||
var entityTransform = entity.Transform;
|
||||
var entityPlanePos = new Vector2(entityTransform.origin.x, entityTransform.origin.z);
|
||||
var entityOffsetCoordinates = _hexGrid.GetHexAt(entityPlanePos).OffsetCoords;
|
||||
foreach (Spatial entity in GetNode("Entities").GetChildren()) {
|
||||
Transform entityTransform = entity.Transform;
|
||||
Vector2 entityPlanePos = new(entityTransform.origin.x, entityTransform.origin.z);
|
||||
Vector2 entityOffsetCoordinates = _hexGrid.GetHexAt(entityPlanePos).OffsetCoords;
|
||||
entityTransform.origin.y = 0;
|
||||
entity.Transform = entityTransform;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHeightmapImageChanged(Image heightmapImage)
|
||||
{
|
||||
var newHeightmapTexture = new ImageTexture();
|
||||
private void OnHeightmapImageChanged(Image heightmapImage) {
|
||||
ImageTexture newHeightmapTexture = new();
|
||||
newHeightmapTexture.CreateFromImage(heightmapImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
|
||||
_heightTextureRect.Texture = newHeightmapTexture;
|
||||
}
|
||||
|
||||
private void OnWorldViewTileTypeImageChanged(Image viewTileTypeImage)
|
||||
{
|
||||
var newWorldTexture = new ImageTexture();
|
||||
private void OnWorldViewTileTypeImageChanged(Image viewTileTypeImage) {
|
||||
ImageTexture newWorldTexture = new();
|
||||
newWorldTexture.CreateFromImage(viewTileTypeImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
|
||||
|
@ -281,9 +265,8 @@ public class Game : Spatial
|
|||
_tileMaterial.SetShaderParam("CoordinateOffsetV", (int)_world.WorldTextureCoordinateOffset.y);
|
||||
}
|
||||
|
||||
public void OnGoldCountChanged(int goldCount)
|
||||
{
|
||||
var animationPlayer = _gameUi.GetNode<AnimationPlayer>("AnimationPlayer");
|
||||
public void OnGoldCountChanged(int goldCount) {
|
||||
AnimationPlayer animationPlayer = _gameUi.GetNode<AnimationPlayer>("AnimationPlayer");
|
||||
_goldCountLabel.Text = goldCount.ToString();
|
||||
animationPlayer.CurrentAnimation = "FlashLabel";
|
||||
animationPlayer.Seek(0);
|
||||
|
|
102
scenes/Game.tscn
102
scenes/Game.tscn
|
@ -1,23 +1,16 @@
|
|||
[gd_scene load_steps=22 format=2]
|
||||
[gd_scene load_steps=14 format=2]
|
||||
|
||||
[ext_resource path="res://ui/WorldGeneratorWidget.gd" type="Script" id=1]
|
||||
[ext_resource path="res://entities/Player.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://scenes/Camera.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://ui/EditorUI.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://utils/TileHighlight.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://ui/DebugStatsContainer.gd" type="Script" id=6]
|
||||
[ext_resource path="res://scenes/World.cs" type="Script" id=7]
|
||||
[ext_resource path="res://scenes/World.tscn" type="PackedScene" id=7]
|
||||
[ext_resource path="res://scenes/Game.cs" type="Script" id=9]
|
||||
[ext_resource path="res://scenes/TileInstanceManager.cs" type="Script" id=10]
|
||||
[ext_resource path="res://entities/Chest.tscn" type="PackedScene" id=11]
|
||||
[ext_resource path="res://ui/WorldGeneratorUI.gd" type="Script" id=12]
|
||||
[ext_resource path="res://assets/Environment/HexTileMesh.tres" type="CylinderMesh" id=13]
|
||||
[ext_resource path="res://entities/Axe.tscn" type="PackedScene" id=14]
|
||||
[ext_resource path="res://systems/InteractionSystem.cs" type="Script" id=15]
|
||||
[ext_resource path="res://entities/rockA.tscn" type="PackedScene" id=16]
|
||||
[ext_resource path="res://entities/rockC.tscn" type="PackedScene" id=17]
|
||||
[ext_resource path="res://entities/rockB.tscn" type="PackedScene" id=18]
|
||||
[ext_resource path="res://entities/Tree.tscn" type="PackedScene" id=19]
|
||||
[ext_resource path="res://assets/Environment/grassLarge.tscn" type="PackedScene" id=20]
|
||||
|
||||
[sub_resource type="Animation" id=25]
|
||||
resource_name = "FlashLabel"
|
||||
|
@ -37,13 +30,6 @@ tracks/0/keys = {
|
|||
|
||||
[sub_resource type="AnimationNodeStateMachinePlayback" id=26]
|
||||
|
||||
[sub_resource type="MultiMesh" id=27]
|
||||
color_format = 1
|
||||
transform_format = 1
|
||||
custom_data_format = 1
|
||||
visible_instance_count = 0
|
||||
mesh = ExtResource( 13 )
|
||||
|
||||
[node name="Game" type="Spatial"]
|
||||
script = ExtResource( 9 )
|
||||
|
||||
|
@ -87,8 +73,8 @@ anchor_left = 1.0
|
|||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -141.0
|
||||
margin_top = -172.0
|
||||
margin_left = -67.0
|
||||
margin_top = -34.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
mouse_filter = 2
|
||||
|
@ -98,8 +84,8 @@ size_flags_vertical = 3
|
|||
[node name="DebugStatsContainer" type="GridContainer" parent="DebugContainer"]
|
||||
margin_left = 7.0
|
||||
margin_top = 7.0
|
||||
margin_right = 134.0
|
||||
margin_bottom = 165.0
|
||||
margin_right = 60.0
|
||||
margin_bottom = 27.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
mouse_filter = 2
|
||||
|
@ -296,18 +282,19 @@ margin_right = 40.0
|
|||
margin_bottom = 40.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="WorldGeneratorContainer" type="VBoxContainer" parent="Generator Container"]
|
||||
[node name="WorldGeneratorWidget" type="VBoxContainer" parent="Generator Container"]
|
||||
margin_left = 10.0
|
||||
margin_top = 10.0
|
||||
margin_right = 145.0
|
||||
margin_bottom = 94.0
|
||||
script = ExtResource( 12 )
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Generator Container/WorldGeneratorContainer"]
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Generator Container/WorldGeneratorWidget"]
|
||||
visible = false
|
||||
margin_right = 135.0
|
||||
margin_bottom = 16.0
|
||||
|
||||
[node name="WorldSizeSlider" type="HSlider" parent="Generator Container/WorldGeneratorContainer/HBoxContainer"]
|
||||
[node name="WorldSizeSlider" type="HSlider" parent="Generator Container/WorldGeneratorWidget/HBoxContainer"]
|
||||
margin_right = 123.0
|
||||
margin_bottom = 16.0
|
||||
size_flags_horizontal = 3
|
||||
|
@ -315,26 +302,25 @@ min_value = 1.0
|
|||
max_value = 256.0
|
||||
value = 1.0
|
||||
|
||||
[node name="WorldSizeLabel" type="Label" parent="Generator Container/WorldGeneratorContainer/HBoxContainer"]
|
||||
[node name="WorldSizeLabel" type="Label" parent="Generator Container/WorldGeneratorWidget/HBoxContainer"]
|
||||
margin_left = 127.0
|
||||
margin_top = 1.0
|
||||
margin_right = 135.0
|
||||
margin_bottom = 15.0
|
||||
text = "4"
|
||||
|
||||
[node name="WorldGenerateButton" type="Button" parent="Generator Container/WorldGeneratorContainer"]
|
||||
margin_top = 20.0
|
||||
[node name="WorldGenerateButton" type="Button" parent="Generator Container/WorldGeneratorWidget"]
|
||||
visible = false
|
||||
margin_right = 135.0
|
||||
margin_bottom = 40.0
|
||||
margin_bottom = 20.0
|
||||
text = "Generate"
|
||||
|
||||
[node name="ShowTexturesCheckButton" type="CheckButton" parent="Generator Container/WorldGeneratorContainer"]
|
||||
margin_top = 44.0
|
||||
[node name="ShowTexturesCheckButton" type="CheckButton" parent="Generator Container/WorldGeneratorWidget"]
|
||||
margin_right = 135.0
|
||||
margin_bottom = 84.0
|
||||
margin_bottom = 40.0
|
||||
text = "Textures"
|
||||
|
||||
[node name="WorldTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorContainer"]
|
||||
[node name="WorldTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorWidget"]
|
||||
visible = false
|
||||
margin_top = 88.0
|
||||
margin_right = 135.0
|
||||
|
@ -344,7 +330,7 @@ expand = true
|
|||
stretch_mode = 5
|
||||
flip_v = true
|
||||
|
||||
[node name="HeightTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorContainer"]
|
||||
[node name="HeightTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorWidget"]
|
||||
visible = false
|
||||
margin_top = 88.0
|
||||
margin_right = 135.0
|
||||
|
@ -358,6 +344,7 @@ flip_v = true
|
|||
visible = false
|
||||
|
||||
[node name="Camera" parent="." instance=ExtResource( 3 )]
|
||||
transform = Transform( 1, 0, 0, 0, 0.60042, 0.799685, 0, -0.799685, 0.60042, -4.76837e-07, 5.16505, 3.1696 )
|
||||
|
||||
[node name="InteractionSystem" type="Node" parent="."]
|
||||
script = ExtResource( 15 )
|
||||
|
@ -370,55 +357,22 @@ WorldNode = NodePath("../World")
|
|||
[node name="WorldInfo" parent="Player" index="2"]
|
||||
WorldPath = NodePath("../../World")
|
||||
|
||||
[node name="ToolAttachement" parent="Player/Geometry/Armature/Skeleton" index="5"]
|
||||
transform = Transform( 1, 8.68458e-08, -1.04308e-07, 1.74623e-07, -1, -1.30385e-07, 1.41561e-07, 1.50874e-07, -1, -0.72, 0.45, 3.28113e-08 )
|
||||
[node name="ToolAttachement" parent="Player/Geometry/PirateAsset/Armature/Skeleton" index="5"]
|
||||
transform = Transform( 1, 7.13626e-08, -4.47035e-08, 1.64262e-07, -1, -1.00583e-07, 1.19209e-07, 1.18278e-07, -1, -0.72, 0.45, 1.78362e-08 )
|
||||
|
||||
[node name="AnimationTree" parent="Player/Geometry" index="2"]
|
||||
parameters/playback = SubResource( 26 )
|
||||
|
||||
[node name="Entities" type="Spatial" parent="."]
|
||||
visible = false
|
||||
|
||||
[node name="Axe" parent="Entities" instance=ExtResource( 14 )]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.79762, 0, 0 )
|
||||
input_ray_pickable = false
|
||||
|
||||
[node name="Chest" parent="Entities" instance=ExtResource( 11 )]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -3.27709, 0, 1.02593 )
|
||||
transform = Transform( -0.825665, 0, 0.56416, 0, 1, 0, -0.56416, 0, -0.825665, -3.27709, 0, 1.02593 )
|
||||
|
||||
[node name="World" type="Spatial" parent="."]
|
||||
script = ExtResource( 7 )
|
||||
|
||||
[node name="Chunks" type="Spatial" parent="World"]
|
||||
|
||||
[node name="TileInstanceManager" type="Spatial" parent="World"]
|
||||
script = ExtResource( 10 )
|
||||
ShowHexTiles = true
|
||||
World = NodePath("..")
|
||||
|
||||
[node name="TileMultiMeshInstance" type="MultiMeshInstance" parent="World/TileInstanceManager"]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -2.5, 0 )
|
||||
multimesh = SubResource( 27 )
|
||||
|
||||
[node name="Assets" type="Spatial" parent="World"]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -5, 0 )
|
||||
visible = false
|
||||
|
||||
[node name="Rocks" type="Spatial" parent="World/Assets"]
|
||||
|
||||
[node name="rockA" parent="World/Assets/Rocks" instance=ExtResource( 16 )]
|
||||
|
||||
[node name="rockB" parent="World/Assets/Rocks" instance=ExtResource( 18 )]
|
||||
|
||||
[node name="rockC" parent="World/Assets/Rocks" instance=ExtResource( 17 )]
|
||||
|
||||
[node name="Grass" type="Spatial" parent="World/Assets"]
|
||||
|
||||
[node name="grassLarge" parent="World/Assets/Grass" instance=ExtResource( 20 )]
|
||||
|
||||
[node name="Trees" type="Spatial" parent="World/Assets"]
|
||||
|
||||
[node name="tree" parent="World/Assets/Trees" instance=ExtResource( 19 )]
|
||||
[node name="World" parent="." instance=ExtResource( 7 )]
|
||||
|
||||
[node name="DirectionalLight" type="DirectionalLight" parent="."]
|
||||
transform = Transform( 0.328059, -0.878387, 0.347583, 0, 0.367946, 0.929847, -0.944657, -0.305045, 0.120708, 0, 6.59293, 1.20265 )
|
||||
|
@ -426,8 +380,8 @@ shadow_enabled = true
|
|||
directional_shadow_mode = 0
|
||||
|
||||
[connection signal="toggled" from="DebugContainer/DebugStatsContainer/DebugMenuButton" to="DebugContainer/DebugStatsContainer" method="_on_DebugMenuButton_toggled"]
|
||||
[connection signal="value_changed" from="Generator Container/WorldGeneratorContainer/HBoxContainer/WorldSizeSlider" to="Generator Container/WorldGeneratorContainer" method="_on_HSlider_value_changed"]
|
||||
[connection signal="toggled" from="Generator Container/WorldGeneratorContainer/ShowTexturesCheckButton" to="Generator Container/WorldGeneratorContainer" method="_on_ShowTexturesCheckButton_toggled"]
|
||||
[connection signal="value_changed" from="Generator Container/WorldGeneratorWidget/HBoxContainer/WorldSizeSlider" to="Generator Container/WorldGeneratorWidget" method="_on_HSlider_value_changed"]
|
||||
[connection signal="toggled" from="Generator Container/WorldGeneratorWidget/ShowTexturesCheckButton" to="Generator Container/WorldGeneratorWidget" method="_on_ShowTexturesCheckButton_toggled"]
|
||||
|
||||
[editable path="Player"]
|
||||
[editable path="Player/Geometry"]
|
||||
[editable path="Player/Geometry/PirateAsset"]
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
using System.Diagnostics;
|
||||
using Godot;
|
||||
|
||||
public class HexTile3D : Spatial
|
||||
{
|
||||
public enum TileType
|
||||
{
|
||||
public class HexTile3D : Spatial {
|
||||
public enum TileType {
|
||||
Undefined,
|
||||
Sand,
|
||||
Grass,
|
||||
DeepGrass
|
||||
}
|
||||
|
||||
static public TileType[] ValidTileTypes = { TileType.Sand, TileType.Grass, TileType.DeepGrass };
|
||||
public static TileType[] ValidTileTypes = { TileType.Sand, TileType.Grass, TileType.DeepGrass };
|
||||
|
||||
// scene nodes
|
||||
private MeshInstance _mesh;
|
||||
|
@ -19,26 +17,24 @@ public class HexTile3D : Spatial
|
|||
|
||||
// signals
|
||||
[Signal]
|
||||
delegate void TileClicked(HexTile3D tile3d);
|
||||
private delegate void TileClicked(HexTile3D tile3d);
|
||||
|
||||
[Signal]
|
||||
delegate void TileHovered(HexTile3D tile3d);
|
||||
private delegate void TileHovered(HexTile3D tile3d);
|
||||
|
||||
// other member variables
|
||||
private SpatialMaterial _previousMaterial;
|
||||
|
||||
private HexGrid _hexGrid;
|
||||
private readonly HexGrid _hexGrid;
|
||||
|
||||
public HexCell Cell = new HexCell();
|
||||
public bool IsMouseOver = false;
|
||||
public HexCell Cell = new();
|
||||
public bool IsMouseOver;
|
||||
public MeshInstance Mesh;
|
||||
|
||||
public Vector2 OffsetCoords
|
||||
{
|
||||
get { return Cell.OffsetCoords; }
|
||||
public Vector2 OffsetCoords {
|
||||
get => Cell.OffsetCoords;
|
||||
|
||||
set
|
||||
{
|
||||
set {
|
||||
Cell.OffsetCoords = value;
|
||||
Transform tile3dTransform = Transform;
|
||||
Vector2 cellPlaneCoords = _hexGrid.GetHexCenter(Cell);
|
||||
|
@ -50,14 +46,12 @@ public class HexTile3D : Spatial
|
|||
|
||||
public TileType Type { get; set; }
|
||||
|
||||
HexTile3D()
|
||||
{
|
||||
private HexTile3D() {
|
||||
_hexGrid = new HexGrid();
|
||||
}
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_mesh = GetNode<MeshInstance>("Mesh");
|
||||
_staticBody = GetNode<StaticBody>("StaticBody");
|
||||
|
||||
|
@ -65,28 +59,24 @@ public class HexTile3D : Spatial
|
|||
_staticBody.Connect("mouse_entered", this, nameof(OnAreaMouseEntered));
|
||||
_staticBody.Connect("mouse_exited", this, nameof(OnAreaMouseExited));
|
||||
|
||||
Mesh = GetNode<MeshInstance>("Mesh");
|
||||
Mesh = GetNode<MeshInstance>("Mesh");
|
||||
Debug.Assert(Mesh != null);
|
||||
|
||||
this.Type = TileType.Undefined;
|
||||
|
||||
Type = TileType.Undefined;
|
||||
}
|
||||
|
||||
|
||||
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||
int shapeIndex)
|
||||
{
|
||||
if (IsMouseOver && inputEvent is InputEventMouseButton)
|
||||
{
|
||||
int shapeIndex) {
|
||||
if (IsMouseOver && inputEvent is InputEventMouseButton) {
|
||||
InputEventMouseButton mouseButtonEvent = (InputEventMouseButton)inputEvent;
|
||||
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed)
|
||||
{
|
||||
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed) {
|
||||
EmitSignal("TileClicked", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAreaMouseEntered()
|
||||
{
|
||||
public void OnAreaMouseEntered() {
|
||||
IsMouseOver = true;
|
||||
_previousMaterial = (SpatialMaterial)_mesh.MaterialOverride;
|
||||
|
||||
|
@ -96,8 +86,7 @@ public class HexTile3D : Spatial
|
|||
// _mesh.MaterialOverride = clonedMaterial;
|
||||
}
|
||||
|
||||
public void OnAreaMouseExited()
|
||||
{
|
||||
public void OnAreaMouseExited() {
|
||||
IsMouseOver = false;
|
||||
_mesh.MaterialOverride = _previousMaterial;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
using System;
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using GoDotLog;
|
||||
using Godot;
|
||||
|
||||
public class StreamContainer : Spatial
|
||||
{
|
||||
public class StreamContainer : Spatial {
|
||||
// readonly variables
|
||||
private readonly Transform _deactivatedTileTransform = new Transform(Basis.Identity, Vector3.Up * 1000);
|
||||
|
||||
private readonly Transform _deactivatedTileTransform = new(Basis.Identity, Vector3.Up * 1000);
|
||||
|
||||
// scene nodes
|
||||
private MeshInstance _bounds;
|
||||
private Spatial _activeTiles;
|
||||
|
@ -18,50 +14,45 @@ public class StreamContainer : Spatial
|
|||
private MultiMeshInstance _tileMultiMesh;
|
||||
|
||||
// resources
|
||||
private PackedScene _hexTileScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
||||
private readonly PackedScene _hexTileScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
||||
|
||||
// exports
|
||||
[Export] public Vector2 Dimensions = new Vector2(8, 4);
|
||||
[Export] public Vector2 Dimensions = new(8, 4);
|
||||
[Export] public NodePath World;
|
||||
[Export] private bool ShowHexTiles = false;
|
||||
[Export] private bool ShowHexTiles;
|
||||
|
||||
[Signal]
|
||||
delegate void TileClicked(HexTile3D tile3d);
|
||||
private delegate void TileClicked(HexTile3D tile3d);
|
||||
|
||||
[Signal]
|
||||
delegate void TileHovered(HexTile3D tile3d);
|
||||
private delegate void TileHovered(HexTile3D tile3d);
|
||||
|
||||
// other members
|
||||
private Rect2 _currentOffsetCoordRect;
|
||||
private Rect2 _oldOffsetCoordRect;
|
||||
private HexGrid _hexGrid;
|
||||
|
||||
private Dictionary<Vector2, HexTile3D> _coordToTile = new();
|
||||
private Dictionary<HexTile3D, int> _tileToInstanceIndex = new();
|
||||
public List<Vector2> RemovedCoords = new List<Vector2>();
|
||||
public List<Vector2> AddedCoords = new List<Vector2>();
|
||||
private readonly Dictionary<Vector2, HexTile3D> _coordToTile = new();
|
||||
private readonly Dictionary<HexTile3D, int> _tileToInstanceIndex = new();
|
||||
public List<Vector2> RemovedCoords = new();
|
||||
public List<Vector2> AddedCoords = new();
|
||||
|
||||
public Rect2 CurrentOffsetCoordRect
|
||||
{
|
||||
get { return _currentOffsetCoordRect; }
|
||||
}
|
||||
public Rect2 CurrentOffsetCoordRect => _currentOffsetCoordRect;
|
||||
|
||||
public void SetWorld(TileWorld tileWorld)
|
||||
{
|
||||
public void SetWorld(TileWorld tileWorld) {
|
||||
TileWorld = tileWorld;
|
||||
}
|
||||
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_unusedTiles = new Queue<HexTile3D>();
|
||||
_bounds = GetNode<MeshInstance>("Bounds");
|
||||
_activeTiles = GetNode<Spatial>("ActiveTiles");
|
||||
|
||||
|
||||
_tileMultiMesh = GetNode<MultiMeshInstance>("TileMultiMesh");
|
||||
_tileMultiMesh.Multimesh.InstanceCount = (int)((Dimensions.x + 5) * (Dimensions.y + 5));
|
||||
_tileMultiMesh.Multimesh.InstanceCount = 1810;
|
||||
foreach (int i in Enumerable.Range(0, _tileMultiMesh.Multimesh.InstanceCount))
|
||||
{
|
||||
foreach (int i in Enumerable.Range(0, _tileMultiMesh.Multimesh.InstanceCount)) {
|
||||
_tileMultiMesh.Multimesh.SetInstanceTransform(i, _deactivatedTileTransform);
|
||||
}
|
||||
|
||||
|
@ -75,13 +66,12 @@ public class StreamContainer : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void UpdateRects(Vector2 centerPlane)
|
||||
{
|
||||
public void UpdateRects(Vector2 centerPlane) {
|
||||
_oldOffsetCoordRect = _currentOffsetCoordRect;
|
||||
|
||||
Vector2 bottomLeftCoord = centerPlane - new Vector2(Dimensions.x / 2, Dimensions.y / 2);
|
||||
Vector2 topRightCoord = centerPlane + new Vector2(Dimensions.x / 2, Dimensions.y / 2);
|
||||
|
||||
|
||||
// GD.Print("World rect now: " + _worldRect.ToString() + " center: " + _worldRect.GetCenter());
|
||||
|
||||
// y axis needs to be inverted as HexGrid's offset coordinates use the opposite axis direction
|
||||
|
@ -104,15 +94,13 @@ public class StreamContainer : Spatial
|
|||
// GD.Print("Bounds Transform: " + boundsTransform.ToString());
|
||||
// GD.Print("Bounds Global : " + _bounds.GlobalTransform.ToString());
|
||||
|
||||
if (!_currentOffsetCoordRect.Equals(_oldOffsetCoordRect))
|
||||
{
|
||||
if (!_currentOffsetCoordRect.Equals(_oldOffsetCoordRect)) {
|
||||
UpdateTileCache();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void UpdateTileCache()
|
||||
{
|
||||
public void UpdateTileCache() {
|
||||
RemovedCoords.Clear();
|
||||
AddedCoords.Clear();
|
||||
_unusedTiles.Clear();
|
||||
|
@ -123,8 +111,7 @@ public class StreamContainer : Spatial
|
|||
MarkUnusedTiles(expandedRect, clippedRect);
|
||||
AddNewTiles(expandedRect, clippedRect);
|
||||
|
||||
foreach (HexTile3D tile3D in _unusedTiles.ToArray())
|
||||
{
|
||||
foreach (HexTile3D tile3D in _unusedTiles.ToArray()) {
|
||||
RemovedCoords.Add(tile3D.OffsetCoords);
|
||||
_activeTiles.RemoveChild(tile3D);
|
||||
tile3D.Disconnect("TileClicked", this, nameof(OnTileClicked));
|
||||
|
@ -134,65 +121,53 @@ public class StreamContainer : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void MarkUnusedTiles(Rect2 expandedRect, Rect2 clippedRect)
|
||||
{
|
||||
public void MarkUnusedTiles(Rect2 expandedRect, Rect2 clippedRect) {
|
||||
foreach (int coord_x in Enumerable.Range(Mathf.FloorToInt(expandedRect.Position.x) - 5,
|
||||
Mathf.CeilToInt(expandedRect.Size.x) + 20))
|
||||
{
|
||||
Mathf.CeilToInt(expandedRect.Size.x) + 20)) {
|
||||
foreach (int coord_y in Enumerable.Range(Mathf.FloorToInt(expandedRect.Position.y) - 5,
|
||||
Mathf.CeilToInt(expandedRect.Size.y) + 20))
|
||||
{
|
||||
Vector2 coord = new Vector2(coord_x, coord_y);
|
||||
Mathf.CeilToInt(expandedRect.Size.y) + 20)) {
|
||||
Vector2 coord = new(coord_x, coord_y);
|
||||
|
||||
if (clippedRect.HasPoint(coord))
|
||||
{
|
||||
if (clippedRect.HasPoint(coord)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isInCurrent = _currentOffsetCoordRect.HasPoint(coord);
|
||||
bool isInOld = _oldOffsetCoordRect.HasPoint(coord);
|
||||
|
||||
if (isInOld && !isInCurrent && _coordToTile.Keys.Contains(coord))
|
||||
{
|
||||
if (isInOld && !isInCurrent && _coordToTile.Keys.Contains(coord)) {
|
||||
HexTile3D tile3D = _coordToTile[coord];
|
||||
|
||||
|
||||
OnTileDeactivate(tile3D, coord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddNewTiles(Rect2 expandedRect, Rect2 clippedRect)
|
||||
{
|
||||
public void AddNewTiles(Rect2 expandedRect, Rect2 clippedRect) {
|
||||
foreach (int coord_x in Enumerable.Range(Mathf.FloorToInt(_currentOffsetCoordRect.Position.x),
|
||||
Mathf.CeilToInt(_currentOffsetCoordRect.Size.x)))
|
||||
{
|
||||
Mathf.CeilToInt(_currentOffsetCoordRect.Size.x))) {
|
||||
foreach (int coord_y in Enumerable.Range(Mathf.FloorToInt(_currentOffsetCoordRect.Position.y),
|
||||
Mathf.CeilToInt(_currentOffsetCoordRect.Size.y)))
|
||||
{
|
||||
Vector2 coord = new Vector2(coord_x, coord_y);
|
||||
Mathf.CeilToInt(_currentOffsetCoordRect.Size.y))) {
|
||||
Vector2 coord = new(coord_x, coord_y);
|
||||
|
||||
if (clippedRect.HasPoint(coord))
|
||||
{
|
||||
if (clippedRect.HasPoint(coord)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_unusedTiles.Count == 0)
|
||||
{
|
||||
if (_unusedTiles.Count == 0) {
|
||||
AddedCoords.Add(coord);
|
||||
HexTile3D tile3D = GetTile3dAt(coord);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
HexTile3D tile3D = _unusedTiles.Dequeue();
|
||||
tile3D.OffsetCoords = coord;
|
||||
tile3D.Type = TileWorld.GetTileTypeAtOffset(coord);
|
||||
Transform tileTransform = tile3D.Transform;
|
||||
tileTransform.origin.y = TileWorld.GetHeightAtOffset(coord);
|
||||
tile3D.Transform = tileTransform;
|
||||
|
||||
|
||||
OnTileActivate(tile3D);
|
||||
|
||||
|
||||
_coordToTile[coord] = tile3D;
|
||||
}
|
||||
}
|
||||
|
@ -200,49 +175,42 @@ public class StreamContainer : Spatial
|
|||
}
|
||||
|
||||
|
||||
public HexTile3D GetTile3dAt(Vector2 offsetCoords)
|
||||
{
|
||||
if (!_coordToTile.Keys.Contains(offsetCoords))
|
||||
{
|
||||
public HexTile3D GetTile3dAt(Vector2 offsetCoords) {
|
||||
if (!_coordToTile.Keys.Contains(offsetCoords)) {
|
||||
HexTile3D tile3D = (HexTile3D)_hexTileScene.Instance();
|
||||
tile3D.OffsetCoords = offsetCoords;
|
||||
_activeTiles.AddChild(tile3D);
|
||||
tile3D.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
tile3D.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
|
||||
if (ShowHexTiles)
|
||||
{
|
||||
if (ShowHexTiles) {
|
||||
MeshInstance HexTileMesh = tile3D.GetNode<MeshInstance>("Mesh");
|
||||
HexTileMesh.Transform = HexTileMesh.Transform.Scaled(new Vector3(0.95f, 1, 0.95f));
|
||||
}
|
||||
|
||||
|
||||
Transform tileTransform = tile3D.Transform;
|
||||
tileTransform.origin.y = TileWorld.GetHeightAtOffset(offsetCoords);
|
||||
tile3D.Transform = tileTransform;
|
||||
tile3D.Type = TileWorld.GetTileTypeAtOffset(offsetCoords);
|
||||
|
||||
_tileToInstanceIndex[tile3D] = _tileToInstanceIndex.Count;
|
||||
|
||||
|
||||
_coordToTile[offsetCoords] = tile3D;
|
||||
}
|
||||
|
||||
OnTileActivate(_coordToTile[offsetCoords]);
|
||||
|
||||
|
||||
return _coordToTile[offsetCoords];
|
||||
}
|
||||
|
||||
public void SetCenterTile(HexCell cell)
|
||||
{
|
||||
public void SetCenterTile(HexCell cell) {
|
||||
UpdateRects(_hexGrid.GetHexCenter(cell));
|
||||
}
|
||||
|
||||
public void SetTileMaterial(ShaderMaterial material)
|
||||
{
|
||||
foreach (Spatial node in _activeTiles.GetChildren())
|
||||
{
|
||||
public void SetTileMaterial(ShaderMaterial material) {
|
||||
foreach (Spatial node in _activeTiles.GetChildren()) {
|
||||
HexTile3D tile = (HexTile3D)node;
|
||||
if (tile == null)
|
||||
{
|
||||
if (tile == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -250,57 +218,51 @@ public class StreamContainer : Spatial
|
|||
}
|
||||
}
|
||||
|
||||
public void OnTileActivate(HexTile3D tile3D)
|
||||
{
|
||||
public void OnTileActivate(HexTile3D tile3D) {
|
||||
int instanceIndex = _tileToInstanceIndex[tile3D];
|
||||
|
||||
Vector3 scale = Vector3.One;
|
||||
if (ShowHexTiles)
|
||||
{
|
||||
if (ShowHexTiles) {
|
||||
scale.x *= 0.96f;
|
||||
scale.z *= 0.96f;
|
||||
}
|
||||
|
||||
Transform instanceTransform = new Transform(tile3D.GlobalTransform.basis.Rotated(Vector3.Up, Mathf.Deg2Rad(30)).Scaled(scale), tile3D.GlobalTransform.origin + Vector3.Up * -2.5f);
|
||||
|
||||
|
||||
Transform instanceTransform =
|
||||
new(tile3D.GlobalTransform.basis.Rotated(Vector3.Up, Mathf.Deg2Rad(30)).Scaled(scale),
|
||||
tile3D.GlobalTransform.origin + Vector3.Up * -2.5f);
|
||||
|
||||
_tileMultiMesh.Multimesh.SetInstanceTransform(instanceIndex, instanceTransform);
|
||||
}
|
||||
|
||||
public void OnTileDeactivate(HexTile3D tile3D, Vector2 coord)
|
||||
{
|
||||
public void OnTileDeactivate(HexTile3D tile3D, Vector2 coord) {
|
||||
int instanceIndex = _tileToInstanceIndex[tile3D];
|
||||
_tileMultiMesh.Multimesh.SetInstanceTransform(instanceIndex, _deactivatedTileTransform);
|
||||
|
||||
|
||||
tile3D.Type = HexTile3D.TileType.Undefined;
|
||||
_unusedTiles.Enqueue(tile3D);
|
||||
_coordToTile.Remove(coord);
|
||||
RemovedCoords.Add(coord);
|
||||
}
|
||||
|
||||
public void OnTileClicked(HexTile3D tile)
|
||||
{
|
||||
public void OnTileClicked(HexTile3D tile) {
|
||||
EmitSignal("TileClicked", tile);
|
||||
}
|
||||
|
||||
public void OnTileHovered(HexTile3D tile)
|
||||
{
|
||||
|
||||
public void OnTileHovered(HexTile3D tile) {
|
||||
EmitSignal("TileHovered", tile);
|
||||
}
|
||||
|
||||
public void OnWorldGenerated()
|
||||
{
|
||||
foreach (Spatial node in _activeTiles.GetChildren())
|
||||
{
|
||||
public void OnWorldGenerated() {
|
||||
foreach (Spatial node in _activeTiles.GetChildren()) {
|
||||
HexTile3D tile = (HexTile3D)node;
|
||||
if (tile == null)
|
||||
{
|
||||
if (tile == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Transform tileTransform = tile.GlobalTransform;
|
||||
tileTransform.origin.y = TileWorld.GetHeightAtOffset(tile.OffsetCoords);
|
||||
tile.GlobalTransform = tileTransform;
|
||||
|
||||
|
||||
OnTileActivate(tile);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,202 +0,0 @@
|
|||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
public class TileInstanceManager : Spatial
|
||||
{
|
||||
// exports
|
||||
[Export] public NodePath World;
|
||||
[Export] public bool ShowHexTiles;
|
||||
[Export] public Vector2 ViewCenterPlaneCoord;
|
||||
|
||||
// scene nodes
|
||||
public MultiMeshInstance TileMultiMeshInstance;
|
||||
|
||||
// other members
|
||||
private readonly Array<SceneTileChunk> _sceneTileChunks = new();
|
||||
private int _usedTileInstanceIndices;
|
||||
private ImageTexture _viewTileTypeTexture;
|
||||
private World _world;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
_world = GetNode<World>(World);
|
||||
|
||||
_world.Connect("OnTilesChanged", this, nameof(HandleWorldTileChange));
|
||||
|
||||
TileMultiMeshInstance = (MultiMeshInstance)FindNode("TileMultiMeshInstance");
|
||||
Debug.Assert(TileMultiMeshInstance != null);
|
||||
}
|
||||
|
||||
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
}
|
||||
|
||||
private SceneTileChunk CreateSceneTileChunk(Vector2 chunkIndex)
|
||||
{
|
||||
var sceneTileChunk =
|
||||
new SceneTileChunk(chunkIndex, TileMultiMeshInstance, _usedTileInstanceIndices, ShowHexTiles);
|
||||
_usedTileInstanceIndices += sceneTileChunk.TileNodes.Count;
|
||||
|
||||
foreach (var hexTile3D in sceneTileChunk.TileNodes)
|
||||
{
|
||||
hexTile3D.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
hexTile3D.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
}
|
||||
|
||||
return sceneTileChunk;
|
||||
}
|
||||
|
||||
private SceneTileChunk FindSceneTileChunkAtIndex(Vector2 chunkIndex)
|
||||
{
|
||||
foreach (Spatial child in GetChildren())
|
||||
{
|
||||
var sceneTileChunk = child as SceneTileChunk;
|
||||
if (sceneTileChunk == null) continue;
|
||||
|
||||
if (sceneTileChunk.ChunkIndex == chunkIndex) return sceneTileChunk;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private void HandleWorldTileChange(Array<Vector2> removedChunkIndices, Array<Vector2> addedChunkIndices)
|
||||
{
|
||||
Array<SceneTileChunk> removedChunks = new();
|
||||
foreach (var chunkIndex in removedChunkIndices)
|
||||
{
|
||||
var chunk = FindSceneTileChunkAtIndex(chunkIndex);
|
||||
if (chunk != null) removedChunks.Add(chunk);
|
||||
}
|
||||
|
||||
foreach (var chunkIndex in addedChunkIndices)
|
||||
{
|
||||
SceneTileChunk sceneTileChunk = null;
|
||||
if (removedChunks.Count > 0)
|
||||
{
|
||||
sceneTileChunk = removedChunks[^1];
|
||||
sceneTileChunk.ChunkIndex = chunkIndex;
|
||||
removedChunks.RemoveAt(removedChunks.Count - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sceneTileChunk = CreateSceneTileChunk(chunkIndex);
|
||||
AddChild(sceneTileChunk);
|
||||
}
|
||||
|
||||
_sceneTileChunks.Add(sceneTileChunk);
|
||||
}
|
||||
|
||||
GD.Print("Removed Chunks " + removedChunkIndices.Count);
|
||||
GD.Print("Added Chunks " + addedChunkIndices.Count);
|
||||
GD.Print("Removed chunk count: " + removedChunks.Count);
|
||||
}
|
||||
|
||||
public void OnTileClicked(HexTile3D tile)
|
||||
{
|
||||
EmitSignal("TileClicked", tile);
|
||||
}
|
||||
|
||||
public void OnTileHovered(HexTile3D tile)
|
||||
{
|
||||
EmitSignal("TileHovered", tile);
|
||||
}
|
||||
|
||||
// signals
|
||||
[Signal]
|
||||
private delegate void TileClicked(HexTile3D tile3d);
|
||||
|
||||
[Signal]
|
||||
private delegate void TileHovered(HexTile3D tile3d);
|
||||
|
||||
private class SceneTileChunk : Spatial
|
||||
{
|
||||
private readonly PackedScene _hexTile3DScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
||||
private readonly MultiMeshInstance _multiMeshInstance;
|
||||
private readonly Array<int> _tileInstanceIndices = new();
|
||||
private readonly HexGrid _hexGrid = new();
|
||||
private readonly bool _showHexTiles;
|
||||
|
||||
public readonly Array<HexTile3D> TileNodes = new();
|
||||
private Vector2 _chunkIndex = Vector2.Inf;
|
||||
|
||||
|
||||
public SceneTileChunk(Vector2 chunkIndex, MultiMeshInstance multiMeshInstance, int tileInstanceIndexStart,
|
||||
bool showHexTiles)
|
||||
{
|
||||
_showHexTiles = showHexTiles;
|
||||
|
||||
var tileInstanceIndexStart1 = tileInstanceIndexStart;
|
||||
var chunkSize = global::World.ChunkSize;
|
||||
|
||||
foreach (var i in Enumerable.Range(0, chunkSize))
|
||||
foreach (var j in Enumerable.Range(0, chunkSize))
|
||||
{
|
||||
var tile3D = (HexTile3D)_hexTile3DScene.Instance();
|
||||
tile3D.Cell.OffsetCoords = new Vector2(chunkIndex * global::World.ChunkSize + new Vector2(i, j));
|
||||
|
||||
var tileTransform = Transform.Identity;
|
||||
var centerPlaneCoord = _hexGrid.GetHexCenterFromOffset(new Vector2(i, j));
|
||||
tileTransform.origin = new Vector3(centerPlaneCoord.x, 0, centerPlaneCoord.y);
|
||||
tile3D.Transform = tileTransform;
|
||||
|
||||
TileNodes.Add(tile3D);
|
||||
AddChild(tile3D);
|
||||
}
|
||||
|
||||
_multiMeshInstance = multiMeshInstance;
|
||||
|
||||
var chunkTileCount = global::World.ChunkSize * global::World.ChunkSize;
|
||||
|
||||
Debug.Assert(tileInstanceIndexStart1 + chunkTileCount <= _multiMeshInstance.Multimesh.InstanceCount);
|
||||
|
||||
foreach (var i in Enumerable.Range(0, chunkTileCount))
|
||||
_tileInstanceIndices.Add(tileInstanceIndexStart1 + i);
|
||||
|
||||
// _multiMeshInstance.Multimesh.InstanceCount += chunkTileCount;
|
||||
_multiMeshInstance.Multimesh.VisibleInstanceCount = _multiMeshInstance.Multimesh.InstanceCount;
|
||||
|
||||
ChunkIndex = chunkIndex;
|
||||
}
|
||||
|
||||
public Vector2 ChunkIndex
|
||||
{
|
||||
get => _chunkIndex;
|
||||
|
||||
set
|
||||
{
|
||||
var chunkTransform = Transform.Identity;
|
||||
var chunkOriginPlaneCoord = _hexGrid.GetHexCenterFromOffset(value * global::World.ChunkSize);
|
||||
chunkTransform.origin = new Vector3(chunkOriginPlaneCoord.x, 0, chunkOriginPlaneCoord.y);
|
||||
Transform = chunkTransform;
|
||||
_chunkIndex = value;
|
||||
|
||||
var tileOrientation = new Basis(Vector3.Up, 90f * Mathf.Pi / 180f);
|
||||
|
||||
GD.Print("Updating transforms for instances of chunk " + value + " origin: " + chunkTransform.origin);
|
||||
|
||||
foreach (var i in Enumerable.Range(0, _tileInstanceIndices.Count))
|
||||
{
|
||||
var column = i % global::World.ChunkSize;
|
||||
var row = i / global::World.ChunkSize;
|
||||
|
||||
var tilePlaneCoord =
|
||||
_hexGrid.GetHexCenterFromOffset(new Vector2(column, row));
|
||||
|
||||
var hexTransform = new Transform(tileOrientation,
|
||||
chunkTransform.origin + new Vector3(tilePlaneCoord.x, 0, tilePlaneCoord.y));
|
||||
|
||||
if (_showHexTiles)
|
||||
hexTransform = new Transform(tileOrientation.Scaled(Vector3.One * 0.95f),
|
||||
hexTransform.origin);
|
||||
|
||||
_multiMeshInstance.Multimesh.SetInstanceTransform(_tileInstanceIndices[i], hexTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,8 +5,7 @@ using Godot;
|
|||
using Godot.Collections;
|
||||
using Namespace;
|
||||
|
||||
public class TileWorld : Spatial
|
||||
{
|
||||
public class TileWorld : Spatial {
|
||||
// exports
|
||||
[Export] public bool DebugMap;
|
||||
[ExportFlagsEnum(typeof(MapType))] public MapType GenerationMapType = MapType.Debug;
|
||||
|
@ -21,8 +20,7 @@ public class TileWorld : Spatial
|
|||
private Spatial _environmentNode;
|
||||
private readonly Array<Spatial> _grassAssets = new();
|
||||
|
||||
private enum GenerationState
|
||||
{
|
||||
private enum GenerationState {
|
||||
Heightmap,
|
||||
Color,
|
||||
Objects,
|
||||
|
@ -34,8 +32,7 @@ public class TileWorld : Spatial
|
|||
private delegate void WorldGenerated();
|
||||
|
||||
// public members
|
||||
public enum MapType
|
||||
{
|
||||
public enum MapType {
|
||||
Noise,
|
||||
Debug,
|
||||
Flat
|
||||
|
@ -62,8 +59,7 @@ public class TileWorld : Spatial
|
|||
private Viewport _worldOffscreenViewport;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
HexGrid = new HexGrid();
|
||||
_tileTypeRandom = new Random();
|
||||
|
||||
|
@ -83,18 +79,15 @@ public class TileWorld : Spatial
|
|||
|
||||
GetNode<Spatial>("Assets").Visible = false;
|
||||
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Rocks").GetChildren())
|
||||
{
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Rocks").GetChildren()) {
|
||||
_rockAssets.Add(asset);
|
||||
}
|
||||
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Grass").GetChildren())
|
||||
{
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Grass").GetChildren()) {
|
||||
_grassAssets.Add(asset);
|
||||
}
|
||||
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Trees").GetChildren())
|
||||
{
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Trees").GetChildren()) {
|
||||
_treeAssets.Add(asset);
|
||||
}
|
||||
|
||||
|
@ -106,8 +99,7 @@ public class TileWorld : Spatial
|
|||
ResetWorldImages(Size);
|
||||
}
|
||||
|
||||
public void ResetWorldImages(int size)
|
||||
{
|
||||
public void ResetWorldImages(int size) {
|
||||
GD.Print("Resetting World Images to size " + size);
|
||||
|
||||
Vector2 sizeVector = new Vector2(size, size);
|
||||
|
@ -130,12 +122,10 @@ public class TileWorld : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void Generate(int size)
|
||||
{
|
||||
public void Generate(int size) {
|
||||
GD.Print("Triggering generation for size: " + size);
|
||||
|
||||
if (Size != size)
|
||||
{
|
||||
if (Size != size) {
|
||||
ResetWorldImages(size);
|
||||
_resizeTriggered = true;
|
||||
_resizeExtraFrameCount = 1;
|
||||
|
@ -153,8 +143,7 @@ public class TileWorld : Spatial
|
|||
|
||||
OnMapGenerationStart();
|
||||
|
||||
switch (GenerationMapType)
|
||||
{
|
||||
switch (GenerationMapType) {
|
||||
case MapType.Debug:
|
||||
GenerateDebugMap();
|
||||
break;
|
||||
|
@ -167,8 +156,7 @@ public class TileWorld : Spatial
|
|||
}
|
||||
}
|
||||
|
||||
private void GenerateDebugMap()
|
||||
{
|
||||
private void GenerateDebugMap() {
|
||||
ColormapImage = new Image();
|
||||
ColormapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
||||
|
||||
|
@ -178,10 +166,8 @@ public class TileWorld : Spatial
|
|||
HeightmapImage.Lock();
|
||||
ColormapImage.Lock();
|
||||
|
||||
foreach (int coordX in Enumerable.Range(0, Size))
|
||||
{
|
||||
foreach (int coordY in Enumerable.Range(0, Size))
|
||||
{
|
||||
foreach (int coordX in Enumerable.Range(0, Size)) {
|
||||
foreach (int coordY in Enumerable.Range(0, Size)) {
|
||||
ColormapImage.SetPixel(coordX, coordY,
|
||||
new Color((float)Mathf.Min(coordX, coordY) / Size, 0, 0));
|
||||
HeightmapImage.SetPixel(coordX, coordY,
|
||||
|
@ -197,8 +183,7 @@ public class TileWorld : Spatial
|
|||
}
|
||||
|
||||
|
||||
private void GenerateFlatMap()
|
||||
{
|
||||
private void GenerateFlatMap() {
|
||||
ColormapImage = new Image();
|
||||
ColormapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
||||
|
||||
|
@ -208,10 +193,8 @@ public class TileWorld : Spatial
|
|||
HeightmapImage.Lock();
|
||||
ColormapImage.Lock();
|
||||
|
||||
foreach (int coordX in Enumerable.Range(0, Size))
|
||||
{
|
||||
foreach (int coordY in Enumerable.Range(0, Size))
|
||||
{
|
||||
foreach (int coordX in Enumerable.Range(0, Size)) {
|
||||
foreach (int coordY in Enumerable.Range(0, Size)) {
|
||||
HeightmapImage.SetPixel(coordX, coordY,
|
||||
new Color(0.5f, 0.5f, 0.5f));
|
||||
}
|
||||
|
@ -224,8 +207,7 @@ public class TileWorld : Spatial
|
|||
}
|
||||
|
||||
|
||||
private void GenerateNoiseMap()
|
||||
{
|
||||
private void GenerateNoiseMap() {
|
||||
HeightmapImage = new Image();
|
||||
HeightmapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
||||
|
||||
|
@ -245,28 +227,23 @@ public class TileWorld : Spatial
|
|||
OnHeightMapChanged();
|
||||
}
|
||||
|
||||
private void OnMapGenerationStart()
|
||||
{
|
||||
foreach (Node child in _environmentNode.GetChildren())
|
||||
{
|
||||
private void OnMapGenerationStart() {
|
||||
foreach (Node child in _environmentNode.GetChildren()) {
|
||||
child.QueueFree();
|
||||
}
|
||||
|
||||
foreach (Node child in Entities.GetChildren())
|
||||
{
|
||||
foreach (Node child in Entities.GetChildren()) {
|
||||
child.QueueFree();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHeightMapChanged()
|
||||
{
|
||||
private void OnHeightMapChanged() {
|
||||
GD.Print("Triggering rendering of height map");
|
||||
_currentGenerationState = GenerationState.Heightmap;
|
||||
_heightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once;
|
||||
}
|
||||
|
||||
private void OnMapGenerationComplete()
|
||||
{
|
||||
private void OnMapGenerationComplete() {
|
||||
_currentGenerationState = GenerationState.Done;
|
||||
_worldOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
||||
_heightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
||||
|
@ -276,10 +253,9 @@ public class TileWorld : Spatial
|
|||
EmitSignal("WorldGenerated");
|
||||
}
|
||||
|
||||
private Spatial SelectAsset(Vector2 offsetCoord, Array<Spatial> assets, Random randomGenerator, double probability)
|
||||
{
|
||||
if (randomGenerator.NextDouble() < 1.0 - probability)
|
||||
{
|
||||
private Spatial SelectAsset(Vector2 offsetCoord, Array<Spatial> assets, Random randomGenerator,
|
||||
double probability) {
|
||||
if (randomGenerator.NextDouble() < 1.0 - probability) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -295,66 +271,52 @@ public class TileWorld : Spatial
|
|||
return assetInstance;
|
||||
}
|
||||
|
||||
private bool IsColorEqualApprox(Color colorA, Color colorB)
|
||||
{
|
||||
private bool IsColorEqualApprox(Color colorA, Color colorB) {
|
||||
Vector3 colorDifference = new Vector3(colorA.r - colorB.r, colorA.g - colorB.g, colorA.b - colorB.b);
|
||||
return colorDifference.LengthSquared() < 0.1 * 0.1;
|
||||
}
|
||||
|
||||
private bool IsColorWater(Color color)
|
||||
{
|
||||
private bool IsColorWater(Color color) {
|
||||
return (color.r == 0 && color.g == 0 && color.b > 0.01);
|
||||
}
|
||||
|
||||
public void MarkCellUnwalkable(HexCell cell)
|
||||
{
|
||||
public void MarkCellUnwalkable(HexCell cell) {
|
||||
HexGrid.AddObstacle(cell);
|
||||
NavigationmapImage.Lock();
|
||||
NavigationmapImage.SetPixelv(OffsetToTextureCoord(cell.OffsetCoords), Colors.Red);
|
||||
NavigationmapImage.Unlock();
|
||||
}
|
||||
|
||||
private void PopulateEnvironment()
|
||||
{
|
||||
private void PopulateEnvironment() {
|
||||
Random environmentRandom = new Random(Seed);
|
||||
|
||||
ColormapImage.Lock();
|
||||
HeightmapImage.Lock();
|
||||
|
||||
foreach (int textureCoordU in Enumerable.Range(0, Size))
|
||||
{
|
||||
foreach (int textureCoordV in Enumerable.Range(0, Size))
|
||||
{
|
||||
foreach (int textureCoordU in Enumerable.Range(0, Size)) {
|
||||
foreach (int textureCoordV in Enumerable.Range(0, Size)) {
|
||||
Color colorValue = ColormapImage.GetPixel(textureCoordU, textureCoordV);
|
||||
Vector2 textureCoord = new Vector2(textureCoordU, textureCoordV);
|
||||
HexCell cell = TextureCoordToCell(textureCoord);
|
||||
Vector2 offsetCoord = cell.OffsetCoords;
|
||||
|
||||
if (IsColorEqualApprox(colorValue, RockColor))
|
||||
{
|
||||
if (IsColorEqualApprox(colorValue, RockColor)) {
|
||||
Spatial rockAsset = SelectAsset(offsetCoord, _rockAssets, environmentRandom, 0.15);
|
||||
if (rockAsset != null)
|
||||
{
|
||||
if (rockAsset != null) {
|
||||
_environmentNode.AddChild(rockAsset);
|
||||
MarkCellUnwalkable(cell);
|
||||
}
|
||||
}
|
||||
else if (IsColorEqualApprox(colorValue, GrassColor))
|
||||
{
|
||||
} else if (IsColorEqualApprox(colorValue, GrassColor)) {
|
||||
Spatial grassAsset = SelectAsset(offsetCoord, _grassAssets, environmentRandom, 0.35);
|
||||
if (grassAsset != null)
|
||||
{
|
||||
if (grassAsset != null) {
|
||||
_environmentNode.AddChild(grassAsset);
|
||||
}
|
||||
|
||||
Spatial treeAsset = SelectAsset(offsetCoord, _treeAssets, environmentRandom, 0.10);
|
||||
if (treeAsset != null)
|
||||
{
|
||||
if (treeAsset != null) {
|
||||
Entities.AddChild(treeAsset);
|
||||
MarkCellUnwalkable(cell);
|
||||
}
|
||||
else if (environmentRandom.NextDouble() < 0.01)
|
||||
{
|
||||
} else if (environmentRandom.NextDouble() < 0.01) {
|
||||
Chest chestAsset = (Chest)_chestScene.Instance();
|
||||
Transform assetTransform = Transform.Identity;
|
||||
assetTransform.origin = GetHexCenterFromOffset(offsetCoord);
|
||||
|
@ -363,9 +325,7 @@ public class TileWorld : Spatial
|
|||
Entities.AddChild(chestAsset);
|
||||
MarkCellUnwalkable(cell);
|
||||
}
|
||||
}
|
||||
else if (IsColorWater(colorValue))
|
||||
{
|
||||
} else if (IsColorWater(colorValue)) {
|
||||
MarkCellUnwalkable(cell);
|
||||
}
|
||||
}
|
||||
|
@ -375,16 +335,13 @@ public class TileWorld : Spatial
|
|||
ColormapImage.Unlock();
|
||||
}
|
||||
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
if (_resizeTriggered && _resizeExtraFrameCount > 0)
|
||||
{
|
||||
public override void _Process(float delta) {
|
||||
if (_resizeTriggered && _resizeExtraFrameCount > 0) {
|
||||
_resizeExtraFrameCount--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_currentGenerationState == GenerationState.Heightmap)
|
||||
{
|
||||
if (_currentGenerationState == GenerationState.Heightmap) {
|
||||
HeightmapImage.CopyFrom(_heightmapOffscreenViewport.GetTexture().GetData());
|
||||
|
||||
_currentGenerationState = GenerationState.Color;
|
||||
|
@ -397,9 +354,7 @@ public class TileWorld : Spatial
|
|||
|
||||
_worldOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once;
|
||||
_resizeExtraFrameCount = 1;
|
||||
}
|
||||
else if (_currentGenerationState == GenerationState.Color)
|
||||
{
|
||||
} else if (_currentGenerationState == GenerationState.Color) {
|
||||
ColormapImage = new Image();
|
||||
ColormapImage.Create(Size, Size, false, Image.Format.Rgb8);
|
||||
ColormapImage.CopyFrom(_worldOffscreenViewport.GetTexture().GetData());
|
||||
|
@ -407,24 +362,19 @@ public class TileWorld : Spatial
|
|||
_currentGenerationState = GenerationState.Objects;
|
||||
|
||||
PopulateEnvironment();
|
||||
}
|
||||
else if (_currentGenerationState == GenerationState.Objects)
|
||||
{
|
||||
} else if (_currentGenerationState == GenerationState.Objects) {
|
||||
OnMapGenerationComplete();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsOffsetCoordValid(Vector2 offsetCoord)
|
||||
{
|
||||
public bool IsOffsetCoordValid(Vector2 offsetCoord) {
|
||||
return ((int)Math.Clamp(offsetCoord.x, -(float)Size / 2, (float)Size / 2 - 1) == (int)offsetCoord.x
|
||||
&& (int)Math.Clamp(offsetCoord.y, -(float)Size / 2, (float)Size / 2 - 1) == (int)offsetCoord.y);
|
||||
}
|
||||
|
||||
|
||||
public HexTile3D.TileType GetTileTypeAtOffset(Vector2 offsetCoord)
|
||||
{
|
||||
if (!IsOffsetCoordValid(offsetCoord))
|
||||
{
|
||||
public HexTile3D.TileType GetTileTypeAtOffset(Vector2 offsetCoord) {
|
||||
if (!IsOffsetCoordValid(offsetCoord)) {
|
||||
return HexTile3D.TileType.Undefined;
|
||||
}
|
||||
|
||||
|
@ -432,24 +382,20 @@ public class TileWorld : Spatial
|
|||
}
|
||||
|
||||
|
||||
public Vector2 OffsetToTextureCoord(Vector2 offsetCoord)
|
||||
{
|
||||
public Vector2 OffsetToTextureCoord(Vector2 offsetCoord) {
|
||||
Vector2 mapSize = Vector2.One * Size;
|
||||
Vector2 textureCoord = (offsetCoord + mapSize / 2).PosMod(mapSize);
|
||||
return textureCoord;
|
||||
}
|
||||
|
||||
public void SetHeightAtOffset(Vector2 offsetCoord, float height)
|
||||
{
|
||||
public void SetHeightAtOffset(Vector2 offsetCoord, float height) {
|
||||
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
|
||||
|
||||
HeightmapImage.SetPixel((int)textureCoord.x, (int)textureCoord.y, new Color(height, 0f, 0f));
|
||||
}
|
||||
|
||||
public float GetHeightAtOffset(Vector2 offsetCoord)
|
||||
{
|
||||
if (_currentGenerationState != GenerationState.Done)
|
||||
{
|
||||
public float GetHeightAtOffset(Vector2 offsetCoord) {
|
||||
if (_currentGenerationState != GenerationState.Done) {
|
||||
return 0f;
|
||||
}
|
||||
|
||||
|
@ -467,8 +413,7 @@ public class TileWorld : Spatial
|
|||
}
|
||||
|
||||
|
||||
public void SetTileColorAtOffset(Vector2 offsetCoord, Color color)
|
||||
{
|
||||
public void SetTileColorAtOffset(Vector2 offsetCoord, Color color) {
|
||||
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
|
||||
|
||||
ColormapImage.Lock();
|
||||
|
@ -476,32 +421,27 @@ public class TileWorld : Spatial
|
|||
ColormapImage.Unlock();
|
||||
}
|
||||
|
||||
public Vector2 WorldToOffsetCoords(Vector3 worldCoord)
|
||||
{
|
||||
public Vector2 WorldToOffsetCoords(Vector3 worldCoord) {
|
||||
return HexGrid.GetHexAt(new Vector2(worldCoord.x, worldCoord.z)).OffsetCoords +
|
||||
Vector2.One * Mathf.Round(Size / 2f);
|
||||
}
|
||||
|
||||
public Vector3 GetTileWorldCenterFromOffset(Vector2 offsetCoord)
|
||||
{
|
||||
public Vector3 GetTileWorldCenterFromOffset(Vector2 offsetCoord) {
|
||||
Vector2 tileCenter = HexGrid.GetHexCenterFromOffset(offsetCoord - Vector2.One * Mathf.Round(Size / 2f));
|
||||
return new Vector3(tileCenter.x, GetHeightAtOffset(offsetCoord), tileCenter.y);
|
||||
}
|
||||
|
||||
|
||||
public Vector3 GetHexCenterFromOffset(Vector2 offsetCoord)
|
||||
{
|
||||
public Vector3 GetHexCenterFromOffset(Vector2 offsetCoord) {
|
||||
Vector2 tileCenter = HexGrid.GetHexCenterFromOffset(offsetCoord);
|
||||
return new Vector3(tileCenter.x, GetHeightAtOffset(offsetCoord), tileCenter.y);
|
||||
}
|
||||
|
||||
public HexCell TextureCoordToCell(Vector2 textureCoord)
|
||||
{
|
||||
public HexCell TextureCoordToCell(Vector2 textureCoord) {
|
||||
return HexCell.FromOffsetCoords(textureCoord - Vector2.One * _halfSize);
|
||||
}
|
||||
|
||||
public Vector2 TextureCoordToOffsetCoord(Vector2 textureCoord)
|
||||
{
|
||||
public Vector2 TextureCoordToOffsetCoord(Vector2 textureCoord) {
|
||||
return TextureCoordToCell(textureCoord).OffsetCoords;
|
||||
}
|
||||
}
|
684
scenes/World.cs
684
scenes/World.cs
|
@ -4,12 +4,11 @@ using System.Diagnostics;
|
|||
using System.Linq;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using Priority_Queue;
|
||||
|
||||
public class World : Spatial
|
||||
{
|
||||
public enum GenerationState
|
||||
{
|
||||
Undefined,
|
||||
public class World : Spatial {
|
||||
public enum GenerationState {
|
||||
Empty,
|
||||
Heightmap,
|
||||
TileType,
|
||||
Objects,
|
||||
|
@ -17,7 +16,7 @@ public class World : Spatial
|
|||
}
|
||||
|
||||
// constants
|
||||
public const int ChunkSize = 18;
|
||||
public int ChunkSize = 14;
|
||||
public const int NumChunkRows = 3;
|
||||
public const int NumChunkColumns = NumChunkRows;
|
||||
private static readonly Color RockColor = new(0.5f, 0.5f, 0.4f);
|
||||
|
@ -25,8 +24,9 @@ public class World : Spatial
|
|||
private static readonly Color DarkGrassColor = new(0.05882353f, 0.5411765f, 0.05882353f);
|
||||
private static readonly Color LightWaterColor = new(0.05882353f, 0.05882353f, 0.8627451f);
|
||||
|
||||
private readonly List<Vector2> _addedChunkIndices = new();
|
||||
private readonly Godot.Collections.Dictionary<Vector2, WorldChunk> _cachedWorldChunks;
|
||||
private readonly List<Vector2> _addedChunkIndices = new();
|
||||
private readonly List<WorldChunk> _deactivatedWorldChunks = new();
|
||||
private readonly Image _heightmapImage = new();
|
||||
private readonly List<Vector2> _removedChunkIndices = new();
|
||||
private readonly Image _tileTypeMapImage = new();
|
||||
|
@ -36,6 +36,7 @@ public class World : Spatial
|
|||
|
||||
private List<Vector2> _activeChunkIndices = new();
|
||||
private Rect2 _centerChunkRect;
|
||||
private readonly List<Spatial> _removedSpatialNodes = new();
|
||||
|
||||
// delegate void OnCoordClicked(Vector2 world_pos);
|
||||
|
||||
|
@ -48,7 +49,8 @@ public class World : Spatial
|
|||
|
||||
private OpenSimplexNoise _noiseGenerator = new();
|
||||
private Array<Spatial> _rockAssets;
|
||||
private TileInstanceManager _tileInstanceManager;
|
||||
private MultiMeshInstance _tileMultiMeshInstance;
|
||||
private int _usedTileMeshInstances;
|
||||
private Array<Spatial> _treeAssets;
|
||||
private ImageTexture _viewTileTypeTexture;
|
||||
public Vector2 CenterChunkIndex = Vector2.Zero;
|
||||
|
@ -57,7 +59,7 @@ public class World : Spatial
|
|||
public HexGrid HexGrid = new();
|
||||
public int Seed = 0;
|
||||
|
||||
public GenerationState State = GenerationState.Done;
|
||||
public GenerationState State = GenerationState.Empty;
|
||||
public Vector2 WorldTextureCoordinateOffset;
|
||||
|
||||
|
||||
|
@ -80,42 +82,51 @@ public class World : Spatial
|
|||
[Signal]
|
||||
private delegate void OnHeightmapImageChanged(Image heightmapImage);
|
||||
|
||||
public World()
|
||||
{
|
||||
[Signal]
|
||||
public delegate void EntityClicked(Entity entity);
|
||||
|
||||
// signals
|
||||
[Signal]
|
||||
private delegate void TileClicked(HexTile3D tile3d);
|
||||
|
||||
[Signal]
|
||||
private delegate void TileHovered(HexTile3D tile3d);
|
||||
|
||||
public World() {
|
||||
Debug.Assert(ChunkSize % 2 == 0);
|
||||
|
||||
_cachedWorldChunks = new Godot.Collections.Dictionary<Vector2, WorldChunk>();
|
||||
}
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
Chunks = (Spatial)FindNode("Chunks");
|
||||
Debug.Assert(Chunks != null);
|
||||
|
||||
_tileInstanceManager = (TileInstanceManager)FindNode("TileInstanceManager");
|
||||
Debug.Assert(_tileInstanceManager != null);
|
||||
_tileInstanceManager.TileMultiMeshInstance.Multimesh.InstanceCount =
|
||||
ChunkSize * ChunkSize * NumChunkColumns * NumChunkRows;
|
||||
_tileMultiMeshInstance = (MultiMeshInstance)FindNode("TileMultiMeshInstance");
|
||||
Debug.Assert(_tileMultiMeshInstance != null);
|
||||
|
||||
InitNoiseGenerator();
|
||||
|
||||
GetNode<Spatial>("Assets").Visible = false;
|
||||
|
||||
_rockAssets = new Array<Spatial>();
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Rocks").GetChildren()) _rockAssets.Add(asset);
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Rocks").GetChildren()) {
|
||||
_rockAssets.Add(asset);
|
||||
}
|
||||
|
||||
_grassAssets = new Array<Spatial>();
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Grass").GetChildren()) _grassAssets.Add(asset);
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Grass").GetChildren()) {
|
||||
_grassAssets.Add(asset);
|
||||
}
|
||||
|
||||
_treeAssets = new Array<Spatial>();
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Trees").GetChildren()) _treeAssets.Add(asset);
|
||||
|
||||
SetCenterPlaneCoord(Vector2.Zero);
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Trees").GetChildren()) {
|
||||
_treeAssets.Add(asset);
|
||||
}
|
||||
}
|
||||
|
||||
public void InitNoiseGenerator()
|
||||
{
|
||||
public void InitNoiseGenerator() {
|
||||
_noiseGenerator = new OpenSimplexNoise();
|
||||
|
||||
_noiseGenerator.Seed = Seed;
|
||||
|
@ -125,65 +136,86 @@ public class World : Spatial
|
|||
_noiseGenerator.Lacunarity = 2;
|
||||
}
|
||||
|
||||
public WorldChunk GetOrCreateWorldChunk(int xIndex, int yIndex, Color debugColor)
|
||||
{
|
||||
if (IsChunkCached(xIndex, yIndex))
|
||||
{
|
||||
var cachedChunk = _cachedWorldChunks[new Vector2(xIndex, yIndex)];
|
||||
return cachedChunk;
|
||||
public void Reset() {
|
||||
foreach (Spatial chunkChild in Chunks.GetChildren()) {
|
||||
chunkChild.QueueFree();
|
||||
}
|
||||
|
||||
return CreateWorldChunk(xIndex, yIndex, debugColor);
|
||||
// foreach (WorldChunk chunk in _cachedWorldChunks.Values) {
|
||||
// chunk.QueueFree();
|
||||
// }
|
||||
|
||||
_cachedWorldChunks.Clear();
|
||||
_addedChunkIndices.Clear();
|
||||
|
||||
_tileMultiMeshInstance.Multimesh.InstanceCount =
|
||||
ChunkSize * ChunkSize * NumChunkColumns * NumChunkRows;
|
||||
_usedTileMeshInstances = 0;
|
||||
|
||||
State = GenerationState.Empty;
|
||||
}
|
||||
|
||||
private bool IsChunkCached(int xIndex, int yIndex)
|
||||
{
|
||||
return _cachedWorldChunks.ContainsKey(new Vector2(xIndex, yIndex));
|
||||
public WorldChunk GetOrCreateWorldChunk(Vector2 chunkIndex, Color debugColor) {
|
||||
WorldChunk chunk;
|
||||
|
||||
if (IsChunkCached(chunkIndex)) {
|
||||
return _cachedWorldChunks[chunkIndex];
|
||||
}
|
||||
|
||||
if (_deactivatedWorldChunks.Count > 0) {
|
||||
chunk = _deactivatedWorldChunks.First();
|
||||
_deactivatedWorldChunks.RemoveAt(0);
|
||||
} else {
|
||||
chunk = CreateWorldChunk(chunkIndex, debugColor);
|
||||
}
|
||||
|
||||
_cachedWorldChunks[chunkIndex] = chunk;
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private WorldChunk CreateWorldChunk(int xIndex, int yIndex, Color debugColor)
|
||||
{
|
||||
var result = (WorldChunk)_worldChunkScene.Instance();
|
||||
private bool IsChunkCached(Vector2 chunkIndex) {
|
||||
return _cachedWorldChunks.ContainsKey(chunkIndex);
|
||||
}
|
||||
|
||||
|
||||
private WorldChunk CreateWorldChunk(Vector2 chunkIndex, Color debugColor) {
|
||||
WorldChunk result = (WorldChunk)_worldChunkScene.Instance();
|
||||
result.SetSize(ChunkSize);
|
||||
Chunks.AddChild(result);
|
||||
result.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
result.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
|
||||
var offsetCoordSouthWest = new Vector2(xIndex, yIndex) * ChunkSize;
|
||||
var offsetCoordNorthEast = offsetCoordSouthWest + new Vector2(1, 1) * (ChunkSize - 1);
|
||||
result.SetSize(ChunkSize);
|
||||
result.InitializeTileInstances(chunkIndex, _tileMultiMeshInstance, _usedTileMeshInstances);
|
||||
_usedTileMeshInstances += result.Tiles.GetChildCount();
|
||||
|
||||
var planeCoordSouthWest = HexGrid.GetHexCenterFromOffset(offsetCoordSouthWest) +
|
||||
new Vector2(-HexGrid.HexSize.x, HexGrid.HexSize.y) * 0.5f;
|
||||
var planeCoordNorthEast = HexGrid.GetHexCenterFromOffset(offsetCoordNorthEast) +
|
||||
new Vector2(HexGrid.HexSize.x, -HexGrid.HexSize.y) * 0.5f;
|
||||
|
||||
result.ChunkIndex = new Vector2(xIndex, yIndex);
|
||||
result.PlaneRect = new Rect2(
|
||||
new Vector2(planeCoordSouthWest.x, planeCoordNorthEast.y),
|
||||
new Vector2(planeCoordNorthEast.x - planeCoordSouthWest.x, planeCoordSouthWest.y - planeCoordNorthEast.y));
|
||||
result.SetChunkIndex(chunkIndex, HexGrid);
|
||||
result.UpdateTileTransforms();
|
||||
|
||||
result.DebugColor = debugColor;
|
||||
result.DebugColor.a = 0.6f;
|
||||
|
||||
Chunks.AddChild(result);
|
||||
var chunkIndex = new Vector2(xIndex, yIndex);
|
||||
_cachedWorldChunks.Add(chunkIndex, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private bool IsColorEqualApprox(Color colorA, Color colorB)
|
||||
{
|
||||
var colorDifference = new Vector3(colorA.r - colorB.r, colorA.g - colorB.g, colorA.b - colorB.b);
|
||||
private bool IsColorEqualApprox(Color colorA, Color colorB) {
|
||||
Vector3 colorDifference = new(colorA.r - colorB.r, colorA.g - colorB.g, colorA.b - colorB.b);
|
||||
return colorDifference.LengthSquared() < 0.1 * 0.1;
|
||||
}
|
||||
|
||||
private Spatial SelectAsset(Vector2 offsetCoord, Array<Spatial> assets, Random randomGenerator, double probability)
|
||||
{
|
||||
if (randomGenerator.NextDouble() < 1.0 - probability) return null;
|
||||
private Spatial SelectAsset(Vector2 textureCoord, Array<Spatial> assets, Random randomGenerator,
|
||||
double probability) {
|
||||
if (randomGenerator.NextDouble() < 1.0 - probability) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var assetIndex = randomGenerator.Next(assets.Count);
|
||||
var assetInstance = (Spatial)assets[assetIndex].Duplicate();
|
||||
var assetTransform = Transform.Identity;
|
||||
assetTransform.origin = HexGrid.GetHexCenterVec3FromOffset(offsetCoord);
|
||||
int assetIndex = randomGenerator.Next(assets.Count);
|
||||
Spatial assetInstance = (Spatial)assets[assetIndex].Duplicate();
|
||||
Transform assetTransform = Transform.Identity;
|
||||
assetTransform.origin = HexGrid.GetHexCenterVec3FromOffset(textureCoord);
|
||||
// TODO: assetTransform.origin.y = GetHeightAtOffset(offsetCoord);
|
||||
assetTransform.origin.y = 0;
|
||||
assetTransform.basis =
|
||||
|
@ -193,41 +225,40 @@ public class World : Spatial
|
|||
return assetInstance;
|
||||
}
|
||||
|
||||
private void PopulateChunk(WorldChunk chunk)
|
||||
{
|
||||
var environmentRandom = new Random(Seed);
|
||||
private void PopulateChunk(WorldChunk chunk) {
|
||||
Random environmentRandom = new(Seed);
|
||||
|
||||
var tileTypeImage = chunk.TileTypeOffscreenViewport.GetTexture().GetData();
|
||||
tileTypeImage.Lock();
|
||||
chunk.CreateUnlockedTileTypeImage();
|
||||
|
||||
foreach (var textureCoordU in Enumerable.Range(0, chunk.Size))
|
||||
foreach (var textureCoordV in Enumerable.Range(0, chunk.Size))
|
||||
{
|
||||
var colorValue = tileTypeImage.GetPixel(textureCoordU, textureCoordV);
|
||||
var textureCoord = new Vector2(textureCoordU, textureCoordV);
|
||||
var offsetCoord = chunk.ChunkIndex * ChunkSize + textureCoord;
|
||||
foreach (int textureCoordU in Enumerable.Range(0, chunk.Size)) {
|
||||
foreach (int textureCoordV in Enumerable.Range(0, chunk.Size)) {
|
||||
Color colorValue = chunk.TileTypeImage.GetPixel(textureCoordU, textureCoordV);
|
||||
Vector2 textureCoord = new(textureCoordU, textureCoordV);
|
||||
Vector2 offsetCoord = chunk.ChunkIndex * ChunkSize + textureCoord;
|
||||
|
||||
if (IsColorEqualApprox(colorValue, RockColor))
|
||||
{
|
||||
var rockAsset = SelectAsset(offsetCoord, _rockAssets, environmentRandom, 0.15);
|
||||
if (rockAsset != null) chunk.Entities.AddChild(rockAsset);
|
||||
// TODO: MarkCellUnwalkable(cell);
|
||||
}
|
||||
else if (IsColorEqualApprox(colorValue, GrassColor) || IsColorEqualApprox(colorValue, DarkGrassColor))
|
||||
{
|
||||
var grassAsset = SelectAsset(offsetCoord, _grassAssets, environmentRandom, 0.15);
|
||||
if (grassAsset != null) chunk.Entities.AddChild(grassAsset);
|
||||
if (IsColorEqualApprox(colorValue, RockColor)) {
|
||||
Spatial rockAsset = SelectAsset(textureCoord, _rockAssets, environmentRandom, 0.15);
|
||||
if (rockAsset != null) {
|
||||
chunk.Entities.AddChild(rockAsset);
|
||||
MarkCellUnwalkable(HexGrid.GetHexAtOffset(offsetCoord));
|
||||
}
|
||||
} else if (IsColorEqualApprox(colorValue, GrassColor) ||
|
||||
IsColorEqualApprox(colorValue, DarkGrassColor)) {
|
||||
Spatial grassAsset = SelectAsset(textureCoord, _grassAssets, environmentRandom, 0.15);
|
||||
if (grassAsset != null) {
|
||||
chunk.Entities.AddChild(grassAsset);
|
||||
}
|
||||
|
||||
Tree treeAsset = SelectAsset(offsetCoord, _treeAssets, environmentRandom, 0.05) as Tree;
|
||||
if (treeAsset != null)
|
||||
{
|
||||
chunk.Entities.AddChild(treeAsset);
|
||||
treeAsset.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
||||
}
|
||||
Tree treeAsset = SelectAsset(textureCoord, _treeAssets, environmentRandom, 0.05) as Tree;
|
||||
if (treeAsset != null) {
|
||||
chunk.Entities.AddChild(treeAsset);
|
||||
treeAsset.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
||||
treeAsset.Connect("TreeChopped", this, nameof(OnBlockingSpatialRemoved));
|
||||
MarkCellUnwalkable(HexGrid.GetHexAtOffset(offsetCoord));
|
||||
}
|
||||
|
||||
|
||||
// TODO: MarkCellUnwalkable(cell);
|
||||
// else if (environmentRandom.NextDouble() < 0.01)
|
||||
// TODO: MarkCellUnwalkable(cell);
|
||||
// else if (environmentRandom.NextDouble() < 0.01)
|
||||
// {
|
||||
// var chestAsset = (Chest)_chestScene.Instance();
|
||||
// var assetTransform = Transform.Identity;
|
||||
|
@ -237,30 +268,25 @@ public class World : Spatial
|
|||
// Entities.AddChild(chestAsset);
|
||||
// MarkCellUnwalkable(cell);
|
||||
// }
|
||||
}
|
||||
}
|
||||
// else if (IsColorWater(colorValue))
|
||||
// {
|
||||
// MarkCellUnwalkable(cell);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
tileTypeImage.Unlock();
|
||||
}
|
||||
|
||||
public Vector2 WorldToOffsetCoords(Vector3 fromPositionWorld)
|
||||
{
|
||||
public Vector2 WorldToOffsetCoords(Vector3 fromPositionWorld) {
|
||||
return HexGrid.GetHexAt(new Vector2(fromPositionWorld.x, fromPositionWorld.z)).OffsetCoords;
|
||||
}
|
||||
|
||||
public Vector3 GetHexCenterFromOffset(Vector2 fromPositionOffset)
|
||||
{
|
||||
public Vector3 GetHexCenterFromOffset(Vector2 fromPositionOffset) {
|
||||
return HexGrid.GetHexCenterVec3FromOffset(fromPositionOffset);
|
||||
}
|
||||
|
||||
public void UpdateCenterChunkFromPlaneCoord(Vector2 planeCoord)
|
||||
{
|
||||
if (State != GenerationState.Done)
|
||||
{
|
||||
public void UpdateCenterChunkFromPlaneCoord(Vector2 planeCoord) {
|
||||
if (State != GenerationState.Done && State != GenerationState.Empty) {
|
||||
GD.PrintErr("Cannot update chunk to new planeCoord " + planeCoord + ": Chunk generation not yet finished!");
|
||||
return;
|
||||
}
|
||||
|
@ -269,105 +295,108 @@ public class World : Spatial
|
|||
Godot.Collections.Dictionary<Vector2, WorldChunk> oldCachedChunks = new(_cachedWorldChunks);
|
||||
|
||||
// set new center chunk
|
||||
var chunkIndex = GetChunkTupleFromPlaneCoord(planeCoord);
|
||||
CenterChunkIndex = new Vector2(chunkIndex.Item1, chunkIndex.Item2);
|
||||
CenterChunkIndex = GetChunkTupleFromPlaneCoord(planeCoord);
|
||||
|
||||
var currentChunk = GetOrCreateWorldChunk(chunkIndex.Item1, chunkIndex.Item2,
|
||||
WorldChunk currentChunk = GetOrCreateWorldChunk(CenterChunkIndex,
|
||||
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
|
||||
_centerChunkRect = currentChunk.PlaneRect;
|
||||
|
||||
_centerChunkRect = new Rect2(
|
||||
new Vector2(currentChunk.Transform.origin.x, currentChunk.Transform.origin.z)
|
||||
+ currentChunk.PlaneRect.Position,
|
||||
currentChunk.PlaneRect.Size);
|
||||
GD.Print("Center Chunk Rect: " + _centerChunkRect.Position + " size: " + _centerChunkRect.Size);
|
||||
|
||||
// load or create adjacent chunks
|
||||
_activeChunkIndices = new List<Vector2>();
|
||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1 - 1, chunkIndex.Item2 - 1));
|
||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1, chunkIndex.Item2 - 1));
|
||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1 + 1, chunkIndex.Item2 - 1));
|
||||
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(-1, -1));
|
||||
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(0, -1));
|
||||
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(1, -1));
|
||||
|
||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1 - 1, chunkIndex.Item2));
|
||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1, chunkIndex.Item2));
|
||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1 + 1, chunkIndex.Item2));
|
||||
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(-1, 0));
|
||||
_activeChunkIndices.Add(CenterChunkIndex);
|
||||
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(+1, 0));
|
||||
|
||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1 - 1, chunkIndex.Item2 + 1));
|
||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1, chunkIndex.Item2 + 1));
|
||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1 + 1, chunkIndex.Item2 + 1));
|
||||
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(-1, +1));
|
||||
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(0, +1));
|
||||
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(+1, +1));
|
||||
|
||||
// clear unused chunks
|
||||
_deactivatedWorldChunks.Clear();
|
||||
_addedChunkIndices.Clear();
|
||||
|
||||
foreach (Vector2 oldChunkIndex in oldCachedChunks.Keys) {
|
||||
if (!_activeChunkIndices.Contains(oldChunkIndex)) {
|
||||
DeactivateChunk(oldCachedChunks[oldChunkIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Vector2 activeChunkIndex in _activeChunkIndices) {
|
||||
WorldChunk chunk = GetOrCreateWorldChunk(activeChunkIndex,
|
||||
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
|
||||
_cachedWorldChunks[activeChunkIndex] = chunk;
|
||||
}
|
||||
|
||||
Debug.Assert(_activeChunkIndices.Count == NumChunkRows * NumChunkColumns);
|
||||
|
||||
foreach (var activeChunkIndex in _activeChunkIndices)
|
||||
GetOrCreateWorldChunk((int)activeChunkIndex.x, (int)activeChunkIndex.y,
|
||||
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
|
||||
|
||||
// unload retired chunks
|
||||
_removedChunkIndices.Clear();
|
||||
_addedChunkIndices.Clear();
|
||||
|
||||
foreach (var cachedChunkKey in oldCachedChunks.Keys)
|
||||
if (!_activeChunkIndices.Contains(cachedChunkKey))
|
||||
RemoveChunk(cachedChunkKey);
|
||||
|
||||
foreach (var chunkKey in _activeChunkIndices)
|
||||
if (!oldCachedChunks.ContainsKey(chunkKey))
|
||||
{
|
||||
_addedChunkIndices.Add(chunkKey);
|
||||
|
||||
var chunk = _cachedWorldChunks[chunkKey];
|
||||
GenerateChunkNoiseMap(chunk);
|
||||
|
||||
foreach (Vector2 chunkKey in _activeChunkIndices) {
|
||||
if (!oldCachedChunks.ContainsKey(chunkKey)) {
|
||||
ActivateChunk(_cachedWorldChunks[chunkKey], chunkKey);
|
||||
State = GenerationState.Heightmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateChunkNoiseMap(WorldChunk chunk)
|
||||
{
|
||||
var chunkIndex = chunk.ChunkIndex;
|
||||
private void ActivateChunk(WorldChunk chunk, Vector2 chunkIndex) {
|
||||
chunk.SetChunkIndex(chunkIndex, HexGrid);
|
||||
chunk.UpdateTileTransforms();
|
||||
|
||||
var debugChunkColor = new Color(Mathf.Abs(chunkIndex.x) / 5, Mathf.Abs(chunkIndex.y) / 5,
|
||||
Mathf.RoundToInt(Mathf.Abs(chunkIndex.x + chunkIndex.y)) % 2);
|
||||
_addedChunkIndices.Add(chunk.ChunkIndex);
|
||||
GenerateChunkNoiseMap(chunk);
|
||||
}
|
||||
|
||||
var noiseImageTexture = new ImageTexture();
|
||||
private void DeactivateChunk(WorldChunk chunk) {
|
||||
_cachedWorldChunks.Remove(chunk.ChunkIndex);
|
||||
chunk.ClearContent();
|
||||
_deactivatedWorldChunks.Add(chunk);
|
||||
}
|
||||
|
||||
private void GenerateChunkNoiseMap(WorldChunk chunk) {
|
||||
Vector2 chunkIndex = chunk.ChunkIndex;
|
||||
|
||||
ImageTexture noiseImageTexture = new();
|
||||
noiseImageTexture.CreateFromImage(_noiseGenerator.GetImage(ChunkSize, ChunkSize, chunkIndex * ChunkSize),
|
||||
0);
|
||||
|
||||
// Debug Texture
|
||||
var simpleImage = new Image();
|
||||
simpleImage.Create(ChunkSize, ChunkSize, false, Image.Format.Rgb8);
|
||||
simpleImage.Lock();
|
||||
|
||||
foreach (var i in Enumerable.Range(0, ChunkSize))
|
||||
foreach (var j in Enumerable.Range(0, ChunkSize))
|
||||
if ((i + j) % 2 == 0)
|
||||
simpleImage.SetPixelv(new Vector2(i, j), Colors.Aqua);
|
||||
else
|
||||
simpleImage.SetPixelv(new Vector2(i, j), debugChunkColor);
|
||||
|
||||
simpleImage.Unlock();
|
||||
// noiseImageTexture.CreateFromImage(simpleImage, 0);
|
||||
|
||||
chunk.SetNoisemap(noiseImageTexture);
|
||||
}
|
||||
|
||||
private void RemoveChunk(Vector2 cachedChunkKey)
|
||||
{
|
||||
private void RemoveChunk(Vector2 cachedChunkKey) {
|
||||
_cachedWorldChunks.Remove(cachedChunkKey);
|
||||
_removedChunkIndices.Add(cachedChunkKey);
|
||||
|
||||
foreach (WorldChunk chunk in Chunks.GetChildren())
|
||||
if (chunk.ChunkIndex == new Vector2(cachedChunkKey.x, cachedChunkKey.y))
|
||||
foreach (WorldChunk chunk in Chunks.GetChildren()) {
|
||||
if (chunk.ChunkIndex == new Vector2(cachedChunkKey.x, cachedChunkKey.y)) {
|
||||
chunk.QueueFree();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Tuple<int, int> GetChunkTupleFromPlaneCoord(Vector2 planeCoord)
|
||||
{
|
||||
var centerOffsetCoord = HexGrid.GetHexAt(planeCoord);
|
||||
var chunkIndexFloat = (centerOffsetCoord.OffsetCoords / ChunkSize).Floor();
|
||||
var chunkIndex = new Tuple<int, int>((int)chunkIndexFloat.x, (int)chunkIndexFloat.y);
|
||||
return chunkIndex;
|
||||
private Vector2 GetChunkTupleFromPlaneCoord(Vector2 planeCoord) {
|
||||
HexCell hexCell = HexGrid.GetHexAt(planeCoord);
|
||||
return GetChunkIndexFromOffsetCoord(hexCell.OffsetCoords);
|
||||
}
|
||||
|
||||
public void SetCenterPlaneCoord(Vector2 centerPlaneCoord)
|
||||
{
|
||||
if (!_centerChunkRect.HasPoint(centerPlaneCoord))
|
||||
{
|
||||
private Vector2 GetChunkIndexFromOffsetCoord(Vector2 offsetCoord) {
|
||||
return (offsetCoord / ChunkSize).Floor();
|
||||
}
|
||||
|
||||
public void SetCenterPlaneCoord(Vector2 centerPlaneCoord) {
|
||||
if (State != GenerationState.Done) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_centerChunkRect.HasPoint(centerPlaneCoord)) {
|
||||
UpdateCenterChunkFromPlaneCoord(centerPlaneCoord);
|
||||
|
||||
UpdateChunkBounds();
|
||||
|
@ -376,20 +405,18 @@ public class World : Spatial
|
|||
}
|
||||
}
|
||||
|
||||
private void UpdateWorldViewTexture()
|
||||
{
|
||||
var worldChunkSize = ChunkSize;
|
||||
var numWorldChunkRows = NumChunkRows;
|
||||
var numWorldChunkColumns = NumChunkColumns;
|
||||
private void UpdateWorldViewTexture() {
|
||||
int worldChunkSize = ChunkSize;
|
||||
int numWorldChunkRows = NumChunkRows;
|
||||
int numWorldChunkColumns = NumChunkColumns;
|
||||
|
||||
_heightmapImage.Create(worldChunkSize * numWorldChunkColumns, worldChunkSize * numWorldChunkRows, false,
|
||||
Image.Format.Rgba8);
|
||||
_tileTypeMapImage.Create(worldChunkSize * numWorldChunkColumns, worldChunkSize * numWorldChunkRows, false,
|
||||
Image.Format.Rgba8);
|
||||
|
||||
foreach (var chunkIndex in _activeChunkIndices)
|
||||
{
|
||||
var worldChunk = GetOrCreateWorldChunk((int)chunkIndex.x, (int)chunkIndex.y, Colors.White);
|
||||
foreach (Vector2 chunkIndex in _activeChunkIndices) {
|
||||
WorldChunk worldChunk = GetOrCreateWorldChunk(chunkIndex, Colors.White);
|
||||
|
||||
_heightmapImage.BlendRect(
|
||||
worldChunk.HeightmapOffscreenViewport.GetTexture().GetData(),
|
||||
|
@ -414,90 +441,287 @@ public class World : Spatial
|
|||
EmitSignal("OnHeightmapImageChanged", _heightmapImage);
|
||||
}
|
||||
|
||||
private void UpdateChunkBounds()
|
||||
{
|
||||
private void UpdateChunkBounds() {
|
||||
_chunkIndexSouthWest = Vector2.Inf;
|
||||
_chunkIndexNorthEast = -Vector2.Inf;
|
||||
|
||||
foreach (var chunkIndex in _activeChunkIndices)
|
||||
{
|
||||
var worldChunk = GetOrCreateWorldChunk((int)chunkIndex.x, (int)chunkIndex.y, Colors.White);
|
||||
|
||||
if (chunkIndex.x <= _chunkIndexSouthWest.x && chunkIndex.y <= _chunkIndexSouthWest.y)
|
||||
foreach (Vector2 chunkIndex in _activeChunkIndices) {
|
||||
if (chunkIndex.x <= _chunkIndexSouthWest.x && chunkIndex.y <= _chunkIndexSouthWest.y) {
|
||||
_chunkIndexSouthWest = chunkIndex;
|
||||
else if (chunkIndex.x >= _chunkIndexNorthEast.x && chunkIndex.y >= _chunkIndexNorthEast.y)
|
||||
} else if (chunkIndex.x >= _chunkIndexNorthEast.x && chunkIndex.y >= _chunkIndexNorthEast.y) {
|
||||
_chunkIndexNorthEast = chunkIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateNavigationBounds()
|
||||
{
|
||||
var cellSouthWest = HexGrid.GetHexAtOffset(_chunkIndexSouthWest * ChunkSize);
|
||||
// Chunks have their cells ordered from south west (0,0) to north east (ChunkSize, ChunkSize). For the
|
||||
// north east cell we have to add the chunk size to get to the actual corner cell.
|
||||
var cellNorthEast = HexGrid.GetHexAtOffset(_chunkIndexNorthEast * ChunkSize + Vector2.One * (ChunkSize - 1));
|
||||
|
||||
var centerCell =
|
||||
HexGrid.GetHexAtOffset(((cellNorthEast.OffsetCoords - cellSouthWest.OffsetCoords) / 2).Round());
|
||||
var numCells = ChunkSize * Math.Max(NumChunkColumns, NumChunkRows);
|
||||
|
||||
private void UpdateNavigationBounds() {
|
||||
HexCell cellSouthWest = HexGrid.GetHexAtOffset(_chunkIndexSouthWest * ChunkSize);
|
||||
HexGrid.SetBoundsOffset(cellSouthWest, ChunkSize * new Vector2(NumChunkColumns, NumChunkRows));
|
||||
}
|
||||
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
var oldState = State;
|
||||
public void MarkCellUnwalkable(HexCell cell) {
|
||||
HexGrid.AddObstacle(cell);
|
||||
}
|
||||
|
||||
public float GetHexCost(Entity entity, HexCell cell) {
|
||||
float nextHexCost = HexGrid.GetHexCost(cell);
|
||||
if (nextHexCost != 0) {
|
||||
Vector2 nextOffset = cell.OffsetCoords;
|
||||
Vector2 chunkIndex = GetChunkIndexFromOffsetCoord(nextOffset);
|
||||
|
||||
if (!_cachedWorldChunks.ContainsKey(chunkIndex)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
||||
Vector2 textureCoordinate = nextOffset - Vector2.One * ChunkSize * chunkIndex;
|
||||
|
||||
Color tileTypeColor = chunk.TileTypeImage.GetPixel((int)textureCoordinate.x, (int)textureCoordinate.y);
|
||||
if (!IsColorEqualApprox(tileTypeColor, GrassColor) &&
|
||||
!IsColorEqualApprox(tileTypeColor, DarkGrassColor)) {
|
||||
nextHexCost = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return nextHexCost;
|
||||
}
|
||||
|
||||
public float GetMoveCost(Entity entity, HexCell currentHex, HexCell nextHex) {
|
||||
if (GetHexCost(entity, nextHex) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return HexGrid.GetMoveCost(currentHex.AxialCoords,
|
||||
new HexCell(nextHex.AxialCoords - currentHex.AxialCoords).CubeCoords);
|
||||
}
|
||||
|
||||
public List<HexCell> FindPath(Entity entity, HexCell startHex, HexCell goalHex) {
|
||||
if (State != GenerationState.Done) {
|
||||
return new List<HexCell>();
|
||||
}
|
||||
|
||||
Vector2 goalAxialCoords = goalHex.AxialCoords;
|
||||
|
||||
SimplePriorityQueue<Vector2, float> frontier = new();
|
||||
frontier.Enqueue(startHex.AxialCoords, 0);
|
||||
System.Collections.Generic.Dictionary<Vector2, Vector2> cameFrom = new();
|
||||
System.Collections.Generic.Dictionary<Vector2, float> costSoFar = new();
|
||||
|
||||
cameFrom.Add(startHex.AxialCoords, startHex.AxialCoords);
|
||||
costSoFar.Add(startHex.AxialCoords, 0);
|
||||
|
||||
int FindPathCheckedCellCount = 0;
|
||||
|
||||
while (frontier.Any()) {
|
||||
FindPathCheckedCellCount++;
|
||||
HexCell currentHex = new(frontier.Dequeue());
|
||||
Vector2 currentAxial = currentHex.AxialCoords;
|
||||
|
||||
if (currentHex == goalHex) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (HexCell nextHex in currentHex.GetAllAdjacent()) {
|
||||
Vector2 nextAxial = nextHex.AxialCoords;
|
||||
|
||||
float moveCost = GetMoveCost(entity, currentHex, nextHex);
|
||||
|
||||
if (nextHex == goalHex && moveCost == 0 && GetHexCost(entity, nextHex) == 0) {
|
||||
// Goal ist an obstacle
|
||||
cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
|
||||
frontier.Clear();
|
||||
break;
|
||||
}
|
||||
|
||||
if (moveCost == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
moveCost += costSoFar[currentHex.AxialCoords];
|
||||
if (!costSoFar.ContainsKey(nextHex.AxialCoords) || moveCost < costSoFar[nextHex.AxialCoords]) {
|
||||
costSoFar[nextHex.AxialCoords] = moveCost;
|
||||
float priority = moveCost + nextHex.DistanceTo(goalHex);
|
||||
|
||||
frontier.Enqueue(nextHex.AxialCoords, priority);
|
||||
cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GD.Print("Checked Cell Count: " + FindPathCheckedCellCount);
|
||||
|
||||
List<HexCell> result = new();
|
||||
if (!cameFrom.ContainsKey(goalHex.AxialCoords)) {
|
||||
GD.Print("Failed to find path from " + startHex + " to " + goalHex);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (HexGrid.GetHexCost(goalAxialCoords) != 0) {
|
||||
result.Add(goalHex);
|
||||
}
|
||||
|
||||
HexCell pathHex = goalHex;
|
||||
while (pathHex != startHex) {
|
||||
pathHex = new HexCell(cameFrom[pathHex.AxialCoords]);
|
||||
result.Insert(0, pathHex);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool CheckSweptTriangleCellCollision(Entity entity, Vector3 startWorld, Vector3 endWorld, float radius) {
|
||||
Vector2 startPlane = new(startWorld.x, startWorld.z);
|
||||
Vector2 endPlane = new(endWorld.x, endWorld.z);
|
||||
Vector2 directionPlane = (endPlane - startPlane).Normalized();
|
||||
Vector2 sidePlane = directionPlane.Rotated(Mathf.Pi * 0.5f);
|
||||
|
||||
List<HexCell> cells =
|
||||
HexGrid.GetCellsForLine(startPlane + directionPlane * radius, endPlane + directionPlane * radius);
|
||||
foreach (HexCell cell in cells) {
|
||||
if (GetHexCost(entity, cell) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
cells = HexGrid.GetCellsForLine(startPlane + sidePlane * radius, endPlane + sidePlane * radius);
|
||||
foreach (HexCell cell in cells) {
|
||||
if (GetHexCost(entity, cell) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
cells = HexGrid.GetCellsForLine(startPlane - sidePlane * radius, endPlane - sidePlane * radius);
|
||||
foreach (HexCell cell in cells) {
|
||||
if (GetHexCost(entity, cell) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<NavigationPoint> SmoothPath(Entity entity, List<NavigationPoint> navigationPoints) {
|
||||
if (navigationPoints.Count <= 2) {
|
||||
return navigationPoints;
|
||||
}
|
||||
|
||||
Vector3 bodyGlobalTranslation = entity.GlobalTranslation;
|
||||
List<NavigationPoint> smoothedPath = new();
|
||||
|
||||
int startIndex = 0;
|
||||
int endIndex = navigationPoints.Count > 1 ? 1 : 0;
|
||||
smoothedPath.Add(navigationPoints[startIndex]);
|
||||
Vector3 startPoint = navigationPoints[startIndex].WorldPosition;
|
||||
|
||||
while (endIndex != navigationPoints.Count) {
|
||||
Vector3 endPoint = navigationPoints[endIndex].WorldPosition;
|
||||
|
||||
if (CheckSweptTriangleCellCollision(entity, startPoint, endPoint, 0.27f)) {
|
||||
if (endIndex - startIndex == 1) {
|
||||
GD.Print("Aborting SmoothPath: input path passes through collision geometry.");
|
||||
entity.GlobalTranslation = bodyGlobalTranslation;
|
||||
return smoothedPath;
|
||||
}
|
||||
|
||||
smoothedPath.Add(navigationPoints[endIndex - 1]);
|
||||
startIndex = endIndex - 1;
|
||||
startPoint = navigationPoints[startIndex].WorldPosition;
|
||||
entity.GlobalTranslation = startPoint;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (endIndex == navigationPoints.Count - 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
endIndex += 1;
|
||||
}
|
||||
|
||||
smoothedPath.Add(navigationPoints[endIndex]);
|
||||
entity.GlobalTranslation = bodyGlobalTranslation;
|
||||
|
||||
return smoothedPath;
|
||||
}
|
||||
|
||||
public override void _Process(float delta) {
|
||||
GenerationState oldState = State;
|
||||
|
||||
UpdateGenerationState();
|
||||
|
||||
if (oldState != GenerationState.Done && State == GenerationState.Done)
|
||||
{
|
||||
if (oldState != GenerationState.Done && State == GenerationState.Done) {
|
||||
UpdateWorldViewTexture();
|
||||
}
|
||||
|
||||
EmitSignal("OnTilesChanged", _removedChunkIndices.ToArray(), _addedChunkIndices.ToArray());
|
||||
while (_removedSpatialNodes.Count > 0) {
|
||||
GD.Print("Queueing deletion of " + _removedSpatialNodes[0]);
|
||||
_removedSpatialNodes[0].QueueFree();
|
||||
_removedSpatialNodes.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateGenerationState()
|
||||
{
|
||||
if (State == GenerationState.Heightmap)
|
||||
{
|
||||
var numChunksGeneratingHeightmap = 0;
|
||||
foreach (var chunkIndex in _addedChunkIndices)
|
||||
{
|
||||
var chunk = _cachedWorldChunks[chunkIndex];
|
||||
if (chunk.HeightMapFrameCount > 0) numChunksGeneratingHeightmap++;
|
||||
private void UpdateGenerationState() {
|
||||
if (State == GenerationState.Heightmap) {
|
||||
int numChunksGeneratingHeightmap = 0;
|
||||
foreach (Vector2 chunkIndex in _addedChunkIndices) {
|
||||
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
||||
if (chunk.HeightMapFrameCount > 0) {
|
||||
numChunksGeneratingHeightmap++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numChunksGeneratingHeightmap == 0)
|
||||
{
|
||||
if (numChunksGeneratingHeightmap == 0) {
|
||||
// assign height map images
|
||||
foreach (var chunkIndex in _addedChunkIndices)
|
||||
{
|
||||
var chunk = _cachedWorldChunks[chunkIndex];
|
||||
foreach (Vector2 chunkIndex in _addedChunkIndices) {
|
||||
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
||||
chunk.SetHeightmap(chunk.HeightmapOffscreenViewport.GetTexture());
|
||||
}
|
||||
|
||||
State = GenerationState.TileType;
|
||||
}
|
||||
}
|
||||
else if (State == GenerationState.TileType)
|
||||
{
|
||||
var numChunksGeneratingTileType = 0;
|
||||
foreach (var chunkIndex in _addedChunkIndices)
|
||||
{
|
||||
var chunk = _cachedWorldChunks[chunkIndex];
|
||||
if (chunk.TileTypeMapFrameCount > 0) numChunksGeneratingTileType++;
|
||||
} else if (State == GenerationState.TileType) {
|
||||
int numChunksGeneratingTileType = 0;
|
||||
foreach (Vector2 chunkIndex in _addedChunkIndices) {
|
||||
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
||||
if (chunk.TileTypeMapFrameCount > 0) {
|
||||
numChunksGeneratingTileType++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numChunksGeneratingTileType == 0) State = GenerationState.Objects;
|
||||
}
|
||||
else if (State == GenerationState.Objects)
|
||||
{
|
||||
if (numChunksGeneratingTileType == 0) {
|
||||
State = GenerationState.Objects;
|
||||
}
|
||||
} else if (State == GenerationState.Objects) {
|
||||
// generate objects
|
||||
foreach (var chunkIndex in _addedChunkIndices) PopulateChunk(_cachedWorldChunks[chunkIndex]);
|
||||
foreach (Vector2 chunkIndex in _addedChunkIndices) {
|
||||
PopulateChunk(_cachedWorldChunks[chunkIndex]);
|
||||
}
|
||||
|
||||
_addedChunkIndices.Clear();
|
||||
|
||||
State = GenerationState.Done;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEntityClicked(Entity entity) {
|
||||
EmitSignal("EntityClicked", entity);
|
||||
}
|
||||
|
||||
public void OnTileClicked(HexTile3D tile) {
|
||||
EmitSignal("TileClicked", tile);
|
||||
}
|
||||
|
||||
public void OnTileHovered(HexTile3D tile) {
|
||||
EmitSignal("TileHovered", tile);
|
||||
}
|
||||
|
||||
public void OnBlockingSpatialRemoved(Spatial spatialNode) {
|
||||
if (spatialNode.IsQueuedForDeletion()) {
|
||||
return;
|
||||
}
|
||||
|
||||
HexGrid.RemoveObstacle(HexGrid.GetHexAt(new Vector2(spatialNode.GlobalTranslation.x,
|
||||
spatialNode.GlobalTranslation.z)));
|
||||
_removedSpatialNodes.Add(spatialNode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
[gd_scene load_steps=10 format=2]
|
||||
|
||||
[ext_resource path="res://scenes/World.cs" type="Script" id=1]
|
||||
[ext_resource path="res://entities/rockA.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://assets/Environment/HexTileMesh.tres" type="CylinderMesh" id=3]
|
||||
[ext_resource path="res://entities/Tree.cs" type="Script" id=4]
|
||||
[ext_resource path="res://entities/rockC.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://assets/Environment/grassLarge.tscn" type="PackedScene" id=6]
|
||||
[ext_resource path="res://entities/rockB.tscn" type="PackedScene" id=7]
|
||||
[ext_resource path="res://entities/Tree.tscn" type="PackedScene" id=8]
|
||||
|
||||
[sub_resource type="MultiMesh" id=27]
|
||||
color_format = 1
|
||||
transform_format = 1
|
||||
custom_data_format = 1
|
||||
visible_instance_count = 0
|
||||
mesh = ExtResource( 3 )
|
||||
|
||||
[node name="World" type="Spatial"]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Chunks" type="Spatial" parent="."]
|
||||
|
||||
[node name="TileMultiMeshInstance" type="MultiMeshInstance" parent="."]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -2.5, 0 )
|
||||
multimesh = SubResource( 27 )
|
||||
|
||||
[node name="Assets" type="Spatial" parent="."]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -5, 0 )
|
||||
visible = false
|
||||
|
||||
[node name="Rocks" type="Spatial" parent="Assets"]
|
||||
|
||||
[node name="rockA" type="StaticBody" parent="Assets/Rocks" instance=ExtResource( 2 )]
|
||||
input_ray_pickable = false
|
||||
|
||||
[node name="rockB" type="StaticBody" parent="Assets/Rocks" instance=ExtResource( 7 )]
|
||||
input_ray_pickable = false
|
||||
|
||||
[node name="rockC" type="StaticBody" parent="Assets/Rocks" instance=ExtResource( 5 )]
|
||||
input_ray_pickable = false
|
||||
|
||||
[node name="Grass" type="Spatial" parent="Assets"]
|
||||
|
||||
[node name="grassLarge" type="Spatial" parent="Assets/Grass" groups=["GameGeometry"] instance=ExtResource( 6 )]
|
||||
|
||||
[node name="Trees" type="Spatial" parent="Assets"]
|
||||
|
||||
[node name="tree" type="StaticBody" parent="Assets/Trees" instance=ExtResource( 8 )]
|
||||
script = ExtResource( 4 )
|
|
@ -1,9 +1,13 @@
|
|||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
public class WorldChunk : Spatial {
|
||||
private readonly PackedScene _hexTile3DScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
||||
private MultiMeshInstance _multiMeshInstance;
|
||||
private readonly Array<int> _tileInstanceIndices = new();
|
||||
|
||||
public class WorldChunk : Spatial
|
||||
{
|
||||
private readonly SpatialMaterial _rectMaterial = new();
|
||||
private Sprite _heightmapSprite;
|
||||
private TextureRect _heightmapTextureRect;
|
||||
|
@ -11,27 +15,39 @@ public class WorldChunk : Spatial
|
|||
|
||||
private Sprite _noiseSprite;
|
||||
private bool _showTextureOverlay;
|
||||
|
||||
[Export] public Vector2 ChunkIndex;
|
||||
|
||||
public Color DebugColor = Colors.White;
|
||||
[Export] public Spatial Entities;
|
||||
public Spatial Entities;
|
||||
public Spatial Tiles;
|
||||
private readonly HexGrid _hexGrid = new();
|
||||
private readonly bool _showHexTiles;
|
||||
|
||||
[Export] public Texture HeightMap;
|
||||
public int HeightMapFrameCount;
|
||||
|
||||
public Image TileTypeImage;
|
||||
public Viewport HeightmapOffscreenViewport;
|
||||
[Export] public Texture NavigationMap;
|
||||
|
||||
public bool NoiseTextureCheckerboardOverlay = true;
|
||||
|
||||
// signals
|
||||
// delegate void OnCoordClicked(Vector2 world_pos);
|
||||
[Signal]
|
||||
private delegate void TileClicked(HexTile3D tile3d);
|
||||
|
||||
[Signal]
|
||||
private delegate void TileHovered(HexTile3D tile3d);
|
||||
|
||||
// other members
|
||||
public Rect2 PlaneRect;
|
||||
|
||||
// ui elements
|
||||
|
||||
// scene nodes
|
||||
private MeshInstance PlaneRectMesh;
|
||||
[Export] public int Size = 32;
|
||||
public int Size = 32;
|
||||
|
||||
// resources
|
||||
|
||||
|
@ -40,34 +56,26 @@ public class WorldChunk : Spatial
|
|||
public int TileTypeMapFrameCount;
|
||||
public Viewport TileTypeOffscreenViewport;
|
||||
|
||||
public WorldChunk()
|
||||
{
|
||||
}
|
||||
|
||||
public WorldChunk(int size)
|
||||
{
|
||||
SetSize(size);
|
||||
}
|
||||
|
||||
[Export]
|
||||
public bool ShowTextureOverlay
|
||||
{
|
||||
public bool ShowTextureOverlay {
|
||||
get => _showTextureOverlay;
|
||||
|
||||
set
|
||||
{
|
||||
if (PlaneRectMesh != null) PlaneRectMesh.Visible = value;
|
||||
set {
|
||||
if (PlaneRectMesh != null) {
|
||||
PlaneRectMesh.Visible = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
PlaneRectMesh = (MeshInstance)FindNode("PlaneRectMesh");
|
||||
Debug.Assert(PlaneRectMesh != null);
|
||||
if (PlaneRectMesh.Visible) _showTextureOverlay = true;
|
||||
if (PlaneRectMesh.Visible) {
|
||||
_showTextureOverlay = true;
|
||||
}
|
||||
|
||||
var planeRectTransform = Transform.Identity;
|
||||
Transform planeRectTransform = Transform.Identity;
|
||||
planeRectTransform =
|
||||
planeRectTransform.Scaled(new Vector3(PlaneRect.Size.x, 0.125f, PlaneRect.Size.y));
|
||||
planeRectTransform.origin.x = PlaneRect.GetCenter().x;
|
||||
|
@ -94,15 +102,14 @@ public class WorldChunk : Spatial
|
|||
Entities = (Spatial)FindNode("Entities");
|
||||
Debug.Assert(Entities != null);
|
||||
|
||||
SetSize(World.ChunkSize);
|
||||
Tiles = (Spatial)FindNode("Tiles");
|
||||
Debug.Assert(Tiles != null);
|
||||
}
|
||||
|
||||
public void SetSize(int size)
|
||||
{
|
||||
public void SetSize(int size) {
|
||||
Size = size;
|
||||
|
||||
if (TileTypeOffscreenViewport != null)
|
||||
{
|
||||
if (TileTypeOffscreenViewport != null) {
|
||||
TileTypeOffscreenViewport.Size = Vector2.One * size;
|
||||
HeightmapOffscreenViewport.Size = Vector2.One * size;
|
||||
_noiseMask.Transform = Transform2D.Identity.Scaled(Vector2.One * size / _noiseMask.Texture.GetSize().x);
|
||||
|
@ -112,10 +119,95 @@ public class WorldChunk : Spatial
|
|||
}
|
||||
}
|
||||
|
||||
public void SetChunkIndex(Vector2 chunkIndex, HexGrid hexGrid) {
|
||||
ChunkIndex = chunkIndex;
|
||||
float chunkSize = Size;
|
||||
|
||||
Vector2 planeCoordSouthWest = hexGrid.GetHexCenterFromOffset(chunkIndex * chunkSize);
|
||||
|
||||
Transform = new Transform(Basis.Identity, new Vector3(planeCoordSouthWest.x, 0, planeCoordSouthWest.y));
|
||||
|
||||
Vector2 localPlaneCoordSouthWest = new Vector2(-hexGrid.HexSize.x, hexGrid.HexSize.y) * 0.5f;
|
||||
Vector2 localPlaneCoordNorthEast = hexGrid.GetHexCenterFromOffset(Vector2.One * chunkSize) +
|
||||
new Vector2(hexGrid.HexSize.x, -hexGrid.HexSize.y) * 0.5f;
|
||||
|
||||
PlaneRect = new Rect2(
|
||||
new Vector2(localPlaneCoordSouthWest.x, localPlaneCoordNorthEast.y),
|
||||
new Vector2(localPlaneCoordNorthEast.x - localPlaneCoordSouthWest.x,
|
||||
localPlaneCoordSouthWest.y - localPlaneCoordNorthEast.y)
|
||||
);
|
||||
}
|
||||
|
||||
public void InitializeTileInstances(Vector2 chunkIndex, MultiMeshInstance multiMeshInstance,
|
||||
int tileInstanceIndexStart) {
|
||||
_multiMeshInstance = multiMeshInstance;
|
||||
_tileInstanceIndices.Clear();
|
||||
|
||||
int chunkSize = Size;
|
||||
|
||||
foreach (Spatial node in Tiles.GetChildren()) {
|
||||
node.QueueFree();
|
||||
}
|
||||
|
||||
foreach (int i in Enumerable.Range(0, chunkSize)) {
|
||||
foreach (int j in Enumerable.Range(0, chunkSize)) {
|
||||
HexTile3D tile3D = (HexTile3D)_hexTile3DScene.Instance();
|
||||
tile3D.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
tile3D.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
|
||||
tile3D.Cell.OffsetCoords = new Vector2(chunkIndex * chunkSize + new Vector2(i, j));
|
||||
_tileInstanceIndices.Add(tileInstanceIndexStart + _tileInstanceIndices.Count);
|
||||
|
||||
Transform tileTransform = Transform.Identity;
|
||||
Vector2 centerPlaneCoord = _hexGrid.GetHexCenterFromOffset(new Vector2(i, j));
|
||||
tileTransform.origin = new Vector3(centerPlaneCoord.x, 0, centerPlaneCoord.y);
|
||||
tile3D.Transform = tileTransform;
|
||||
|
||||
Tiles.AddChild(tile3D);
|
||||
}
|
||||
}
|
||||
|
||||
_multiMeshInstance.Multimesh.VisibleInstanceCount = _multiMeshInstance.Multimesh.InstanceCount;
|
||||
|
||||
GD.Print("Chunk: " + chunkIndex + " Last index: " + _tileInstanceIndices.Last());
|
||||
}
|
||||
|
||||
public void ClearContent() {
|
||||
foreach (Spatial child in Entities.GetChildren()) {
|
||||
child.QueueFree();
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTileTransforms() {
|
||||
Transform chunkTransform = Transform.Identity;
|
||||
Vector2 chunkOriginPlaneCoord = _hexGrid.GetHexCenterFromOffset(ChunkIndex * Size);
|
||||
chunkTransform.origin = new Vector3(chunkOriginPlaneCoord.x, 0, chunkOriginPlaneCoord.y);
|
||||
Transform = chunkTransform;
|
||||
|
||||
Basis tileOrientation = new(Vector3.Up, 90f * Mathf.Pi / 180f);
|
||||
|
||||
foreach (int i in Enumerable.Range(0, _tileInstanceIndices.Count)) {
|
||||
int column = i % Size;
|
||||
int row = i / Size;
|
||||
|
||||
Vector2 tilePlaneCoord =
|
||||
_hexGrid.GetHexCenterFromOffset(new Vector2(column, row));
|
||||
|
||||
Transform hexTransform = new(tileOrientation,
|
||||
chunkTransform.origin + new Vector3(tilePlaneCoord.x, 0, tilePlaneCoord.y));
|
||||
|
||||
if (_showHexTiles) {
|
||||
hexTransform = new Transform(tileOrientation.Scaled(Vector3.One * 0.95f),
|
||||
hexTransform.origin);
|
||||
}
|
||||
|
||||
_multiMeshInstance.Multimesh.SetInstanceTransform(_tileInstanceIndices[i], hexTransform);
|
||||
}
|
||||
}
|
||||
|
||||
// other members
|
||||
public void SaveToFile(string chunkName)
|
||||
{
|
||||
var image = new Image();
|
||||
public void SaveToFile(string chunkName) {
|
||||
Image image = new();
|
||||
|
||||
image.CreateFromData(Size, Size, false, Image.Format.Rgba8, TileTypeMap.GetData().GetData());
|
||||
image.SavePng(chunkName + "_tileType.png");
|
||||
|
@ -127,13 +219,10 @@ public class WorldChunk : Spatial
|
|||
image.SavePng(chunkName + "_heightMap.png");
|
||||
}
|
||||
|
||||
public void LoadFromFile(string chunkName)
|
||||
{
|
||||
}
|
||||
public void LoadFromFile(string chunkName) { }
|
||||
|
||||
|
||||
public void SetNoisemap(Texture texture)
|
||||
{
|
||||
public void SetNoisemap(Texture texture) {
|
||||
_noiseSprite.Texture = texture;
|
||||
_noiseSprite.Transform =
|
||||
Transform2D.Identity.Scaled(HeightmapOffscreenViewport.Size / _noiseSprite.Texture.GetSize().x);
|
||||
|
@ -141,8 +230,7 @@ public class WorldChunk : Spatial
|
|||
HeightMapFrameCount = 1;
|
||||
}
|
||||
|
||||
public void SetHeightmap(Texture texture)
|
||||
{
|
||||
public void SetHeightmap(Texture texture) {
|
||||
_heightmapSprite.Texture = texture;
|
||||
_heightmapSprite.Transform =
|
||||
Transform2D.Identity.Scaled(TileTypeOffscreenViewport.Size / _heightmapSprite.Texture.GetSize());
|
||||
|
@ -151,29 +239,33 @@ public class WorldChunk : Spatial
|
|||
TileTypeMapFrameCount = 1;
|
||||
}
|
||||
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
public void CreateUnlockedTileTypeImage() {
|
||||
TileTypeImage = TileTypeOffscreenViewport.GetTexture().GetData();
|
||||
TileTypeImage.Lock();
|
||||
}
|
||||
|
||||
public override void _Process(float delta) {
|
||||
Texture tileTypeTexture = TileTypeOffscreenViewport.GetTexture();
|
||||
|
||||
if (NoiseTextureCheckerboardOverlay)
|
||||
{
|
||||
var tileTypeImage = tileTypeTexture.GetData();
|
||||
if (NoiseTextureCheckerboardOverlay) {
|
||||
Image tileTypeImage = tileTypeTexture.GetData();
|
||||
tileTypeImage.Lock();
|
||||
|
||||
foreach (var i in Enumerable.Range(0, Size))
|
||||
foreach (var j in Enumerable.Range(0, Size))
|
||||
{
|
||||
var textureCoord = new Vector2(i, j);
|
||||
var baseColor = tileTypeImage.GetPixelv(textureCoord);
|
||||
foreach (int i in Enumerable.Range(0, Size)) {
|
||||
foreach (int j in Enumerable.Range(0, Size)) {
|
||||
Vector2 textureCoord = new(i, j);
|
||||
Color baseColor = tileTypeImage.GetPixelv(textureCoord);
|
||||
|
||||
if ((i + j) % 2 == 0)
|
||||
tileTypeImage.SetPixelv(textureCoord, baseColor);
|
||||
else
|
||||
tileTypeImage.SetPixelv(textureCoord, baseColor * 0.6f);
|
||||
if ((i + j) % 2 == 0) {
|
||||
tileTypeImage.SetPixelv(textureCoord, baseColor);
|
||||
} else {
|
||||
tileTypeImage.SetPixelv(textureCoord, baseColor * 0.6f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tileTypeImage.Unlock();
|
||||
var imageTexture = new ImageTexture();
|
||||
ImageTexture imageTexture = new();
|
||||
imageTexture.CreateFromImage(tileTypeImage, 0);
|
||||
tileTypeTexture = imageTexture;
|
||||
}
|
||||
|
@ -188,14 +280,26 @@ public class WorldChunk : Spatial
|
|||
//RectMaterial.Uv1Triplanar = true;
|
||||
PlaneRectMesh.SetSurfaceMaterial(0, _rectMaterial);
|
||||
|
||||
if (HeightMapFrameCount == 0) HeightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
||||
if (HeightMapFrameCount == 0) {
|
||||
HeightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
||||
}
|
||||
|
||||
HeightMapFrameCount = HeightMapFrameCount > 0 ? HeightMapFrameCount - 1 : 0;
|
||||
|
||||
if (TileTypeMapFrameCount == 0) TileTypeOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
||||
if (TileTypeMapFrameCount == 0) {
|
||||
TileTypeOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
||||
}
|
||||
|
||||
TileTypeMapFrameCount = TileTypeMapFrameCount > 0 ? TileTypeMapFrameCount - 1 : 0;
|
||||
|
||||
PlaneRectMesh.MaterialOverride = null;
|
||||
}
|
||||
|
||||
public void OnTileClicked(HexTile3D tile) {
|
||||
EmitSignal("TileClicked", tile);
|
||||
}
|
||||
|
||||
public void OnTileHovered(HexTile3D tile) {
|
||||
EmitSignal("TileHovered", tile);
|
||||
}
|
||||
}
|
|
@ -24,6 +24,8 @@ blend_mode = 3
|
|||
[node name="WorldChunk" type="Spatial"]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Tiles" type="Spatial" parent="."]
|
||||
|
||||
[node name="Entities" type="Spatial" parent="."]
|
||||
|
||||
[node name="PlaneRectMesh" type="MeshInstance" parent="."]
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
public class EditorUI : Control
|
||||
{
|
||||
public enum InputMode
|
||||
{
|
||||
public class EditorUI : Control {
|
||||
public enum InputMode {
|
||||
None,
|
||||
Grass,
|
||||
Sand,
|
||||
|
@ -35,8 +34,7 @@ public class EditorUI : Control
|
|||
public Vector2 currentTileOffset = Vector2.Zero;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_tileMaterial = GD.Load<ShaderMaterial>("materials/HexTileTextureLookup.tres");
|
||||
|
||||
// signals
|
||||
|
@ -69,74 +67,65 @@ public class EditorUI : Control
|
|||
}
|
||||
|
||||
|
||||
public void OnResetButton()
|
||||
{
|
||||
public void OnResetButton() {
|
||||
GD.Print("Resetting Map");
|
||||
_tileWorld.Seed = _tileWorld.Seed + 1;
|
||||
_tileWorld.Generate(24);
|
||||
}
|
||||
|
||||
public void OnGrassButton()
|
||||
{
|
||||
public void OnGrassButton() {
|
||||
CurrentInputMode = InputMode.Grass;
|
||||
}
|
||||
|
||||
public void OnSandButton()
|
||||
{
|
||||
public void OnSandButton() {
|
||||
CurrentInputMode = InputMode.Sand;
|
||||
}
|
||||
|
||||
public void OnWaterButton()
|
||||
{
|
||||
public void OnWaterButton() {
|
||||
CurrentInputMode = InputMode.Water;
|
||||
}
|
||||
|
||||
public void OnObstacleButton()
|
||||
{
|
||||
public void OnObstacleButton() {
|
||||
CurrentInputMode = InputMode.Obstacle;
|
||||
}
|
||||
|
||||
public void OnNavigateButton()
|
||||
{
|
||||
public void OnNavigateButton() {
|
||||
CurrentInputMode = InputMode.Navigate;
|
||||
}
|
||||
|
||||
public void OnGameGeometryCheckBoxToggled(bool pressed)
|
||||
{
|
||||
var gameGeometries = GetTree().GetNodesInGroup("GameGeometry");
|
||||
foreach (Spatial mesh in gameGeometries)
|
||||
if (mesh != null)
|
||||
public void OnGameGeometryCheckBoxToggled(bool pressed) {
|
||||
Array gameGeometries = GetTree().GetNodesInGroup("GameGeometry");
|
||||
foreach (Spatial mesh in gameGeometries) {
|
||||
if (mesh != null) {
|
||||
mesh.Visible = pressed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnPhysicsGeometryCheckBoxToggled(bool pressed)
|
||||
{
|
||||
var physicsGeometries = GetTree().GetNodesInGroup("PhysicsGeometry");
|
||||
foreach (Spatial mesh in physicsGeometries)
|
||||
if (mesh != null)
|
||||
public void OnPhysicsGeometryCheckBoxToggled(bool pressed) {
|
||||
Array physicsGeometries = GetTree().GetNodesInGroup("PhysicsGeometry");
|
||||
foreach (Spatial mesh in physicsGeometries) {
|
||||
if (mesh != null) {
|
||||
mesh.Visible = pressed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnNavigationGeometryCheckBoxToggled(bool pressed)
|
||||
{
|
||||
public void OnNavigationGeometryCheckBoxToggled(bool pressed) {
|
||||
UpdateTileMaterial();
|
||||
}
|
||||
|
||||
public void UpdateTileMaterial()
|
||||
{
|
||||
if (_navigationGeometryCheckBox.Pressed)
|
||||
{
|
||||
ImageTexture newWorldTexture = new ImageTexture();
|
||||
public void UpdateTileMaterial() {
|
||||
if (_navigationGeometryCheckBox.Pressed) {
|
||||
ImageTexture newWorldTexture = new();
|
||||
newWorldTexture.CreateFromImage(_tileWorld.NavigationmapImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
|
||||
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.NavigationmapImage.GetSize().x);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageTexture newWorldTexture = new ImageTexture();
|
||||
} else {
|
||||
ImageTexture newWorldTexture = new();
|
||||
newWorldTexture.CreateFromImage(_tileWorld.ColormapImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
|
||||
|
@ -145,10 +134,8 @@ public class EditorUI : Control
|
|||
}
|
||||
|
||||
|
||||
public void OnTileClicked(Vector2 offsetCoord)
|
||||
{
|
||||
switch (CurrentInputMode)
|
||||
{
|
||||
public void OnTileClicked(Vector2 offsetCoord) {
|
||||
switch (CurrentInputMode) {
|
||||
case InputMode.Grass:
|
||||
_tileWorld.SetTileColorAtOffset(currentTileOffset, Colors.Green);
|
||||
break;
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
using Godot;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Godot;
|
||||
|
||||
public class HexTile3DMaterialAssign : Spatial
|
||||
{
|
||||
public class HexTile3DMaterialAssign : Spatial {
|
||||
// Declare member variables here. Examples:
|
||||
// private int a = 2;
|
||||
// private string b = "text";
|
||||
|
@ -15,10 +13,9 @@ public class HexTile3DMaterialAssign : Spatial
|
|||
private ShaderMaterial _customTileMaterial;
|
||||
private ImageTexture _blackWhitePatternTexture;
|
||||
private ImageTexture _colorPatternTexture;
|
||||
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_blackWhitePatternButton = (Button)FindNode("BlackWhitePatternButton");
|
||||
Debug.Assert(_blackWhitePatternButton != null);
|
||||
_blackWhitePatternButton.Connect("pressed", this, nameof(OnBlackWhitePatternButton));
|
||||
|
@ -30,42 +27,39 @@ public class HexTile3DMaterialAssign : Spatial
|
|||
_textureSizeSpinBox = (SpinBox)FindNode("TextureSizeSpinBox");
|
||||
Debug.Assert(_textureSizeSpinBox != null);
|
||||
_textureSizeSpinBox.Connect("value_changed", this, nameof(OnTextureSizeChanged));
|
||||
|
||||
|
||||
_hexTile = (HexTile3D)FindNode("HexTile3D");
|
||||
Debug.Assert(_hexTile != null);
|
||||
|
||||
|
||||
_customTileMaterial = GD.Load<ShaderMaterial>("materials/HexTileTextureLookup.tres");
|
||||
|
||||
_blackWhitePatternTexture = new ImageTexture();
|
||||
Image image = new Image();
|
||||
Image image = new();
|
||||
image.Load("assets/4x4checker.png");
|
||||
_blackWhitePatternTexture.CreateFromImage(image, (uint) (Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
|
||||
_blackWhitePatternTexture.CreateFromImage(image, (uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
|
||||
_colorPatternTexture = new ImageTexture();
|
||||
image.Load("assets/4x4checkerColor.png");
|
||||
_colorPatternTexture.CreateFromImage(image, (uint) (Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
_colorPatternTexture.CreateFromImage(image, (uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
}
|
||||
|
||||
public void OnBlackWhitePatternButton()
|
||||
{
|
||||
public void OnBlackWhitePatternButton() {
|
||||
GD.Print("Apply Black White Pattern!");
|
||||
_customTileMaterial.SetShaderParam("MapAlbedoTexture", _blackWhitePatternTexture);
|
||||
}
|
||||
|
||||
public void OnColorPatternButton()
|
||||
{
|
||||
|
||||
public void OnColorPatternButton() {
|
||||
GD.Print("Apply Collor Pattern!");
|
||||
//currentMaterial.SetShaderParam("MapAlbedoTexture", _colorPatternTexture);
|
||||
_customTileMaterial.SetShaderParam("MapAlbedoTexture", _colorPatternTexture);
|
||||
|
||||
|
||||
// _customTileMaterial.SetShaderParam("MapAlbedoTexture", _imageTexture);
|
||||
|
||||
|
||||
// _hexTile.Mesh.SetSurfaceMaterial(0, _customTileMaterial);
|
||||
}
|
||||
|
||||
public void OnTextureSizeChanged(float value)
|
||||
{
|
||||
_customTileMaterial.SetShaderParam("TextureSize", (int) value);
|
||||
public void OnTextureSizeChanged(float value) {
|
||||
_customTileMaterial.SetShaderParam("TextureSize", (int)value);
|
||||
GD.Print("Texture size: " + _customTileMaterial.GetShaderParam("TextureSize"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,65 +1,59 @@
|
|||
using Godot;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
public class NavigationTests : Spatial
|
||||
{
|
||||
public class NavigationTests : Spatial {
|
||||
private HexGrid _hexGrid;
|
||||
private HexCell _currentTile;
|
||||
private HexCell _lastTile;
|
||||
|
||||
|
||||
private Spatial _mouseHighlight;
|
||||
private ShaderMaterial _tileMaterial;
|
||||
|
||||
private EditorUI _editorUi;
|
||||
private TileWorld _tileWorld;
|
||||
private World _world;
|
||||
private StreamContainer _streamContainer;
|
||||
private Player _player;
|
||||
private NavigationComponent _playerNavigationComponent;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
|
||||
public override void _Ready() {
|
||||
_hexGrid = new HexGrid();
|
||||
_currentTile = new HexCell();
|
||||
_lastTile = new HexCell();
|
||||
|
||||
|
||||
_tileMaterial = GD.Load<ShaderMaterial>("materials/HexTileTextureLookup.tres");
|
||||
|
||||
|
||||
_mouseHighlight = GetNode<Spatial>("MouseHighlight");
|
||||
|
||||
_editorUi = GetNode<EditorUI>("EditorUI");
|
||||
_tileWorld = GetNode<TileWorld>("TileWorld");
|
||||
_tileWorld.Connect("WorldGenerated", this, nameof(OnWorldGenerated));
|
||||
_world = GetNode<World>("World");
|
||||
_world.Connect("WorldGenerated", this, nameof(OnWorldGenerated));
|
||||
_streamContainer = GetNode<StreamContainer>("StreamContainer");
|
||||
|
||||
|
||||
_streamContainer.SetCenterTile(_currentTile);
|
||||
|
||||
_player = GetNode<Player>("Player");
|
||||
_playerNavigationComponent = _player.GetNode<NavigationComponent>("Navigation");
|
||||
|
||||
|
||||
// input handling
|
||||
// _groundLayer.Connect("input_event", this, nameof(OnGroundLayerInputEvent));
|
||||
_streamContainer.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
_streamContainer.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
_world.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
_world.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
|
||||
CorrectEntityGridPositions();
|
||||
}
|
||||
|
||||
public void CorrectEntityGridPositions()
|
||||
{
|
||||
public void CorrectEntityGridPositions() {
|
||||
Spatial entitiesNode = GetNode<Spatial>("Entities");
|
||||
if (entitiesNode == null)
|
||||
{
|
||||
if (entitiesNode == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var entities = entitiesNode.GetChildren();
|
||||
foreach (Spatial entity in entities)
|
||||
{
|
||||
Vector2 entityPlaneCoords = new Vector2(entity.GlobalTranslation.x, entity.GlobalTranslation.z);
|
||||
HexCell entityCell = _tileWorld.HexGrid.GetHexAt(entityPlaneCoords);
|
||||
_tileWorld.MarkCellUnwalkable(entityCell);
|
||||
Array entities = entitiesNode.GetChildren();
|
||||
foreach (Spatial entity in entities) {
|
||||
Vector2 entityPlaneCoords = new(entity.GlobalTranslation.x, entity.GlobalTranslation.z);
|
||||
HexCell entityCell = _world.HexGrid.GetHexAt(entityPlaneCoords);
|
||||
_world.MarkCellUnwalkable(entityCell);
|
||||
Vector2 cellPlaneCoords = _hexGrid.GetHexCenterFromOffset(entityCell.OffsetCoords);
|
||||
Vector3 entityGlobalTranslation = entity.GlobalTranslation;
|
||||
entityGlobalTranslation.x = cellPlaneCoords.x;
|
||||
|
@ -68,79 +62,70 @@ public class NavigationTests : Spatial
|
|||
}
|
||||
}
|
||||
|
||||
public void OnWorldGenerated()
|
||||
{
|
||||
public void OnWorldGenerated() {
|
||||
_streamContainer.OnWorldGenerated();
|
||||
|
||||
// Properly place the Player
|
||||
Vector2 centerTileCoord = (Vector2.One * _tileWorld.Size / 2).Round();
|
||||
Vector3 worldCenterTileCoords = _tileWorld.GetTileWorldCenterFromOffset(centerTileCoord);
|
||||
worldCenterTileCoords.y = _tileWorld.GetHeightAtOffset(centerTileCoord);
|
||||
Vector2 centerTileCoord = (Vector2.One * _world.Size / 2).Round();
|
||||
Vector3 worldCenterTileCoords = _world.GetTileWorldCenterFromOffset(centerTileCoord);
|
||||
worldCenterTileCoords.y = _world.GetHeightAtOffset(centerTileCoord);
|
||||
Transform playerTransform = Transform.Identity;
|
||||
playerTransform.origin = worldCenterTileCoords;
|
||||
_player.Transform = playerTransform;
|
||||
|
||||
ImageTexture newWorldTexture = new ImageTexture();
|
||||
newWorldTexture.CreateFromImage(_tileWorld.ColormapImage,
|
||||
ImageTexture newWorldTexture = new();
|
||||
newWorldTexture.CreateFromImage(_world.ColormapImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
|
||||
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.ColormapImage.GetSize().x);
|
||||
_tileMaterial.SetShaderParam("TextureSize", (int)_world.ColormapImage.GetSize().x);
|
||||
|
||||
CorrectEntityGridPositions();
|
||||
}
|
||||
|
||||
|
||||
public void UpdateCurrentTile(HexCell tile)
|
||||
{
|
||||
if (_currentTile.AxialCoords == tile.AxialCoords)
|
||||
{
|
||||
public void UpdateCurrentTile(HexCell tile) {
|
||||
if (_currentTile.AxialCoords == tile.AxialCoords) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_lastTile = _currentTile;
|
||||
_currentTile = tile;
|
||||
|
||||
|
||||
GD.Print("Current tile: " + _currentTile.OffsetCoords);
|
||||
|
||||
if (_lastTile.OffsetCoords != _currentTile.OffsetCoords && _editorUi != null)
|
||||
{
|
||||
if (_lastTile.OffsetCoords != _currentTile.OffsetCoords && _editorUi != null) {
|
||||
_editorUi.currentTileOffset = _currentTile.OffsetCoords;
|
||||
}
|
||||
|
||||
|
||||
Vector2 planeCoords = _hexGrid.GetHexCenterFromOffset(_currentTile.OffsetCoords);
|
||||
Transform tileTransform = Transform.Identity;
|
||||
tileTransform.origin.x = planeCoords.x;
|
||||
tileTransform.origin.y = _tileWorld.GetHeightAtOffset(_currentTile.OffsetCoords) + 0.1f;
|
||||
tileTransform.origin.y = _world.GetHeightAtOffset(_currentTile.OffsetCoords) + 0.1f;
|
||||
tileTransform.origin.z = planeCoords.y;
|
||||
|
||||
|
||||
_mouseHighlight.Transform = tileTransform;
|
||||
}
|
||||
|
||||
|
||||
public void OnGroundLayerInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||
int shapeIndex)
|
||||
{
|
||||
int shapeIndex) {
|
||||
UpdateCurrentTile(_hexGrid.GetHexAt(new Vector2(position.x, position.z)));
|
||||
}
|
||||
|
||||
public void OnTileClicked(HexTile3D tile)
|
||||
{
|
||||
if (_editorUi != null)
|
||||
{
|
||||
public void OnTileClicked(HexTile3D tile) {
|
||||
if (_editorUi != null) {
|
||||
_editorUi.OnTileClicked(tile.OffsetCoords);
|
||||
|
||||
if (_editorUi.CurrentInputMode == EditorUI.InputMode.Navigate)
|
||||
{
|
||||
if (_editorUi.CurrentInputMode == EditorUI.InputMode.Navigate) {
|
||||
_playerNavigationComponent.FindPath(_player, _player.GlobalTranslation, tile.GlobalTranslation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnTileHovered(HexTile3D tile)
|
||||
{
|
||||
public void OnTileHovered(HexTile3D tile) {
|
||||
UpdateCurrentTile(tile.Cell);
|
||||
|
||||
|
||||
Debug.Assert(_playerNavigationComponent != null);
|
||||
|
||||
_playerNavigationComponent.FindPath(_player, _player.GlobalTranslation, tile.GlobalTranslation);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=25 format=2]
|
||||
[gd_scene load_steps=26 format=2]
|
||||
|
||||
[ext_resource path="res://entities/Player.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://scenes/TileWorld.tscn" type="PackedScene" id=2]
|
||||
|
@ -11,6 +11,7 @@
|
|||
[ext_resource path="res://scenes/HexTile3DPatch.tscn" type="PackedScene" id=9]
|
||||
[ext_resource path="res://entities/rockB.tscn" type="PackedScene" id=10]
|
||||
[ext_resource path="res://entities/Chest.tscn" type="PackedScene" id=11]
|
||||
[ext_resource path="res://scenes/World.tscn" type="PackedScene" id=12]
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachinePlayback" id=8]
|
||||
|
||||
|
@ -289,18 +290,21 @@ script = ExtResource( 4 )
|
|||
|
||||
[node name="Player" parent="." instance=ExtResource( 1 )]
|
||||
collision_mask = 1
|
||||
TileWorldNode = NodePath("../TileWorld")
|
||||
WorldNode = NodePath("../World")
|
||||
|
||||
[node name="ToolAttachement" parent="Player/Geometry/Armature/Skeleton" index="5"]
|
||||
transform = Transform( 1, 8.68458e-08, -1.04308e-07, 1.74623e-07, -1, -1.30385e-07, 1.41561e-07, 1.50874e-07, -1, -0.72, 0.45, 3.28113e-08 )
|
||||
[node name="WorldInfo" parent="Player" index="2"]
|
||||
WorldPath = NodePath("../../World")
|
||||
|
||||
[node name="ToolAttachement" parent="Player/Geometry/PirateAsset/Armature/Skeleton" index="5"]
|
||||
transform = Transform( 1, 7.13626e-08, -4.47035e-08, 1.64262e-07, -1, -1.00583e-07, 1.19209e-07, 1.18278e-07, -1, -0.72, 0.45, 1.78362e-08 )
|
||||
|
||||
[node name="AnimationTree" parent="Player/Geometry" index="2"]
|
||||
parameters/playback = SubResource( 8 )
|
||||
|
||||
[node name="TileWorld" parent="." instance=ExtResource( 2 )]
|
||||
DebugMap = true
|
||||
GenerationMapType = 2
|
||||
Size = 20
|
||||
DebugMap = true
|
||||
|
||||
[node name="MouseHighlight" parent="." instance=ExtResource( 3 )]
|
||||
|
||||
|
@ -374,8 +378,10 @@ anims/TreeShake = SubResource( 17 )
|
|||
[node name="Geometry" parent="Entities/Tree5" index="2"]
|
||||
transform = Transform( 1.5, 0, 0, 0, 0.984722, 0.266325, 0, -0.177712, 1.47574, 0, 0, 0 )
|
||||
|
||||
[node name="World" parent="." instance=ExtResource( 12 )]
|
||||
|
||||
[editable path="Player"]
|
||||
[editable path="Player/Geometry"]
|
||||
[editable path="Player/Geometry/PirateAsset"]
|
||||
[editable path="TileWorld"]
|
||||
[editable path="StreamContainer"]
|
||||
[editable path="Entities/Chest"]
|
||||
|
|
|
@ -1,84 +1,68 @@
|
|||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Godot.Collections;
|
||||
using Godot;
|
||||
using GodotComponentTest.components;
|
||||
using GodotComponentTest.entities;
|
||||
using Array = System.Array;
|
||||
using NodePair = System.Tuple<Godot.Node, Godot.Node>;
|
||||
|
||||
public class InteractionSystem : Node
|
||||
{
|
||||
public class InteractionSystem : Node {
|
||||
private List<InteractionComponent> _activeInteractions;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
_activeInteractions = new List<InteractionComponent>();
|
||||
}
|
||||
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
public override void _Process(float delta) {
|
||||
base._Process(delta);
|
||||
|
||||
List<NodePair> invalidInteractionPairs = new List<NodePair>();
|
||||
List<InteractionComponent> endedInteractions = new List<InteractionComponent>();
|
||||
List<InteractionComponent> endedInteractions = new();
|
||||
|
||||
foreach (InteractionComponent interaction in _activeInteractions)
|
||||
{
|
||||
foreach (InteractionComponent interaction in _activeInteractions) {
|
||||
Spatial owningEntity = interaction.OwningEntity;
|
||||
Spatial targetEntity = interaction.TargetEntity;
|
||||
|
||||
if (owningEntity == null || owningEntity.IsQueuedForDeletion() || targetEntity == null || targetEntity.IsQueuedForDeletion())
|
||||
{
|
||||
if (owningEntity == null || owningEntity.IsQueuedForDeletion() || targetEntity == null ||
|
||||
targetEntity.IsQueuedForDeletion()) {
|
||||
interaction.hasStopped = true;
|
||||
}
|
||||
|
||||
if (interaction.hasStopped)
|
||||
{
|
||||
|
||||
if (interaction.hasStopped) {
|
||||
IInteractionInterface interactableA = owningEntity as IInteractionInterface;
|
||||
if (interactableA != null)
|
||||
{
|
||||
if (interactableA != null) {
|
||||
interactableA.OnInteractionEnd();
|
||||
interactableA.InteractionComponent = null;
|
||||
}
|
||||
|
||||
|
||||
IInteractionInterface interactableB = targetEntity as IInteractionInterface;
|
||||
if (interactableB != null)
|
||||
{
|
||||
if (interactableB != null) {
|
||||
interactableB.OnInteractionEnd();
|
||||
interactableB.InteractionComponent = null;
|
||||
}
|
||||
|
||||
|
||||
endedInteractions.Add(interaction);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (InteractionComponent interaction in endedInteractions)
|
||||
{
|
||||
_activeInteractions.Remove(interaction);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnStartInteraction(Entity owningEntity, Entity targetEntity)
|
||||
{
|
||||
InteractionComponent interactionComponent = new InteractionComponent();
|
||||
public void OnStartInteraction(Entity owningEntity, Entity targetEntity) {
|
||||
InteractionComponent interactionComponent = new();
|
||||
interactionComponent.OwningEntity = owningEntity;
|
||||
interactionComponent.TargetEntity = targetEntity;
|
||||
|
||||
|
||||
ConnectInteractionSignals(owningEntity, interactionComponent);
|
||||
ConnectInteractionSignals(targetEntity, interactionComponent);
|
||||
|
||||
|
||||
interactionComponent.EmitSignal("InteractionStart");
|
||||
|
||||
_activeInteractions.Add(interactionComponent);
|
||||
}
|
||||
|
||||
private static void ConnectInteractionSignals(Entity entity, InteractionComponent interactionComponent)
|
||||
{
|
||||
private static void ConnectInteractionSignals(Entity entity, InteractionComponent interactionComponent) {
|
||||
IInteractionInterface interactable = entity as IInteractionInterface;
|
||||
if (interactable != null)
|
||||
{
|
||||
if (interactable != null) {
|
||||
interactable.InteractionComponent = interactionComponent;
|
||||
interactionComponent.Connect("InteractionStart", entity, nameof(interactable.OnInteractionStart));
|
||||
interactionComponent.Connect("InteractionEnd", entity, nameof(interactable.OnInteractionEnd));
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
public class LookupWorldSystem : IWorldSystemInterface
|
||||
{
|
||||
public void RegisterEntityComponent(Entity entity, Component component)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
using System;
|
||||
|
||||
public class LookupWorldSystem : IWorldSystemInterface {
|
||||
public void RegisterEntityComponent(Entity entity, Component component) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Update(float delta)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
public void Update(float delta) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
public interface IWorldSystemInterface
|
||||
{
|
||||
public interface IWorldSystemInterface {
|
||||
void RegisterEntityComponent(Entity entity, Component component);
|
||||
void Update(float delta);
|
||||
}
|
|
@ -1,27 +1,22 @@
|
|||
using Godot;
|
||||
using GoDotTest;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
using GoDotTest;
|
||||
using Xunit;
|
||||
|
||||
public class HexCellTests : TestClass
|
||||
{
|
||||
public HexCellTests(Node testScene) : base(testScene)
|
||||
{
|
||||
}
|
||||
public class HexCellTests : TestClass {
|
||||
public HexCellTests(Node testScene) : base(testScene) { }
|
||||
|
||||
[Test]
|
||||
public void TestHexCellSimple()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestHexCellSimple() {
|
||||
HexCell cell = new();
|
||||
Debug.Assert(cell.CubeCoords == new Vector3(0, 0, 0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHexCellEqualityInequality()
|
||||
{
|
||||
HexCell cellA = new HexCell();
|
||||
HexCell cellB = new HexCell();
|
||||
public void TestHexCellEqualityInequality() {
|
||||
HexCell cellA = new();
|
||||
HexCell cellB = new();
|
||||
|
||||
cellA.AxialCoords = new Vector2(2, 3);
|
||||
cellB.AxialCoords = new Vector2(2, 3);
|
||||
|
@ -37,9 +32,8 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestAxialCoords()
|
||||
{
|
||||
HexCell cell = new HexCell(1, 1, -2);
|
||||
public void TestAxialCoords() {
|
||||
HexCell cell = new(1, 1, -2);
|
||||
Debug.Assert(cell.AxialCoords == new Vector2(1, 1));
|
||||
|
||||
cell = new HexCell(1, -1);
|
||||
|
@ -51,9 +45,8 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestAxialCoordsRounded()
|
||||
{
|
||||
HexCell cell = new HexCell(new Vector2(-0.1f, 0.6f));
|
||||
public void TestAxialCoordsRounded() {
|
||||
HexCell cell = new(new Vector2(-0.1f, 0.6f));
|
||||
Debug.Assert(cell.CubeCoords == new Vector3(0, 1, -1));
|
||||
|
||||
cell = new HexCell(new Vector2(4.2f, -5.5f));
|
||||
|
@ -61,17 +54,15 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestConversion()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestConversion() {
|
||||
HexCell cell = new();
|
||||
Debug.Assert(cell.AxialToCubeCoords(new Vector2(2, 1)) == new Vector3(2, 1, -3));
|
||||
Debug.Assert(cell.AxialToCubeCoords(new Vector2(-1, -1)) == new Vector3(-1, -1, 2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRounding()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestRounding() {
|
||||
HexCell cell = new();
|
||||
Debug.Assert(cell.RoundCoords(new Vector3(0.1f, 0.5f, -0.6f)) == new Vector3(0, 1, -1));
|
||||
Debug.Assert(cell.RoundCoords(new Vector3(-0.4f, -1.3f, 1.7f)) == new Vector3(-1, -1, 2));
|
||||
|
||||
|
@ -80,9 +71,8 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestCoords()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestCoords() {
|
||||
HexCell cell = new();
|
||||
|
||||
// from cubic positive
|
||||
cell.CubeCoords = new Vector3(2, 1, -3);
|
||||
|
@ -104,9 +94,8 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestNearby()
|
||||
{
|
||||
HexCell cell = new HexCell(new Vector2(1, 2));
|
||||
public void TestNearby() {
|
||||
HexCell cell = new(new Vector2(1, 2));
|
||||
|
||||
// adjacent
|
||||
HexCell otherCell = cell.GetAdjacent(HexCell.DIR_N);
|
||||
|
@ -128,9 +117,8 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestDistance()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestDistance() {
|
||||
HexCell cell = new();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
Debug.Assert(cell.DistanceTo(new HexCell(new Vector2(0, 0))) == 3);
|
||||
|
@ -140,80 +128,71 @@ public class HexCellTests : TestClass
|
|||
|
||||
|
||||
[Test]
|
||||
public void TestLineTo()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestLineTo() {
|
||||
HexCell cell = new();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
HexCell[] path = cell.LineTo(new HexCell(5, 2));
|
||||
|
||||
HexCell[] pathExpected =
|
||||
{
|
||||
new HexCell(1, 2),
|
||||
new HexCell(2, 2),
|
||||
new HexCell(3, 2),
|
||||
new HexCell(4, 2),
|
||||
new HexCell(5, 2)
|
||||
HexCell[] pathExpected = {
|
||||
new(1, 2),
|
||||
new(2, 2),
|
||||
new(3, 2),
|
||||
new(4, 2),
|
||||
new(5, 2)
|
||||
};
|
||||
|
||||
Debug.Assert(path.Length == pathExpected.Length);
|
||||
|
||||
foreach (int index in Enumerable.Range(0, path.Length))
|
||||
{
|
||||
foreach (int index in Enumerable.Range(0, path.Length)) {
|
||||
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestLineToAngled()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestLineToAngled() {
|
||||
HexCell cell = new();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
HexCell[] path = cell.LineTo(new HexCell(5, 4));
|
||||
|
||||
HexCell[] pathExpected =
|
||||
{
|
||||
new HexCell(1, 2),
|
||||
new HexCell(2, 2),
|
||||
new HexCell(2, 3),
|
||||
new HexCell(3, 3),
|
||||
new HexCell(4, 3),
|
||||
new HexCell(4, 4),
|
||||
new HexCell(5, 4)
|
||||
HexCell[] pathExpected = {
|
||||
new(1, 2),
|
||||
new(2, 2),
|
||||
new(2, 3),
|
||||
new(3, 3),
|
||||
new(4, 3),
|
||||
new(4, 4),
|
||||
new(5, 4)
|
||||
};
|
||||
|
||||
Debug.Assert(path.Length == pathExpected.Length);
|
||||
|
||||
foreach (int index in Enumerable.Range(0, path.Length))
|
||||
{
|
||||
foreach (int index in Enumerable.Range(0, path.Length)) {
|
||||
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestLineEdge()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestLineEdge() {
|
||||
HexCell cell = new();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
HexCell[] path = cell.LineTo(new HexCell(3, 4));
|
||||
|
||||
HexCell[] pathExpected =
|
||||
{
|
||||
new HexCell(1, 2),
|
||||
new HexCell(2, 2),
|
||||
new HexCell(2, 3),
|
||||
new HexCell(2, 4),
|
||||
new HexCell(3, 4)
|
||||
HexCell[] pathExpected = {
|
||||
new(1, 2),
|
||||
new(2, 2),
|
||||
new(2, 3),
|
||||
new(2, 4),
|
||||
new(3, 4)
|
||||
};
|
||||
|
||||
Debug.Assert(path.Length == pathExpected.Length);
|
||||
|
||||
foreach (int index in Enumerable.Range(0, path.Length))
|
||||
{
|
||||
foreach (int index in Enumerable.Range(0, path.Length)) {
|
||||
Debug.Print("index: " + index + " path: " + path[index].AxialCoords + " expected: " +
|
||||
pathExpected[index].AxialCoords);
|
||||
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
||||
|
@ -221,9 +200,8 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestCellDirections()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestCellDirections() {
|
||||
HexCell cell = new();
|
||||
|
||||
HexCell cellN = HexCell.FromOffsetCoords(new Vector2(0, 1));
|
||||
HexCell cellNW = HexCell.FromOffsetCoords(new Vector2(-1, 0));
|
||||
|
@ -252,8 +230,7 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestCellDirectionsNonzeroReference()
|
||||
{
|
||||
public void TestCellDirectionsNonzeroReference() {
|
||||
HexCell cell = HexCell.FromOffsetCoords(new Vector2(-4, -3));
|
||||
|
||||
HexCell cellN = HexCell.FromOffsetCoords(new Vector2(-4, -2));
|
||||
|
@ -283,9 +260,8 @@ public class HexCellTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestNextCellAlongLine()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
public void TestNextCellAlongLine() {
|
||||
HexCell cell = new();
|
||||
HexCell cellN = HexCell.FromOffsetCoords(new Vector2(0, 1));
|
||||
HexCell cellNE = HexCell.FromOffsetCoords(new Vector2(1, 0));
|
||||
HexCell cellSE = HexCell.FromOffsetCoords(new Vector2(1, -1));
|
||||
|
|
|
@ -7,50 +7,43 @@ using Xunit;
|
|||
|
||||
namespace GodotComponentTest.tests;
|
||||
|
||||
public class HexGridPathFindingTests : TestClass
|
||||
{
|
||||
public class HexGridPathFindingTests : TestClass {
|
||||
private HexGrid _hexGrid;
|
||||
private HexCell _hexCell;
|
||||
|
||||
private HexCell _positionA = new HexCell(new Vector2(2, 0));
|
||||
private HexCell _positionB = new HexCell(new Vector2(4, 2));
|
||||
private HexCell _positionC = new HexCell(new Vector2(7, 0));
|
||||
private HexCell _positionD = new HexCell(new Vector2(5, 0));
|
||||
private HexCell _positionE = new HexCell(new Vector2(2, 2));
|
||||
private HexCell _positionF = new HexCell(new Vector2(1, 3));
|
||||
private HexCell _positionG = new HexCell(new Vector2(1, 0));
|
||||
private readonly HexCell _positionA = new(new Vector2(2, 0));
|
||||
private readonly HexCell _positionB = new(new Vector2(4, 2));
|
||||
private readonly HexCell _positionC = new(new Vector2(7, 0));
|
||||
private readonly HexCell _positionD = new(new Vector2(5, 0));
|
||||
private HexCell _positionE = new(new Vector2(2, 2));
|
||||
private HexCell _positionF = new(new Vector2(1, 3));
|
||||
private readonly HexCell _positionG = new(new Vector2(1, 0));
|
||||
|
||||
private Vector2[] _obstacles =
|
||||
{
|
||||
new Vector2(2, 1),
|
||||
new Vector2(3, 1),
|
||||
new Vector2(4, 1),
|
||||
new Vector2(1, 2),
|
||||
new Vector2(3, 2),
|
||||
new Vector2(1, 3),
|
||||
new Vector2(2, 3),
|
||||
private readonly Vector2[] _obstacles = {
|
||||
new(2, 1),
|
||||
new(3, 1),
|
||||
new(4, 1),
|
||||
new(1, 2),
|
||||
new(3, 2),
|
||||
new(1, 3),
|
||||
new(2, 3)
|
||||
};
|
||||
|
||||
public HexGridPathFindingTests(Node testScene) : base(testScene)
|
||||
{
|
||||
}
|
||||
public HexGridPathFindingTests(Node testScene) : base(testScene) { }
|
||||
|
||||
[Setup]
|
||||
public void Setup()
|
||||
{
|
||||
public void Setup() {
|
||||
_hexGrid = new HexGrid();
|
||||
_hexCell = new HexCell();
|
||||
|
||||
_hexGrid.SetBounds(new Vector2(0, 0), new Vector2(7, 4));
|
||||
foreach (Vector2 obstacle in _obstacles)
|
||||
{
|
||||
foreach (Vector2 obstacle in _obstacles) {
|
||||
_hexGrid.AddObstacle(new HexCell(obstacle));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBounds()
|
||||
{
|
||||
public void TestBounds() {
|
||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(0, 0)));
|
||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(0, 4)));
|
||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(7, 0)));
|
||||
|
@ -63,9 +56,8 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestNegativeBounds()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
public void TestNegativeBounds() {
|
||||
HexGrid grid = new();
|
||||
grid.SetBounds(new Vector2(-5, -5), new Vector2(-2, -2));
|
||||
|
||||
Assert.Equal(grid.PathCostDefault, grid.GetHexCost(new Vector2(-2, -2)));
|
||||
|
@ -76,9 +68,8 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestNegativeBoundsAlt()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
public void TestNegativeBoundsAlt() {
|
||||
HexGrid grid = new();
|
||||
grid.SetBounds(new Vector2(-3, -3), new Vector2(2, 2));
|
||||
|
||||
Assert.Equal(grid.PathCostDefault, grid.GetHexCost(new Vector2(-3, -3)));
|
||||
|
@ -89,8 +80,7 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestGridObstacles()
|
||||
{
|
||||
public void TestGridObstacles() {
|
||||
Assert.Equal(_obstacles.Length, _hexGrid.Obstacles.Count);
|
||||
|
||||
// Adding an obstacle
|
||||
|
@ -110,8 +100,7 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestHexCost()
|
||||
{
|
||||
public void TestHexCost() {
|
||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(1, 1)));
|
||||
Assert.Equal(0, _hexGrid.GetHexCost(new HexCell(new Vector3(2, 1, -3))));
|
||||
|
||||
|
@ -120,14 +109,12 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestMoveCost()
|
||||
{
|
||||
public void TestMoveCost() {
|
||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetMoveCost(new Vector2(0, 0), HexCell.DIR_N));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMovieCostCumulative()
|
||||
{
|
||||
public void TestMovieCostCumulative() {
|
||||
_hexGrid.AddObstacle(new Vector2(0, 0), 1);
|
||||
_hexGrid.AddObstacle(new Vector2(0, 1), 2);
|
||||
_hexGrid.AddBarrier(new Vector2(0, 0), HexCell.DIR_N, 4);
|
||||
|
@ -138,12 +125,10 @@ public class HexGridPathFindingTests : TestClass
|
|||
Assert.Equal(14, _hexGrid.GetMoveCost(new Vector2(0, 0), HexCell.DIR_N));
|
||||
}
|
||||
|
||||
void ComparePath(List<HexCell> expected, List<HexCell> path)
|
||||
{
|
||||
private void ComparePath(List<HexCell> expected, List<HexCell> path) {
|
||||
Assert.Equal(expected.Count, path.Count());
|
||||
|
||||
foreach (int i in Enumerable.Range(0, Math.Min(expected.Count, path.Count())))
|
||||
{
|
||||
foreach (int i in Enumerable.Range(0, Math.Min(expected.Count, path.Count()))) {
|
||||
HexCell pathCell = path[i];
|
||||
HexCell expectedCell = expected[i];
|
||||
Assert.Equal(expectedCell.AxialCoords, pathCell.AxialCoords);
|
||||
|
@ -151,10 +136,8 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestStraightLine()
|
||||
{
|
||||
List<HexCell> expectedPath = new List<HexCell>()
|
||||
{
|
||||
public void TestStraightLine() {
|
||||
List<HexCell> expectedPath = new() {
|
||||
_positionA,
|
||||
new HexCell(new Vector2(3, 0)),
|
||||
new HexCell(new Vector2(4, 0)),
|
||||
|
@ -184,10 +167,8 @@ public class HexGridPathFindingTests : TestClass
|
|||
// }
|
||||
|
||||
[Test]
|
||||
public void TestObstacle()
|
||||
{
|
||||
List<HexCell> expectedPath = new List<HexCell>()
|
||||
{
|
||||
public void TestObstacle() {
|
||||
List<HexCell> expectedPath = new() {
|
||||
_positionA,
|
||||
new HexCell(new Vector2(3, 0)),
|
||||
new HexCell(new Vector2(4, 0)),
|
||||
|
@ -200,10 +181,8 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestWalls()
|
||||
{
|
||||
Vector3[] walls =
|
||||
{
|
||||
public void TestWalls() {
|
||||
Vector3[] walls = {
|
||||
HexCell.DIR_N,
|
||||
HexCell.DIR_NE,
|
||||
HexCell.DIR_SE,
|
||||
|
@ -212,13 +191,11 @@ public class HexGridPathFindingTests : TestClass
|
|||
HexCell.DIR_NW
|
||||
};
|
||||
|
||||
foreach (Vector3 wall in walls)
|
||||
{
|
||||
foreach (Vector3 wall in walls) {
|
||||
_hexGrid.AddBarrier(_positionG, wall);
|
||||
}
|
||||
|
||||
List<HexCell> expectedPath = new List<HexCell>()
|
||||
{
|
||||
List<HexCell> expectedPath = new() {
|
||||
_positionA,
|
||||
new HexCell(new Vector2(1, 1)),
|
||||
new HexCell(new Vector2(0, 1)),
|
||||
|
@ -230,13 +207,11 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestSlopes()
|
||||
{
|
||||
public void TestSlopes() {
|
||||
_hexGrid.AddBarrier(_positionG, HexCell.DIR_NE, 3);
|
||||
_hexGrid.AddBarrier(_positionG, HexCell.DIR_N, _hexGrid.PathCostDefault - 0.1f);
|
||||
|
||||
List<HexCell> expectedPath = new List<HexCell>()
|
||||
{
|
||||
List<HexCell> expectedPath = new() {
|
||||
_positionA,
|
||||
new HexCell(new Vector2(1, 1)),
|
||||
_positionG
|
||||
|
@ -246,20 +221,17 @@ public class HexGridPathFindingTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestRoughTerrain()
|
||||
{
|
||||
List<HexCell> shortPath = new List<HexCell>()
|
||||
{
|
||||
public void TestRoughTerrain() {
|
||||
List<HexCell> shortPath = new() {
|
||||
_positionA,
|
||||
new HexCell(new Vector2(3, 0)),
|
||||
new HexCell(new Vector2(4, 0)),
|
||||
_positionD,
|
||||
new HexCell(new Vector2(5, 1)),
|
||||
_positionB,
|
||||
_positionB
|
||||
};
|
||||
|
||||
List<HexCell> longPath = new List<HexCell>()
|
||||
{
|
||||
List<HexCell> longPath = new() {
|
||||
_positionA,
|
||||
new HexCell(new Vector2(1, 1)),
|
||||
new HexCell(new Vector2(0, 2)),
|
||||
|
@ -268,7 +240,7 @@ public class HexGridPathFindingTests : TestClass
|
|||
new HexCell(new Vector2(1, 4)),
|
||||
new HexCell(new Vector2(2, 4)),
|
||||
new HexCell(new Vector2(3, 3)),
|
||||
_positionB,
|
||||
_positionB
|
||||
};
|
||||
|
||||
_hexGrid.PathCostDefault = 1f;
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Godot;
|
||||
using GoDotTest;
|
||||
using System.Diagnostics;
|
||||
using Xunit;
|
||||
|
||||
public class HexGridTests : TestClass
|
||||
{
|
||||
public HexGridTests(Node testScene) : base(testScene)
|
||||
{
|
||||
}
|
||||
public class HexGridTests : TestClass {
|
||||
public HexGridTests(Node testScene) : base(testScene) { }
|
||||
|
||||
[Test]
|
||||
public void TestGetAt()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
public void TestGetAt() {
|
||||
HexGrid grid = new();
|
||||
float w = grid.HexSize.x;
|
||||
float h = grid.HexSize.y;
|
||||
|
||||
|
@ -24,9 +20,8 @@ public class HexGridTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestGetCellsForLineSimple()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
public void TestGetCellsForLineSimple() {
|
||||
HexGrid grid = new();
|
||||
|
||||
List<HexCell> lineCells =
|
||||
grid.GetCellsForLine(new Vector2(0, 0), grid.GetHexCenterFromOffset(new Vector2(0, 2)));
|
||||
|
@ -46,9 +41,8 @@ public class HexGridTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestGetCellsDiagonal()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
public void TestGetCellsDiagonal() {
|
||||
HexGrid grid = new();
|
||||
|
||||
List<HexCell> lineCells =
|
||||
grid.GetCellsForLine(new Vector2(0, 0), grid.GetHexCenterFromOffset(new Vector2(2, 1)));
|
||||
|
@ -68,9 +62,8 @@ public class HexGridTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestGetCellsForLineAlongEdge()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
public void TestGetCellsForLineAlongEdge() {
|
||||
HexGrid grid = new();
|
||||
|
||||
List<HexCell> lineCells =
|
||||
grid.GetCellsForLine(new Vector2(0, -0.0001f), grid.GetHexCenterFromOffset(new Vector2(2, 0)));
|
||||
|
@ -90,13 +83,12 @@ public class HexGridTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void GetTestsInfiniteLoop()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
|
||||
Vector2 fromPlane = new Vector2(-2.31678f, -5.024752f);
|
||||
Vector2 toPlane = new Vector2(-2.599937f, -6.134028f);
|
||||
|
||||
public void GetTestsInfiniteLoop() {
|
||||
HexGrid grid = new();
|
||||
|
||||
Vector2 fromPlane = new(-2.31678f, -5.024752f);
|
||||
Vector2 toPlane = new(-2.599937f, -6.134028f);
|
||||
|
||||
List<HexCell> cellList = grid.GetCellsForLine(fromPlane, toPlane);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
using Godot;
|
||||
using GoDotTest;
|
||||
|
||||
public class NavigationComponentTests : TestClass
|
||||
{
|
||||
public class NavigationComponentTests : TestClass {
|
||||
private readonly Node _testScene;
|
||||
|
||||
private readonly PackedScene _WorldScene = GD.Load<PackedScene>("res://scenes/World.tscn");
|
||||
|
@ -10,14 +9,12 @@ public class NavigationComponentTests : TestClass
|
|||
private NavigationComponent _navigationComponent;
|
||||
private World _world;
|
||||
|
||||
public NavigationComponentTests(Node testScene) : base(testScene)
|
||||
{
|
||||
public NavigationComponentTests(Node testScene) : base(testScene) {
|
||||
_testScene = testScene;
|
||||
}
|
||||
|
||||
[Setup]
|
||||
public void Setup()
|
||||
{
|
||||
public void Setup() {
|
||||
_world = (World)_WorldScene.Instance();
|
||||
_world.HexGrid = new HexGrid();
|
||||
_testScene.AddChild(_world);
|
||||
|
|
|
@ -6,41 +6,35 @@ using Xunit;
|
|||
|
||||
namespace GodotComponentTest.tests;
|
||||
|
||||
public class Plane2DTests : TestClass
|
||||
{
|
||||
public Plane2DTests(Node testScene) : base(testScene)
|
||||
{
|
||||
public class Plane2DTests : TestClass {
|
||||
public Plane2DTests(Node testScene) : base(testScene) { }
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistSimple() {
|
||||
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(0, -1));
|
||||
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 0)) - 1) < float.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 1))) < float.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 2)) + 1) < float.Epsilon);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistSimple()
|
||||
{
|
||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(0, -1));
|
||||
public void Plane2DDistAngled() {
|
||||
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 0)) - 1) < Single.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 1))) < Single.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 2)) + 1) < Single.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 1))) < float.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 0)) - MathF.Sqrt(2) / 2) < float.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(-1, 0))) < float.Epsilon);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistAngled()
|
||||
{
|
||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 1))) < Single.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 0)) - MathF.Sqrt(2) / 2) < Single.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(-1, 0))) < Single.Epsilon);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistLineSegment()
|
||||
{
|
||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
public void Plane2DDistLineSegment() {
|
||||
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
|
||||
Assert.True(
|
||||
Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(-1, 0)) - 1) < Single.Epsilon);
|
||||
Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(-1, 0)) - 1) < float.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(0, 1)) - 1) <
|
||||
Single.Epsilon);
|
||||
float.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(1, -1).Normalized()) +
|
||||
MathF.Sqrt(2) / 2) < Plane2D.DistancePrecision);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(-1, 1).Normalized()) -
|
||||
|
@ -48,22 +42,20 @@ public class Plane2DTests : TestClass
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DTestIsParallel()
|
||||
{
|
||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
public void Plane2DTestIsParallel() {
|
||||
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
|
||||
Assert.True(plane2D.IsParallelToDir(new Vector2(1, 1.00001f).Normalized()));
|
||||
Assert.True(plane2D.IsParallelToDir(new Vector2(1, 0.99999f).Normalized()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistLineSegmentParallel()
|
||||
{
|
||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
public void Plane2DDistLineSegmentParallel() {
|
||||
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
|
||||
Assert.Equal(Single.PositiveInfinity,
|
||||
Assert.Equal(float.PositiveInfinity,
|
||||
plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(1, 1.00001f).Normalized()));
|
||||
Assert.Equal(Single.NegativeInfinity,
|
||||
Assert.Equal(float.NegativeInfinity,
|
||||
plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(1, 0.99999f).Normalized()));
|
||||
}
|
||||
}
|
|
@ -1,37 +1,29 @@
|
|||
using System;
|
||||
using Godot;
|
||||
using GodotComponentTest.utils;
|
||||
using GoDotTest;
|
||||
using Xunit;
|
||||
|
||||
namespace GodotComponentTest.tests;
|
||||
|
||||
public class StreamContainerTests : TestClass
|
||||
{
|
||||
private Node _testScene = null;
|
||||
public class StreamContainerTests : TestClass {
|
||||
private readonly Node _testScene;
|
||||
private TileWorld _tileWorld;
|
||||
private StreamContainer _streamContainer;
|
||||
|
||||
private PackedScene _tileWorldScene = GD.Load<PackedScene>("res://scenes/TileWorld.tscn");
|
||||
private PackedScene _streamContainerScene = GD.Load<PackedScene>("res://scenes/StreamContainer.tscn");
|
||||
|
||||
public StreamContainerTests(Node testScene) : base(testScene)
|
||||
{
|
||||
|
||||
private readonly PackedScene _tileWorldScene = GD.Load<PackedScene>("res://scenes/TileWorld.tscn");
|
||||
private readonly PackedScene _streamContainerScene = GD.Load<PackedScene>("res://scenes/StreamContainer.tscn");
|
||||
|
||||
public StreamContainerTests(Node testScene) : base(testScene) {
|
||||
_testScene = testScene;
|
||||
}
|
||||
|
||||
[Setup]
|
||||
public void Setup()
|
||||
{
|
||||
_tileWorld = (TileWorld) _tileWorldScene.Instance();
|
||||
public void Setup() {
|
||||
_tileWorld = (TileWorld)_tileWorldScene.Instance();
|
||||
_tileWorld.HexGrid = new HexGrid();
|
||||
_testScene.AddChild(_tileWorld);
|
||||
_streamContainer = (StreamContainer) _streamContainerScene.Instance();
|
||||
_streamContainer = (StreamContainer)_streamContainerScene.Instance();
|
||||
|
||||
foreach (Node node in _testScene.GetChildren())
|
||||
{
|
||||
if (node is TileWorld)
|
||||
{
|
||||
foreach (Node node in _testScene.GetChildren()) {
|
||||
if (node is TileWorld) {
|
||||
_streamContainer.World = node.GetPath();
|
||||
}
|
||||
}
|
||||
|
@ -40,20 +32,17 @@ public class StreamContainerTests : TestClass
|
|||
}
|
||||
|
||||
[Cleanup]
|
||||
public void Cleanup()
|
||||
{
|
||||
foreach (Node node in _testScene.GetChildren())
|
||||
{
|
||||
public void Cleanup() {
|
||||
foreach (Node node in _testScene.GetChildren()) {
|
||||
node.QueueFree();
|
||||
}
|
||||
|
||||
|
||||
_streamContainer.QueueFree();
|
||||
_tileWorld.QueueFree();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistSimple()
|
||||
{
|
||||
public void Plane2DDistSimple() {
|
||||
// _streamContainer.UpdateRects(new Vector2(0, 0));
|
||||
// _streamContainer.UpdateRects(new Vector2(1, 0));
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@ using System.Reflection;
|
|||
using Godot;
|
||||
using GoDotTest;
|
||||
|
||||
public class Tests : Control
|
||||
{
|
||||
public override async void _Ready()
|
||||
=> await GoTest.RunTests(Assembly.GetExecutingAssembly(), this);
|
||||
public class Tests : Control {
|
||||
public override async void _Ready() {
|
||||
await GoTest.RunTests(Assembly.GetExecutingAssembly(), this);
|
||||
}
|
||||
}
|
|
@ -1,21 +1,26 @@
|
|||
extends VBoxContainer
|
||||
extends CenterContainer
|
||||
|
||||
var world_size_label = null
|
||||
var world_size_slider = null
|
||||
onready var SeedLineEdit: LineEdit
|
||||
onready var ChunkSizeSpinBox: SpinBox
|
||||
onready var GameScene: PackedScene = preload ("res://scenes/Game.tscn")
|
||||
|
||||
onready var WorldTextureRect = $WorldTextureRect
|
||||
onready var HeightTextureRect = $HeightTextureRect
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
world_size_label = find_node("WorldSizeLabel")
|
||||
world_size_slider = find_node("WorldSizeSlider");
|
||||
SeedLineEdit = find_node("SeedLineEdit")
|
||||
assert(SeedLineEdit)
|
||||
|
||||
world_size_slider.value = 4
|
||||
ChunkSizeSpinBox = find_node("ChunkSizeSpinBox")
|
||||
assert(ChunkSizeSpinBox)
|
||||
|
||||
func _on_HSlider_value_changed(value):
|
||||
world_size_label.text = str(value)
|
||||
|
||||
func _on_ShowTexturesCheckButton_toggled(button_pressed):
|
||||
WorldTextureRect.visible = button_pressed
|
||||
HeightTextureRect.visible = button_pressed
|
||||
func _on_RefreshSeedButton_pressed():
|
||||
var rng = RandomNumberGenerator.new()
|
||||
rng.seed = Time.get_ticks_msec()
|
||||
SeedLineEdit.text = str(rng.randi())
|
||||
|
||||
|
||||
func _on_GenerateButton_pressed():
|
||||
var game_scene_instance = GameScene.instance()
|
||||
|
||||
self.visible = false
|
||||
get_tree().get_root().add_child(game_scene_instance)
|
||||
game_scene_instance.StartNewGame(int(SeedLineEdit.text), int(ChunkSizeSpinBox.value))
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://ui/WorldGeneratorUI.gd" type="Script" id=1]
|
||||
|
||||
[node name="WorldGeneratorUI" type="CenterContainer"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
margin_left = 16.0
|
||||
margin_top = 81.0
|
||||
margin_right = 303.0
|
||||
margin_bottom = 319.0
|
||||
custom_constants/separation = 20
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer"]
|
||||
margin_right = 287.0
|
||||
margin_bottom = 14.0
|
||||
text = "World Generation"
|
||||
align = 1
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="VBoxContainer"]
|
||||
margin_top = 34.0
|
||||
margin_right = 287.0
|
||||
margin_bottom = 198.0
|
||||
columns = 3
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/GridContainer"]
|
||||
margin_top = 5.0
|
||||
margin_right = 69.0
|
||||
margin_bottom = 19.0
|
||||
text = "Seed"
|
||||
|
||||
[node name="SeedLineEdit" type="LineEdit" parent="VBoxContainer/GridContainer"]
|
||||
margin_left = 73.0
|
||||
margin_right = 223.0
|
||||
margin_bottom = 24.0
|
||||
rect_min_size = Vector2( 150, 0 )
|
||||
text = "0"
|
||||
align = 2
|
||||
caret_blink = true
|
||||
|
||||
[node name="RefreshSeedButton" type="Button" parent="VBoxContainer/GridContainer"]
|
||||
margin_left = 227.0
|
||||
margin_right = 287.0
|
||||
margin_bottom = 24.0
|
||||
text = "Refresh"
|
||||
|
||||
[node name="Label2" type="Label" parent="VBoxContainer/GridContainer"]
|
||||
margin_top = 33.0
|
||||
margin_right = 69.0
|
||||
margin_bottom = 47.0
|
||||
text = "Chunk Size"
|
||||
|
||||
[node name="ChunkSizeSpinBox" type="SpinBox" parent="VBoxContainer/GridContainer"]
|
||||
margin_left = 73.0
|
||||
margin_top = 28.0
|
||||
margin_right = 223.0
|
||||
margin_bottom = 52.0
|
||||
min_value = 4.0
|
||||
step = 2.0
|
||||
value = 10.0
|
||||
rounded = true
|
||||
align = 2
|
||||
|
||||
[node name="Empty" type="Label" parent="VBoxContainer/GridContainer"]
|
||||
margin_left = 227.0
|
||||
margin_top = 33.0
|
||||
margin_right = 287.0
|
||||
margin_bottom = 47.0
|
||||
|
||||
[node name="Label4" type="Label" parent="VBoxContainer/GridContainer"]
|
||||
margin_top = 103.0
|
||||
margin_right = 69.0
|
||||
margin_bottom = 117.0
|
||||
text = "Objects"
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/GridContainer"]
|
||||
margin_left = 73.0
|
||||
margin_top = 56.0
|
||||
margin_right = 223.0
|
||||
margin_bottom = 164.0
|
||||
|
||||
[node name="ObjectTypeTreeCheckbox" type="CheckBox" parent="VBoxContainer/GridContainer/VBoxContainer"]
|
||||
margin_right = 150.0
|
||||
margin_bottom = 24.0
|
||||
pressed = true
|
||||
text = "Trees"
|
||||
|
||||
[node name="ObjectTypeGrassCheckbox" type="CheckBox" parent="VBoxContainer/GridContainer/VBoxContainer"]
|
||||
margin_top = 28.0
|
||||
margin_right = 150.0
|
||||
margin_bottom = 52.0
|
||||
pressed = true
|
||||
text = "Grass"
|
||||
|
||||
[node name="ObjectTypeChestCheckbox" type="CheckBox" parent="VBoxContainer/GridContainer/VBoxContainer"]
|
||||
margin_top = 56.0
|
||||
margin_right = 150.0
|
||||
margin_bottom = 80.0
|
||||
pressed = true
|
||||
text = "Chests"
|
||||
|
||||
[node name="ObjectTypeRockCheckbox" type="CheckBox" parent="VBoxContainer/GridContainer/VBoxContainer"]
|
||||
margin_top = 84.0
|
||||
margin_right = 150.0
|
||||
margin_bottom = 108.0
|
||||
pressed = true
|
||||
text = "Rocks"
|
||||
|
||||
[node name="GenerateButton" type="Button" parent="VBoxContainer"]
|
||||
margin_left = 216.0
|
||||
margin_top = 218.0
|
||||
margin_right = 287.0
|
||||
margin_bottom = 238.0
|
||||
size_flags_horizontal = 8
|
||||
text = "Generate"
|
||||
|
||||
[connection signal="pressed" from="VBoxContainer/GridContainer/RefreshSeedButton" to="." method="_on_RefreshSeedButton_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/GenerateButton" to="." method="_on_GenerateButton_pressed"]
|
|
@ -0,0 +1,21 @@
|
|||
extends VBoxContainer
|
||||
|
||||
var world_size_label = null
|
||||
var world_size_slider = null
|
||||
|
||||
onready var WorldTextureRect = $WorldTextureRect
|
||||
onready var HeightTextureRect = $HeightTextureRect
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
world_size_label = find_node("WorldSizeLabel")
|
||||
world_size_slider = find_node("WorldSizeSlider");
|
||||
|
||||
world_size_slider.value = 4
|
||||
|
||||
func _on_HSlider_value_changed(value):
|
||||
world_size_label.text = str(value)
|
||||
|
||||
func _on_ShowTexturesCheckButton_toggled(button_pressed):
|
||||
WorldTextureRect.visible = button_pressed
|
||||
HeightTextureRect.visible = button_pressed
|
|
@ -1,76 +1,63 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
|
||||
namespace GodotComponentTest.utils;
|
||||
|
||||
public class DebugGeometry : Spatial
|
||||
{
|
||||
public class DebugGeometry : Spatial {
|
||||
private ImmediateGeometry _immediateGeometry;
|
||||
|
||||
private List<Transform> _transformStack;
|
||||
private Transform _currentTransform = Transform.Identity;
|
||||
private Transform _currentTransform = Transform.Identity;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
public override void _Ready() {
|
||||
base._Ready();
|
||||
|
||||
|
||||
_immediateGeometry = (ImmediateGeometry)FindNode("ImmediateGeometry");
|
||||
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
public void Clear() {
|
||||
_immediateGeometry.Clear();
|
||||
_transformStack = new List<Transform>();
|
||||
_transformStack.Add(Transform.Identity);
|
||||
}
|
||||
|
||||
public void PushTransform(Transform transform)
|
||||
{
|
||||
public void PushTransform(Transform transform) {
|
||||
_transformStack.Add(transform);
|
||||
_currentTransform = transform;
|
||||
}
|
||||
|
||||
public void PushTranslated(Vector3 offset)
|
||||
{
|
||||
public void PushTranslated(Vector3 offset) {
|
||||
PushTransform(_currentTransform.Translated(offset));
|
||||
}
|
||||
|
||||
public void PopTransform()
|
||||
{
|
||||
public void PopTransform() {
|
||||
_transformStack.RemoveAt(_transformStack.Count - 1);
|
||||
_currentTransform = PeekTransform();
|
||||
}
|
||||
|
||||
public Transform PeekTransform()
|
||||
{
|
||||
public Transform PeekTransform() {
|
||||
return _transformStack[_transformStack.Count - 1];
|
||||
}
|
||||
|
||||
public void Begin(Mesh.PrimitiveType primitive, Texture texture = null)
|
||||
{
|
||||
public void Begin(Mesh.PrimitiveType primitive, Texture texture = null) {
|
||||
_immediateGeometry.Begin(primitive, texture);
|
||||
}
|
||||
|
||||
public void End()
|
||||
{
|
||||
public void End() {
|
||||
_immediateGeometry.End();
|
||||
}
|
||||
|
||||
public void AddVertex(Vector3 vertex)
|
||||
{
|
||||
public void AddVertex(Vector3 vertex) {
|
||||
_immediateGeometry.AddVertex(_currentTransform.Xform(vertex));
|
||||
}
|
||||
|
||||
public void SetColor(Color color)
|
||||
{
|
||||
public void SetColor(Color color) {
|
||||
_immediateGeometry.SetColor(color);
|
||||
}
|
||||
|
||||
public void AddBox(Vector3 extents)
|
||||
{
|
||||
|
||||
public void AddBox(Vector3 extents) {
|
||||
Transform currentTransform = PeekTransform();
|
||||
// bottom square
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||
|
@ -81,7 +68,7 @@ public class DebugGeometry : Spatial
|
|||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||
|
||||
|
||||
// top square
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * 0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * 0.5f, extents.z * 0.5f));
|
||||
|
@ -91,15 +78,15 @@ public class DebugGeometry : Spatial
|
|||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * 0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * 0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * 0.5f, extents.z * -0.5f));
|
||||
|
||||
|
||||
// side
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * 0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * 0.5f, extents.z * 0.5f));
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * -0.5f, extents.z * 0.5f));
|
||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * -0.5f, extents.z * 0.5f));
|
||||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * 0.5f, extents.z * 0.5f));
|
||||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * -0.5f, extents.z * 0.5f));
|
||||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * 0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||
AddVertex(new Vector3(extents.x * 0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||
}
|
||||
}
|
|
@ -5,43 +5,39 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using Godot;
|
||||
|
||||
namespace Namespace
|
||||
{
|
||||
using UnderlyingType = UInt64;
|
||||
namespace Namespace;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
public class ExportFlagsEnumAttribute : ExportAttribute
|
||||
{
|
||||
public ExportFlagsEnumAttribute(Type enumType)
|
||||
: base(PropertyHint.Flags, GetFlagsEnumHintString(enumType))
|
||||
{ }
|
||||
using UnderlyingType = UInt64;
|
||||
|
||||
private static string GetFlagsEnumHintString(Type enumType)
|
||||
{
|
||||
Dictionary<UnderlyingType, List<string>> flagNamesByFlag = new Dictionary<UnderlyingType, List<string>>();
|
||||
UnderlyingType flag = (UnderlyingType)1;
|
||||
foreach (string name in Enum.GetNames(enumType))
|
||||
{
|
||||
UnderlyingType value = (UnderlyingType)Convert.ChangeType(Enum.Parse(enumType, name), typeof(UnderlyingType));
|
||||
while (value > flag)
|
||||
{
|
||||
if (!flagNamesByFlag.ContainsKey(flag))
|
||||
{
|
||||
flagNamesByFlag.Add(flag, new List<string>());
|
||||
}
|
||||
flag <<= 1;
|
||||
}
|
||||
if (value == flag)
|
||||
{
|
||||
if (!flagNamesByFlag.TryGetValue(flag, out List<string> names))
|
||||
{
|
||||
names = new List<string>();
|
||||
flagNamesByFlag.Add(flag, names);
|
||||
}
|
||||
names.Add(name);
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
public class ExportFlagsEnumAttribute : ExportAttribute {
|
||||
public ExportFlagsEnumAttribute(Type enumType)
|
||||
: base(PropertyHint.Flags, GetFlagsEnumHintString(enumType)) { }
|
||||
|
||||
private static string GetFlagsEnumHintString(Type enumType) {
|
||||
Dictionary<UnderlyingType, List<string>> flagNamesByFlag = new();
|
||||
UnderlyingType flag = 1;
|
||||
foreach (string name in Enum.GetNames(enumType)) {
|
||||
UnderlyingType value =
|
||||
(UnderlyingType)Convert.ChangeType(Enum.Parse(enumType, name), typeof(UnderlyingType));
|
||||
while (value > flag) {
|
||||
if (!flagNamesByFlag.ContainsKey(flag)) {
|
||||
flagNamesByFlag.Add(flag, new List<string>());
|
||||
}
|
||||
|
||||
flag <<= 1;
|
||||
}
|
||||
|
||||
if (value == flag) {
|
||||
if (!flagNamesByFlag.TryGetValue(flag, out List<string> names)) {
|
||||
names = new List<string>();
|
||||
flagNamesByFlag.Add(flag, names);
|
||||
}
|
||||
|
||||
names.Add(name);
|
||||
}
|
||||
return string.Join(", ", flagNamesByFlag.Values.Select(flagNames => string.Join(" / ", flagNames)));
|
||||
}
|
||||
|
||||
return string.Join(", ", flagNamesByFlag.Values.Select(flagNames => string.Join(" / ", flagNames)));
|
||||
}
|
||||
}
|
|
@ -1,11 +1,9 @@
|
|||
using System;
|
||||
using Godot;
|
||||
|
||||
public class NavigationPoint
|
||||
{
|
||||
public class NavigationPoint {
|
||||
[Flags]
|
||||
public enum NavigationFlags
|
||||
{
|
||||
public enum NavigationFlags {
|
||||
Position = 1,
|
||||
Orientation = 2
|
||||
}
|
||||
|
@ -16,52 +14,43 @@ public class NavigationPoint
|
|||
|
||||
public Vector3 WorldPosition = Vector3.Zero;
|
||||
|
||||
public NavigationPoint(Vector3 worldPosition)
|
||||
{
|
||||
public NavigationPoint(Vector3 worldPosition) {
|
||||
WorldPosition = worldPosition;
|
||||
Flags = NavigationFlags.Position;
|
||||
}
|
||||
|
||||
public NavigationPoint(Quat worldOrientation)
|
||||
{
|
||||
public NavigationPoint(Quat worldOrientation) {
|
||||
WorldOrientation = worldOrientation;
|
||||
Flags = NavigationFlags.Orientation;
|
||||
}
|
||||
|
||||
public NavigationPoint(Transform worldTransform)
|
||||
{
|
||||
public NavigationPoint(Transform worldTransform) {
|
||||
WorldPosition = worldTransform.origin;
|
||||
WorldOrientation = worldTransform.basis.Quat();
|
||||
WorldAngle = Globals.CalcPlaneAngle(worldTransform);
|
||||
|
||||
|
||||
Flags = NavigationFlags.Position | NavigationFlags.Orientation;
|
||||
}
|
||||
|
||||
public bool IsReached(Transform worldTransform)
|
||||
{
|
||||
var goalReached = false;
|
||||
var positionError = new Vector2(WorldPosition.x - worldTransform.origin.x,
|
||||
public bool IsReached(Transform worldTransform) {
|
||||
bool goalReached = false;
|
||||
Vector2 positionError = new Vector2(WorldPosition.x - worldTransform.origin.x,
|
||||
WorldPosition.z - worldTransform.origin.z);
|
||||
var positionErrorSquared = positionError.LengthSquared();
|
||||
float positionErrorSquared = positionError.LengthSquared();
|
||||
worldTransform.basis.Quat();
|
||||
var orientationError = Mathf.Abs(worldTransform.basis.Quat().AngleTo(WorldOrientation));
|
||||
var angleError = Mathf.Abs(Globals.CalcPlaneAngle(worldTransform) - WorldAngle);
|
||||
float orientationError = Mathf.Abs(worldTransform.basis.Quat().AngleTo(WorldOrientation));
|
||||
float angleError = Mathf.Abs(Globals.CalcPlaneAngle(worldTransform) - WorldAngle);
|
||||
|
||||
if (Flags.HasFlag(NavigationFlags.Position)
|
||||
&& Flags.HasFlag(NavigationFlags.Orientation)
|
||||
&& positionErrorSquared < Globals.EpsPositionSquared
|
||||
&& angleError < Globals.EpsRadians)
|
||||
{
|
||||
&& angleError < Globals.EpsRadians) {
|
||||
goalReached = true;
|
||||
}
|
||||
else if (Flags == NavigationFlags.Position &&
|
||||
positionErrorSquared < Globals.EpsPositionSquared)
|
||||
{
|
||||
} else if (Flags == NavigationFlags.Position &&
|
||||
positionErrorSquared < Globals.EpsPositionSquared) {
|
||||
goalReached = true;
|
||||
}
|
||||
else if (Flags == NavigationFlags.Orientation &&
|
||||
angleError < Globals.EpsRadians)
|
||||
{
|
||||
} else if (Flags == NavigationFlags.Orientation &&
|
||||
angleError < Globals.EpsRadians) {
|
||||
goalReached = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,47 +1,39 @@
|
|||
using System;
|
||||
using Godot;
|
||||
|
||||
namespace GodotComponentTest.utils;
|
||||
|
||||
public class Plane2D
|
||||
{
|
||||
public class Plane2D {
|
||||
public static readonly float DistancePrecision = 1.0e-5f;
|
||||
|
||||
private Vector2 _planePoint;
|
||||
public Vector2 Normal;
|
||||
|
||||
public Plane2D(Vector2 planePoint, Vector2 normal)
|
||||
{
|
||||
public Plane2D(Vector2 planePoint, Vector2 normal) {
|
||||
_planePoint = planePoint;
|
||||
Normal = normal;
|
||||
}
|
||||
|
||||
public float DistanceToPoint(Vector2 point)
|
||||
{
|
||||
public float DistanceToPoint(Vector2 point) {
|
||||
return (point - _planePoint).Dot(Normal);
|
||||
}
|
||||
|
||||
public bool IsParallelToDir(Vector2 dir)
|
||||
{
|
||||
public bool IsParallelToDir(Vector2 dir) {
|
||||
float normalDotDir = Normal.Dot(dir);
|
||||
|
||||
return (Mathf.Abs(normalDotDir) <= Plane2D.DistancePrecision);
|
||||
return Mathf.Abs(normalDotDir) <= DistancePrecision;
|
||||
}
|
||||
|
||||
public float DistanceToLineSegment(Vector2 point, Vector2 dir)
|
||||
{
|
||||
public float DistanceToLineSegment(Vector2 point, Vector2 dir) {
|
||||
float normalDotDir = Normal.Dot(dir);
|
||||
|
||||
if (Mathf.Abs(normalDotDir) > Plane2D.DistancePrecision)
|
||||
{
|
||||
if (Mathf.Abs(normalDotDir) > DistancePrecision) {
|
||||
return (_planePoint.Dot(Normal) - point.Dot(Normal)) / normalDotDir;
|
||||
}
|
||||
|
||||
if (normalDotDir < 0)
|
||||
{
|
||||
return Single.PositiveInfinity;
|
||||
if (normalDotDir < 0) {
|
||||
return float.PositiveInfinity;
|
||||
}
|
||||
|
||||
return Single.NegativeInfinity;
|
||||
return float.NegativeInfinity;
|
||||
}
|
||||
}
|
|
@ -1,23 +1,19 @@
|
|||
// Based on: allenchou.net/2015/04/game-math-precise-control-over-numeric-springing/
|
||||
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Godot;
|
||||
|
||||
public class SpringDamper
|
||||
{
|
||||
public class SpringDamper {
|
||||
public float omega = 1;
|
||||
public float zeta = 1;
|
||||
|
||||
public SpringDamper(float osc_freq = 1.0f, float osc_red = 0.1f, float osc_red_h = 1.0f)
|
||||
{
|
||||
public SpringDamper(float osc_freq = 1.0f, float osc_red = 0.1f, float osc_red_h = 1.0f) {
|
||||
Debug.Assert(osc_red > 0.001 && osc_red < 0.999);
|
||||
omega = osc_freq * 2 * Mathf.Pi;
|
||||
zeta = Mathf.Log(1.0f - osc_red) / (-omega * osc_red_h);
|
||||
}
|
||||
|
||||
public (float, float) Calc(float x, float v, float xt, float h)
|
||||
{
|
||||
public (float, float) Calc(float x, float v, float xt, float h) {
|
||||
float f = 1 + 2 * h * zeta * omega;
|
||||
float oo = omega * omega;
|
||||
float hoo = oo * h;
|
||||
|
@ -30,8 +26,7 @@ public class SpringDamper
|
|||
return (det_x * det_inv, det_v * det_inv);
|
||||
}
|
||||
|
||||
public (Vector3, Vector3) Calc(Vector3 x, Vector3 v, Vector3 xt, float h)
|
||||
{
|
||||
public (Vector3, Vector3) Calc(Vector3 x, Vector3 v, Vector3 xt, float h) {
|
||||
float f = 1 + 2 * h * zeta * omega;
|
||||
float oo = omega * omega;
|
||||
float hoo = oo * h;
|
||||
|
@ -44,27 +39,24 @@ public class SpringDamper
|
|||
return (det_x * det_inv, det_v * det_inv);
|
||||
}
|
||||
|
||||
public (Vector3, Vector3) CalcClampedSpeed(Vector3 x, Vector3 v, Vector3 xt, float h, float speedMax)
|
||||
{
|
||||
var defaultResult = Calc(x, v, xt, h);
|
||||
public (Vector3, Vector3) CalcClampedSpeed(Vector3 x, Vector3 v, Vector3 xt, float h, float speedMax) {
|
||||
(Vector3, Vector3) defaultResult = Calc(x, v, xt, h);
|
||||
|
||||
Vector3 x_new = defaultResult.Item1;
|
||||
Vector3 vel_new = (x_new - x) / h;
|
||||
float speed_new = vel_new.Length();
|
||||
|
||||
if (speed_new > speedMax)
|
||||
{
|
||||
vel_new = (vel_new / speed_new) * speedMax;
|
||||
if (speed_new > speedMax) {
|
||||
vel_new = vel_new / speed_new * speedMax;
|
||||
x_new = x + vel_new * h;
|
||||
}
|
||||
|
||||
return (x_new, vel_new);
|
||||
}
|
||||
|
||||
public (Vector3, Vector3) CalcClampedSpeedXZ(Vector3 x, Vector3 v, Vector3 xt, float h, float speedMax)
|
||||
{
|
||||
var result_x = Calc(x.x, v.x, xt.x, h);
|
||||
var result_z = Calc(x.z, v.z, xt.z, h);
|
||||
|
||||
public (Vector3, Vector3) CalcClampedSpeedXZ(Vector3 x, Vector3 v, Vector3 xt, float h, float speedMax) {
|
||||
(float, float) result_x = Calc(x.x, v.x, xt.x, h);
|
||||
(float, float) result_z = Calc(x.z, v.z, xt.z, h);
|
||||
|
||||
Vector3 x_new = x;
|
||||
Vector3 v_new = v;
|
||||
|
@ -74,24 +66,23 @@ public class SpringDamper
|
|||
|
||||
x_new.z = result_z.Item1;
|
||||
v_new.z = result_z.Item2;
|
||||
|
||||
Vector3 result_v_xz = new Vector3(
|
||||
|
||||
Vector3 result_v_xz = new(
|
||||
(result_x.Item1 - x.x) / h,
|
||||
0,
|
||||
(result_z.Item1 - x.z) / h);
|
||||
|
||||
|
||||
float speed_new = result_v_xz.Length();
|
||||
|
||||
if (speed_new > speedMax)
|
||||
{
|
||||
result_v_xz = (result_v_xz) / speed_new * speedMax;
|
||||
if (speed_new > speedMax) {
|
||||
result_v_xz = result_v_xz / speed_new * speedMax;
|
||||
x_new.x = x.x + result_v_xz.x * h;
|
||||
x_new.z = x.z + result_v_xz.z * h;
|
||||
}
|
||||
|
||||
v.x = result_v_xz.x;
|
||||
v.z = result_v_xz.z;
|
||||
|
||||
|
||||
return (x_new, v_new);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue