Compare commits
No commits in common. "main" and "WorldChunkRefactoring" have entirely different histories.
main
...
WorldChunk
|
@ -1,28 +1,8 @@
|
|||
# Godot 4+ specific ignores
|
||||
.godot/
|
||||
|
||||
# Godot-specific ignores
|
||||
.import/
|
||||
export.cfg
|
||||
export_presets.cfg
|
||||
|
||||
# Imported translations (automatically generated from CSV files)
|
||||
*.translation
|
||||
|
||||
# Mono-specific ignores
|
||||
.mono/
|
||||
data_*/
|
||||
mono_crash.*.json
|
||||
|
||||
# JetBrains Rider ignores
|
||||
.import/*
|
||||
.mono/*
|
||||
.idea/*
|
||||
android/*
|
||||
|
||||
# project specific ignores
|
||||
addons/gdhexgrid/addons/gut
|
||||
ass
|
||||
assets/KenneySurvivalKit/Previews
|
||||
|
||||
*.swp
|
||||
*.apk
|
||||
*.idsig
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
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,24 +3,18 @@ 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() != 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() != this.GetType()) return false;
|
||||
return Equals((HexCell)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _cubeCoords.GetHashCode();
|
||||
}
|
||||
|
||||
|
@ -35,7 +29,8 @@ 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,
|
||||
|
@ -44,13 +39,13 @@ public class HexCell : IEquatable<HexCell> {
|
|||
DIR_NE
|
||||
};
|
||||
|
||||
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 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 PlaneNormalNE =
|
||||
-new Vector2(Mathf.Cos(Mathf.Deg2Rad(30)), -Mathf.Sin(Mathf.Deg2Rad(30)));
|
||||
|
@ -58,61 +53,76 @@ 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(0, -1);
|
||||
private static readonly Vector2 PlaneNormalS = new Vector2(0, -1);
|
||||
|
||||
private static readonly Vector2 PlaneNormalSW = new(Mathf.Cos(Mathf.Deg2Rad(30)), -Mathf.Sin(Mathf.Deg2Rad(30)));
|
||||
private static readonly Vector2 PlaneNormalSW =
|
||||
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 Vector2 PlaneNormalNW =
|
||||
new Vector2(Mathf.Cos(Mathf.Deg2Rad(-30)), -Mathf.Sin(Mathf.Deg2Rad(-30)));
|
||||
|
||||
private static readonly Plane2D[] BoundaryPlanes = {
|
||||
new(CornerNE, PlaneNormalN),
|
||||
new(CornerNW, PlaneNormalNW),
|
||||
new(CornerW, PlaneNormalSW),
|
||||
new(CornerSW, PlaneNormalS),
|
||||
new(CornerSE, PlaneNormalSE),
|
||||
new(CornerE, PlaneNormalNE)
|
||||
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),
|
||||
};
|
||||
|
||||
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();
|
||||
public static HexCell FromOffsetCoords(Vector2 offsetCoords)
|
||||
{
|
||||
HexCell result = new HexCell();
|
||||
result.OffsetCoords = offsetCoords;
|
||||
|
||||
return result;
|
||||
|
@ -120,10 +130,13 @@ public class HexCell : IEquatable<HexCell> {
|
|||
|
||||
private Vector3 _cubeCoords;
|
||||
|
||||
public Vector3 CubeCoords {
|
||||
get => _cubeCoords;
|
||||
set {
|
||||
if (Mathf.Abs(value.x + value.y + value.z) > 0.0001) {
|
||||
public Vector3 CubeCoords
|
||||
{
|
||||
get { return _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());
|
||||
}
|
||||
|
||||
|
@ -131,21 +144,25 @@ public class HexCell : IEquatable<HexCell> {
|
|||
}
|
||||
}
|
||||
|
||||
public Vector2 AxialCoords {
|
||||
get => new(CubeCoords.x, CubeCoords.y);
|
||||
public Vector2 AxialCoords
|
||||
{
|
||||
get => new Vector2(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;
|
||||
|
@ -153,40 +170,51 @@ 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(
|
||||
public Vector3 RoundCoords(Vector3 cubeCoords)
|
||||
{
|
||||
Vector3 rounded = new Vector3(
|
||||
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(CubeCoords + dir);
|
||||
public HexCell GetAdjacent(Vector3 dir)
|
||||
{
|
||||
return new HexCell(this.CubeCoords + dir);
|
||||
}
|
||||
|
||||
public HexCell[] GetAllAdjacent() {
|
||||
return new[] {
|
||||
public HexCell[] GetAllAdjacent()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
GetAdjacent(DIR_NE),
|
||||
GetAdjacent(DIR_SE),
|
||||
GetAdjacent(DIR_S),
|
||||
|
@ -196,7 +224,8 @@ 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)
|
||||
|
@ -204,14 +233,16 @@ public class HexCell : IEquatable<HexCell> {
|
|||
) / 2;
|
||||
}
|
||||
|
||||
public HexCell[] LineTo(HexCell target) {
|
||||
HexCell nudgedTarget = new();
|
||||
public HexCell[] LineTo(HexCell target)
|
||||
{
|
||||
HexCell nudgedTarget = new HexCell();
|
||||
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);
|
||||
}
|
||||
|
@ -221,23 +252,28 @@ public class HexCell : IEquatable<HexCell> {
|
|||
return path;
|
||||
}
|
||||
|
||||
public void QueryClosestCellBoundary(Vector2 pointLocal, Vector2 dir, out int neighbourIndex, out float distance) {
|
||||
distance = float.PositiveInfinity;
|
||||
public void QueryClosestCellBoundary(Vector2 pointLocal, Vector2 dir, out int neighbourIndex, out float distance)
|
||||
{
|
||||
distance = Single.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 > float.NegativeInfinity && planeDistance < distance) {
|
||||
if (planeDistance > Single.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,7 +4,8 @@ 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);
|
||||
|
@ -23,15 +24,18 @@ 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(
|
||||
|
@ -44,129 +48,135 @@ public class HexGrid : Resource {
|
|||
}
|
||||
}
|
||||
|
||||
public Vector2 GetHexCenter(HexCell cell) {
|
||||
public Vector2 GetHexCenter(HexCell cell)
|
||||
{
|
||||
return _hexTransform * cell.AxialCoords;
|
||||
}
|
||||
|
||||
public Vector2 GetHexCenterFromOffset(Vector2 offsetCoord) {
|
||||
HexCell cell = new HexCell();
|
||||
public Vector2 GetHexCenterFromOffset(Vector2 offsetCoord)
|
||||
{
|
||||
var cell = new HexCell();
|
||||
cell.OffsetCoords = offsetCoord;
|
||||
return GetHexCenter(cell);
|
||||
}
|
||||
|
||||
public Vector3 GetHexCenterVec3FromOffset(Vector2 offsetCoord) {
|
||||
HexCell cell = new HexCell();
|
||||
public Vector3 GetHexCenterVec3FromOffset(Vector2 offsetCoord)
|
||||
{
|
||||
var cell = new HexCell();
|
||||
cell.OffsetCoords = offsetCoord;
|
||||
Vector2 hexCenter = GetHexCenter(cell);
|
||||
var hexCenter = GetHexCenter(cell);
|
||||
return new Vector3(hexCenter.x, 0, hexCenter.y);
|
||||
}
|
||||
|
||||
public HexCell GetHexAtOffset(Vector2 offsetCoord) {
|
||||
HexCell cell = new HexCell();
|
||||
public HexCell GetHexAtOffset(Vector2 offsetCoord)
|
||||
{
|
||||
var cell = new HexCell();
|
||||
cell.OffsetCoords = offsetCoord;
|
||||
return cell;
|
||||
}
|
||||
|
||||
public HexCell GetHexAt(Vector2 planeCoord) {
|
||||
HexCell result = new HexCell(_hexTransformInv * planeCoord);
|
||||
public HexCell GetHexAt(Vector2 planeCoord)
|
||||
{
|
||||
var 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) {
|
||||
Vector2 centerOffset = center.OffsetCoords;
|
||||
public void SetBounds(HexCell center, int size)
|
||||
{
|
||||
var 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) {
|
||||
HexCell startCell = new HexCell(axialCoords);
|
||||
HexCell targetCell = new HexCell(startCell.CubeCoords + directionCube);
|
||||
public float GetMoveCost(Vector2 axialCoords, Vector3 directionCube)
|
||||
{
|
||||
var startCell = new HexCell(axialCoords);
|
||||
var targetCell = new HexCell(startCell.CubeCoords + directionCube);
|
||||
|
||||
float cost = GetHexCost(axialCoords);
|
||||
if (cost == 0) {
|
||||
return 0;
|
||||
}
|
||||
var 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;
|
||||
}
|
||||
|
@ -175,29 +185,32 @@ public class HexGrid : Resource {
|
|||
}
|
||||
|
||||
|
||||
public HexCell GetClosestWalkableCell(HexCell fromCell, HexCell toCell) {
|
||||
if (GetHexCost(toCell) == 0) {
|
||||
HexCell[] line = fromCell.LineTo(toCell);
|
||||
public HexCell GetClosestWalkableCell(HexCell fromCell, HexCell toCell)
|
||||
{
|
||||
if (GetHexCost(toCell) == 0)
|
||||
{
|
||||
var line = fromCell.LineTo(toCell);
|
||||
|
||||
foreach (int i in Enumerable.Range(1, line.Length)) {
|
||||
if (GetHexCost(line[i]) == 0) {
|
||||
foreach (var 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) {
|
||||
Vector2 goalAxialCoords = goalHex.AxialCoords;
|
||||
public List<HexCell> FindPath(HexCell startHex, HexCell goalHex)
|
||||
{
|
||||
var goalAxialCoords = goalHex.AxialCoords;
|
||||
|
||||
SimplePriorityQueue<Vector2, float> frontier = new SimplePriorityQueue<Vector2, float>();
|
||||
var frontier = new SimplePriorityQueue<Vector2, float>();
|
||||
frontier.Enqueue(startHex.AxialCoords, 0);
|
||||
Dictionary<Vector2, Vector2> cameFrom =
|
||||
var cameFrom =
|
||||
new Dictionary<Vector2, Vector2>();
|
||||
Dictionary<Vector2, float> costSoFar =
|
||||
var costSoFar =
|
||||
new Dictionary<Vector2, float>();
|
||||
|
||||
cameFrom.Add(startHex.AxialCoords, startHex.AxialCoords);
|
||||
|
@ -205,34 +218,34 @@ public class HexGrid : Resource {
|
|||
|
||||
FindPathCheckedCellCount = 0;
|
||||
|
||||
while (frontier.Any()) {
|
||||
while (frontier.Any())
|
||||
{
|
||||
FindPathCheckedCellCount++;
|
||||
HexCell currentHex = new HexCell(frontier.Dequeue());
|
||||
Vector2 currentAxial = currentHex.AxialCoords;
|
||||
var currentHex = new HexCell(frontier.Dequeue());
|
||||
var currentAxial = currentHex.AxialCoords;
|
||||
|
||||
if (currentHex == goalHex) {
|
||||
break;
|
||||
}
|
||||
if (currentHex == goalHex) break;
|
||||
|
||||
foreach (HexCell nextHex in currentHex.GetAllAdjacent()) {
|
||||
Vector2 nextAxial = nextHex.AxialCoords;
|
||||
float nextCost = GetMoveCost(currentAxial, new HexCell(nextAxial - currentHex.AxialCoords).CubeCoords);
|
||||
foreach (var nextHex in currentHex.GetAllAdjacent())
|
||||
{
|
||||
var nextAxial = nextHex.AxialCoords;
|
||||
var nextCost = GetMoveCost(currentAxial, new HexCell(nextAxial - currentHex.AxialCoords).CubeCoords);
|
||||
|
||||
if (nextHex == goalHex && GetHexCost(nextAxial) == 0) {
|
||||
if (nextHex == goalHex && GetHexCost(nextAxial) == 0)
|
||||
{
|
||||
// Goal ist an obstacle
|
||||
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;
|
||||
float priority = nextCost + nextHex.DistanceTo(goalHex);
|
||||
var priority = nextCost + nextHex.DistanceTo(goalHex);
|
||||
|
||||
frontier.Enqueue(nextHex.AxialCoords, priority);
|
||||
cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
|
||||
|
@ -242,18 +255,18 @@ public class HexGrid : Resource {
|
|||
|
||||
// GD.Print("Checked Cell Count: " + FindPathCheckedCellCount);
|
||||
|
||||
List<HexCell> result = new List<HexCell>();
|
||||
if (!cameFrom.ContainsKey(goalHex.AxialCoords)) {
|
||||
var 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);
|
||||
|
||||
HexCell pathHex = goalHex;
|
||||
while (pathHex != startHex) {
|
||||
var pathHex = goalHex;
|
||||
while (pathHex != startHex)
|
||||
{
|
||||
pathHex = new HexCell(cameFrom[pathHex.AxialCoords]);
|
||||
result.Insert(0, pathHex);
|
||||
}
|
||||
|
@ -262,20 +275,22 @@ public class HexGrid : Resource {
|
|||
}
|
||||
|
||||
|
||||
public List<HexCell> GetCellsForLine(Vector2 fromPlane, Vector2 toPlane) {
|
||||
List<HexCell> result = new List<HexCell>();
|
||||
public List<HexCell> GetCellsForLine(Vector2 fromPlane, Vector2 toPlane)
|
||||
{
|
||||
var result = new List<HexCell>();
|
||||
|
||||
float distance = (toPlane - fromPlane).Length();
|
||||
Vector2 direction = (toPlane - fromPlane) / distance;
|
||||
var distance = (toPlane - fromPlane).Length();
|
||||
var direction = (toPlane - fromPlane) / distance;
|
||||
|
||||
Vector2 currentPointPlane = fromPlane;
|
||||
HexCell currentCell = GetHexAt(currentPointPlane);
|
||||
var currentPointPlane = fromPlane;
|
||||
var currentCell = GetHexAt(currentPointPlane);
|
||||
float currentDistance = 0;
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
result.Add(currentCell);
|
||||
GetHexCenter(currentCell);
|
||||
Vector2 currentPointLocal = currentPointPlane - GetHexCenter(currentCell);
|
||||
var 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=1
|
||||
flags/repeat=true
|
||||
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=0
|
||||
flags/repeat=true
|
||||
flags/filter=false
|
||||
flags/mipmaps=true
|
||||
flags/anisotropic=false
|
||||
|
|
Binary file not shown.
|
@ -1,50 +0,0 @@
|
|||
[remap]
|
||||
|
||||
importer="scene"
|
||||
importer_version=1
|
||||
type="PackedScene"
|
||||
uid="uid://c7dpvyathtwcn"
|
||||
path="res://.godot/imported/Pirate1_Rigged.blend-ea530b9073238ab11e8923a91a430d84.scn"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/CreatusPiratePack/Modified/Pirate1_Rigged.blend"
|
||||
dest_files=["res://.godot/imported/Pirate1_Rigged.blend-ea530b9073238ab11e8923a91a430d84.scn"]
|
||||
|
||||
[params]
|
||||
|
||||
nodes/root_type=""
|
||||
nodes/root_name=""
|
||||
nodes/apply_root_scale=true
|
||||
nodes/root_scale=1.0
|
||||
meshes/ensure_tangents=true
|
||||
meshes/generate_lods=true
|
||||
meshes/create_shadow_meshes=true
|
||||
meshes/light_baking=1
|
||||
meshes/lightmap_texel_size=0.2
|
||||
meshes/force_disable_compression=false
|
||||
skins/use_named_skins=true
|
||||
animation/import=true
|
||||
animation/fps=30
|
||||
animation/trimming=false
|
||||
animation/remove_immutable_tracks=true
|
||||
import_script/path=""
|
||||
_subresources={}
|
||||
gltf/naming_version=1
|
||||
gltf/embedded_image_handling=1
|
||||
blender/nodes/visible=0
|
||||
blender/nodes/punctual_lights=true
|
||||
blender/nodes/cameras=true
|
||||
blender/nodes/custom_properties=true
|
||||
blender/nodes/modifiers=1
|
||||
blender/meshes/colors=false
|
||||
blender/meshes/uvs=true
|
||||
blender/meshes/normals=true
|
||||
blender/meshes/tangents=true
|
||||
blender/meshes/skins=2
|
||||
blender/meshes/export_bones_deforming_mesh_only=false
|
||||
blender/materials/unpack_enabled=true
|
||||
blender/materials/export_materials=1
|
||||
blender/animation/limit_playback=true
|
||||
blender/animation/always_sample=true
|
||||
blender/animation/group_tracks=true
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
Binary file not shown.
|
@ -2,30 +2,28 @@
|
|||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path.s3tc="res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.s3tc.stex"
|
||||
path.etc2="res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.etc2.stex"
|
||||
path="res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.stex"
|
||||
metadata={
|
||||
"imported_formats": [ "s3tc", "etc2" ],
|
||||
"vram_texture": true
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/IslandMasks/IslandMask2.png"
|
||||
dest_files=[ "res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.s3tc.stex", "res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.etc2.stex" ]
|
||||
dest_files=[ "res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=true
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=1
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
|
@ -33,5 +31,5 @@ process/invert_color=false
|
|||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=false
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
||||
|
|
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -2,21 +2,24 @@ 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;
|
||||
}
|
||||
|
@ -27,21 +30,26 @@ 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,46 +0,0 @@
|
|||
using Godot;
|
||||
|
||||
public class CollectibleComponent : Component {
|
||||
private Vector3 targetPosition;
|
||||
private bool hasTarget;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready() { }
|
||||
|
||||
public void SetTarget(Vector3 target) {
|
||||
targetPosition = target;
|
||||
hasTarget = true;
|
||||
}
|
||||
|
||||
public void UnsetTarget() {
|
||||
hasTarget = false;
|
||||
}
|
||||
|
||||
public void PhysicsProcess(float delta, Entity entity) {
|
||||
if (hasTarget) {
|
||||
if (targetPosition.IsEqualApprox(entity.GlobalTransform.origin)) {
|
||||
targetPosition = entity.GlobalTransform.origin;
|
||||
entity.Velocity = Vector3.Zero;
|
||||
}
|
||||
|
||||
|
||||
Vector3 targetDirection = (targetPosition - entity.GlobalTransform.origin).Normalized();
|
||||
entity.Velocity = targetDirection * (entity.Velocity.Length() + 10 * delta);
|
||||
entity.Transform = new Transform(entity.Transform.basis.Rotated(Vector3.Up, delta * 2.0f),
|
||||
entity.Transform.origin);
|
||||
} else {
|
||||
entity.Velocity = entity.Velocity - 9.81f * delta * Vector3.Up;
|
||||
}
|
||||
|
||||
entity.Velocity = entity.MoveAndSlide(entity.Velocity, Vector3.Up);
|
||||
|
||||
if (entity.IsOnFloor() || Mathf.Abs(entity.Transform.origin.y) < 0.01) {
|
||||
// apply damping when on ground
|
||||
entity.Velocity = entity.Velocity - entity.Velocity.Normalized() * 0.9f * delta;
|
||||
}
|
||||
|
||||
if (entity.Velocity.LengthSquared() < 0.01) {
|
||||
entity.Velocity = Vector3.Zero;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://components/CollectibleComponent.cs" type="Script" id=1]
|
||||
|
||||
[node name="CollectibleComponent" type="Node"]
|
||||
script = ExtResource( 1 )
|
|
@ -1,3 +1,6 @@
|
|||
using Godot;
|
||||
|
||||
public class Component : Node { }
|
||||
public class Component : Node
|
||||
{
|
||||
|
||||
}
|
|
@ -2,7 +2,8 @@ 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;
|
||||
|
@ -13,21 +14,29 @@ public class GroundMotionComponent : Component {
|
|||
public float TargetAngle;
|
||||
public float TargetDeltaAngle;
|
||||
|
||||
private void CalcAndApplyOrientation(float delta, Entity entity, Vector3 targetPosition, float targetAngle) {
|
||||
private void CalcAndApplyOrientation(float delta, Entity entity, Vector3 targetPosition, float targetAngle)
|
||||
{
|
||||
float deltaAngleAbsolute = Mathf.Abs(TargetDeltaAngle);
|
||||
if (deltaAngleAbsolute > 0.001) {
|
||||
if (RotationSpeedRadPerSecond * delta >= deltaAngleAbsolute) {
|
||||
if (deltaAngleAbsolute > 0.001)
|
||||
{
|
||||
if (RotationSpeedRadPerSecond * delta >= deltaAngleAbsolute)
|
||||
{
|
||||
entity.PlaneAngle = TargetAngle;
|
||||
TargetDeltaAngle = 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
entity.PlaneAngle += Mathf.Sign(TargetDeltaAngle) * RotationSpeedRadPerSecond * delta;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
TargetDeltaAngle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void CalcPlaneVelocity(float delta, Entity entity, Vector3 targetPosition) {
|
||||
private void CalcPlaneVelocity(float delta, Entity entity, Vector3 targetPosition)
|
||||
{
|
||||
Vector2 planeTargetDirection = new(DirectionToTarget.x, DirectionToTarget.z);
|
||||
|
||||
Vector2 planeVelocity = new(entity.Velocity.x, entity.Velocity.z);
|
||||
|
@ -35,25 +44,29 @@ public class GroundMotionComponent : Component {
|
|||
planeVelocity -= planeVelocity * Damping;
|
||||
// GD.Print(" damp : speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
||||
|
||||
if (DistanceToTarget < 0.01) {
|
||||
if (DistanceToTarget < 0.01)
|
||||
{
|
||||
planeVelocity = Vector2.Zero;
|
||||
} else if (TargetDeltaAngle == 0.0) {
|
||||
}
|
||||
else if (TargetDeltaAngle == 0.0)
|
||||
{
|
||||
planeVelocity = planeVelocity.Length() * planeTargetDirection + planeTargetDirection * Accel * delta;
|
||||
// GD.Print(" accel: speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
||||
|
||||
float projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
|
||||
// GD.Print(" Projected step: " + projectedStep + " Speed: " + planeVelocity.Length() + " delta: " + delta);
|
||||
if (projectedStep > DistanceToTarget) {
|
||||
if (projectedStep > DistanceToTarget)
|
||||
{
|
||||
planeVelocity *= DistanceToTarget / projectedStep;
|
||||
projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
|
||||
// GD.Print(" corr speed: " + planeVelocity.Length() + " step: " + projectedStep);
|
||||
}
|
||||
|
||||
float planeSpeed = planeVelocity.Length();
|
||||
if (planeSpeed > MaxSpeed) {
|
||||
planeVelocity *= MaxSpeed / planeSpeed;
|
||||
}
|
||||
} else {
|
||||
if (planeSpeed > MaxSpeed) planeVelocity *= MaxSpeed / planeSpeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
planeVelocity = Vector2.Zero;
|
||||
}
|
||||
|
||||
|
@ -61,19 +74,22 @@ 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;
|
||||
|
||||
|
@ -89,26 +105,32 @@ 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,18 +2,20 @@ using Godot;
|
|||
|
||||
namespace GodotComponentTest.components;
|
||||
|
||||
public class InteractionComponent : Component {
|
||||
public class InteractionComponent: Component
|
||||
{
|
||||
[Signal]
|
||||
private delegate void InteractionStart(Spatial owningEntity, Spatial targetEntity);
|
||||
|
||||
delegate void InteractionStart(Spatial owningEntity, Spatial targetEntity);
|
||||
|
||||
[Signal]
|
||||
private delegate void InteractionEnd(Spatial owningEntity, Spatial targetEntity);
|
||||
delegate void InteractionEnd(Spatial owningEntity, Spatial targetEntity);
|
||||
|
||||
public void EndInteraction() {
|
||||
public void EndInteraction()
|
||||
{
|
||||
hasStopped = true;
|
||||
}
|
||||
|
||||
public bool hasStopped;
|
||||
public bool hasStopped = false;
|
||||
public Spatial OwningEntity;
|
||||
public Spatial TargetEntity;
|
||||
}
|
|
@ -1,13 +1,15 @@
|
|||
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;
|
||||
public float currentAngle;
|
||||
public float currentAngularVelocity;
|
||||
public float targetAngle = 0;
|
||||
public float currentAngle = 0;
|
||||
public float currentAngularVelocity = 0;
|
||||
|
||||
[Export] public float maxSpeed = 3;
|
||||
|
||||
|
@ -15,55 +17,62 @@ public class MovableComponent : Component {
|
|||
private SpringDamper _angleSpringDamper;
|
||||
|
||||
[Signal]
|
||||
private delegate void PositionUpdated(Vector3 newPosition);
|
||||
delegate void PositionUpdated(Vector3 newPosition);
|
||||
|
||||
[Signal]
|
||||
private delegate void OrientationUpdated(float newAngle);
|
||||
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) {
|
||||
(float, float) springDamperResult =
|
||||
if (Mathf.Abs(currentAngularVelocity) > 0.1 || Mathf.Abs(targetAngle - currentAngle) > 0.01)
|
||||
{
|
||||
var springDamperResult =
|
||||
_angleSpringDamper.Calc(currentAngle, currentAngularVelocity, targetAngle, delta);
|
||||
|
||||
currentAngle = springDamperResult.Item1;
|
||||
currentAngularVelocity = springDamperResult.Item2;
|
||||
|
||||
EmitSignal("OrientationUpdated", currentAngle);
|
||||
EmitSignal("OrientationUpdated", this.currentAngle);
|
||||
}
|
||||
|
||||
if (Mathf.Abs(currentAngularVelocity) < 5 && Mathf.Abs(targetAngle - currentAngle) < 0.3
|
||||
&& (targetPosition - currentPosition).LengthSquared() > 0.01) {
|
||||
(Vector3, Vector3) springDamperResult =
|
||||
if ((Mathf.Abs(currentAngularVelocity) < 5 && Mathf.Abs(targetAngle - currentAngle) < 0.3)
|
||||
&& (targetPosition - currentPosition).LengthSquared() > 0.01)
|
||||
{
|
||||
var 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,9 +7,8 @@ using GodotComponentTest.utils;
|
|||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public class NavigationComponent : Spatial {
|
||||
[Export] public bool PathSmoothing = false;
|
||||
|
||||
public class NavigationComponent : Spatial
|
||||
{
|
||||
public World World { set; get; }
|
||||
public Vector3 CurrentGoalPositionWorld { get; private set; } = Vector3.Zero;
|
||||
public float CurrentGoalAngleWorld { get; private set; }
|
||||
|
@ -17,57 +16,69 @@ public class NavigationComponent : Spatial {
|
|||
private NavigationPoint _currentGoal;
|
||||
private HexCell[] _path;
|
||||
private List<NavigationPoint> _pathWorldNavigationPoints = new();
|
||||
private List<NavigationPoint> _activePathWorldNavigationPoints = new();
|
||||
private List<NavigationPoint> _planningPathSmoothedWorldNavigationPoints = new();
|
||||
|
||||
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(Entity body, Transform fromTransformWorld, NavigationPoint navigationPoint) {
|
||||
public void PlanSmoothedPath(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))
|
||||
{
|
||||
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(Entity entity, Vector3 fromPositionWorld, Vector3 toPositionWorld) {
|
||||
HexCell fromCell = World.HexGrid.GetHexAt(new Vector2(fromPositionWorld.x, fromPositionWorld.z));
|
||||
if (World.HexGrid.GetHexCost(fromCell) == 0) {
|
||||
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)
|
||||
{
|
||||
GD.Print("Invalid starting point for FindPath(): returning empty path.");
|
||||
_planningPathWorldNavigationPoints = new List<NavigationPoint>();
|
||||
_planningPathWorldNavigationPoints.Add(new NavigationPoint(fromPositionWorld));
|
||||
_activePathWorldNavigationPoints = _planningPathWorldNavigationPoints;
|
||||
_planningPathSmoothedWorldNavigationPoints = _planningPathWorldNavigationPoints;
|
||||
return;
|
||||
}
|
||||
|
||||
HexCell toCell = World.HexGrid.GetHexAt(new Vector2(toPositionWorld.x, toPositionWorld.z));
|
||||
var 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));
|
||||
_activePathWorldNavigationPoints = _planningPathWorldNavigationPoints;
|
||||
_planningPathSmoothedWorldNavigationPoints = _planningPathWorldNavigationPoints;
|
||||
return;
|
||||
}
|
||||
|
||||
List<HexCell> path = World.FindPath(entity, fromCell, toCell);
|
||||
var path = World.HexGrid.FindPath(fromCell, toCell);
|
||||
|
||||
// Generate grid navigation points
|
||||
_planningPathWorldNavigationPoints = new List<NavigationPoint>();
|
||||
foreach (int index in Enumerable.Range(0, path.Count)) {
|
||||
foreach (var index in Enumerable.Range(0, path.Count))
|
||||
{
|
||||
_planningPathWorldNavigationPoints.Add(
|
||||
new NavigationPoint(World.HexGrid.GetHexCenterVec3FromOffset(path[index].OffsetCoords)));
|
||||
}
|
||||
|
@ -75,44 +86,40 @@ 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
|
||||
if (PathSmoothing)
|
||||
{
|
||||
_activePathWorldNavigationPoints = World.SmoothPath(entity, _planningPathWorldNavigationPoints);
|
||||
}
|
||||
else
|
||||
{
|
||||
_activePathWorldNavigationPoints = _planningPathWorldNavigationPoints;
|
||||
}
|
||||
|
||||
|
||||
_planningPathSmoothedWorldNavigationPoints = SmoothPath(body, _planningPathWorldNavigationPoints);
|
||||
|
||||
// Ensure starting point is the current position
|
||||
if (_activePathWorldNavigationPoints.Count > 0) {
|
||||
_activePathWorldNavigationPoints[0] = new NavigationPoint(fromPositionWorld);
|
||||
if (_planningPathSmoothedWorldNavigationPoints.Count > 0)
|
||||
{
|
||||
_planningPathSmoothedWorldNavigationPoints[0] = new NavigationPoint(fromPositionWorld);
|
||||
}
|
||||
}
|
||||
|
||||
public void FindPath(Entity entity, Vector3 fromPositionWorld, NavigationPoint navigationPoint) {
|
||||
FindPath(entity, fromPositionWorld, navigationPoint.WorldPosition);
|
||||
public void FindPath(KinematicBody body, Vector3 fromPositionWorld, NavigationPoint navigationPoint)
|
||||
{
|
||||
FindPath(body, fromPositionWorld, navigationPoint.WorldPosition);
|
||||
|
||||
_planningPathWorldNavigationPoints[_planningPathWorldNavigationPoints.Count - 1] = navigationPoint;
|
||||
_activePathWorldNavigationPoints[_activePathWorldNavigationPoints.Count - 1] =
|
||||
_planningPathSmoothedWorldNavigationPoints[_planningPathSmoothedWorldNavigationPoints.Count - 1] =
|
||||
navigationPoint;
|
||||
}
|
||||
|
||||
public void PlanGridPath(Entity entity, Vector3 fromPositionWorld, Vector3 toPositionWorld) {
|
||||
Vector2 fromPositionOffset = World.WorldToOffsetCoords(fromPositionWorld);
|
||||
Vector2 toPositionOffset = World.WorldToOffsetCoords(toPositionWorld);
|
||||
public void PlanGridPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld)
|
||||
{
|
||||
var fromPositionOffset = World.WorldToOffsetCoords(fromPositionWorld);
|
||||
var toPositionOffset = World.WorldToOffsetCoords(toPositionWorld);
|
||||
|
||||
HexCell fromCell = new();
|
||||
var fromCell = new HexCell();
|
||||
fromCell.OffsetCoords = fromPositionOffset;
|
||||
|
||||
HexCell toCell = new();
|
||||
var toCell = new HexCell();
|
||||
toCell.OffsetCoords = toPositionOffset;
|
||||
|
||||
_path = fromCell.LineTo(toCell);
|
||||
|
@ -122,23 +129,26 @@ public class NavigationComponent : Spatial {
|
|||
_pathWorldNavigationPoints.Add(
|
||||
new NavigationPoint(World.HexGrid.GetHexCenterVec3FromOffset(fromPositionOffset)));
|
||||
|
||||
foreach (int index in Enumerable.Range(1, _path.Length - 1)) {
|
||||
foreach (var 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) {
|
||||
// Remove the last one, because it is only the position rounded to HexGrid coordinates.
|
||||
if (_pathWorldNavigationPoints.Count > 0)
|
||||
{
|
||||
_pathWorldNavigationPoints.RemoveAt(_pathWorldNavigationPoints.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
_pathWorldNavigationPoints.Add(new NavigationPoint(toPositionWorld));
|
||||
if (_pathWorldNavigationPoints.Count > 2) {
|
||||
_smoothedPathWorldNavigationPoints = SmoothPath(entity, _pathWorldNavigationPoints);
|
||||
if (_pathWorldNavigationPoints.Count > 2)
|
||||
{
|
||||
_smoothedPathWorldNavigationPoints = SmoothPath(body, _pathWorldNavigationPoints);
|
||||
_pathWorldNavigationPoints = _smoothedPathWorldNavigationPoints;
|
||||
}
|
||||
|
||||
|
@ -146,28 +156,36 @@ public class NavigationComponent : Spatial {
|
|||
}
|
||||
|
||||
|
||||
public void PlanGridPath(Entity entity, Vector3 fromPositionWorld, Vector3 toPositionWorld,
|
||||
Quat toWorldOrientation) {
|
||||
PlanGridPath(entity, fromPositionWorld, toPositionWorld);
|
||||
public void PlanGridPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld,
|
||||
Quat toWorldOrientation)
|
||||
{
|
||||
PlanGridPath(body, fromPositionWorld, toPositionWorld);
|
||||
|
||||
_pathWorldNavigationPoints.Add(new NavigationPoint(toWorldOrientation));
|
||||
}
|
||||
|
||||
|
||||
public void PlanGridPath(Entity entity, Transform fromTransformWorld, NavigationPoint navigationPoint) {
|
||||
public void PlanGridPath(KinematicBody body, Transform fromTransformWorld, NavigationPoint navigationPoint)
|
||||
{
|
||||
if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)
|
||||
&& navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation)) {
|
||||
PlanGridPath(entity, fromTransformWorld.origin, navigationPoint.WorldPosition,
|
||||
&& navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation))
|
||||
{
|
||||
PlanGridPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition,
|
||||
navigationPoint.WorldOrientation);
|
||||
} else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)) {
|
||||
PlanGridPath(entity, fromTransformWorld.origin, navigationPoint.WorldPosition);
|
||||
} else {
|
||||
}
|
||||
else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position))
|
||||
{
|
||||
PlanGridPath(body, 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));
|
||||
|
||||
|
@ -176,20 +194,23 @@ 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;
|
||||
|
@ -199,30 +220,37 @@ public class NavigationComponent : Spatial {
|
|||
}
|
||||
|
||||
|
||||
public bool CheckSweptTriangleCellCollision(Vector3 startWorld, Vector3 endWorld, float radius) {
|
||||
Vector2 startPlane = new(startWorld.x, startWorld.z);
|
||||
Vector2 endPlane = new(endWorld.x, endWorld.z);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -230,24 +258,29 @@ 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> smoothedPath = new List<NavigationPoint>();
|
||||
|
||||
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;
|
||||
|
@ -261,7 +294,8 @@ public class NavigationComponent : Spatial {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (endIndex == navigationPoints.Count - 1) {
|
||||
if (endIndex == navigationPoints.Count - 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -274,25 +308,34 @@ 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() {
|
||||
_pathWorldNavigationPoints = _activePathWorldNavigationPoints;
|
||||
public void ActivatePlannedPath()
|
||||
{
|
||||
_pathWorldNavigationPoints = _planningPathSmoothedWorldNavigationPoints;
|
||||
UpdateCurrentGoal();
|
||||
}
|
||||
|
||||
private void UpdateCurrentGoal() {
|
||||
if (_pathWorldNavigationPoints.Count == 0) {
|
||||
private void UpdateCurrentGoal()
|
||||
{
|
||||
if (_pathWorldNavigationPoints.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -301,56 +344,73 @@ 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;
|
||||
|
@ -368,7 +428,8 @@ 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);
|
||||
|
||||
|
@ -376,7 +437,8 @@ 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);
|
||||
|
@ -385,7 +447,8 @@ 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);
|
||||
|
@ -394,7 +457,8 @@ public class NavigationComponent : Spatial {
|
|||
}
|
||||
|
||||
previousPoint = parentNode.GlobalTranslation;
|
||||
foreach (NavigationPoint point in _activePathWorldNavigationPoints) {
|
||||
foreach (NavigationPoint point in _planningPathSmoothedWorldNavigationPoints)
|
||||
{
|
||||
debugGeometry.SetColor(new Color(1, 1, 0));
|
||||
debugGeometry.AddVertex(previousPoint + yOffset);
|
||||
debugGeometry.AddVertex(point.WorldPosition + yOffset);
|
||||
|
|
|
@ -1,39 +1,42 @@
|
|||
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 {
|
||||
Task currentTask = Queue.Peek();
|
||||
do
|
||||
{
|
||||
var currentTask = Queue.Peek();
|
||||
|
||||
if (currentTask.PerformTask(entity, this, delta)) {
|
||||
if (currentTask.PerformTask(entity, this, delta))
|
||||
Queue.Dequeue();
|
||||
} else {
|
||||
else
|
||||
break;
|
||||
}
|
||||
} while (Queue.Count > 0);
|
||||
}
|
||||
|
||||
public abstract class Task : Object {
|
||||
public abstract class Task : Object
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes a Task on the specified entity.
|
||||
/// </summary>
|
||||
|
@ -44,27 +47,33 @@ public class TaskQueueComponent : Component {
|
|||
/// <summary>
|
||||
/// Makes an entity move towards a target (translation and or orientation).
|
||||
/// </summary>
|
||||
public class NavigationTask : Task {
|
||||
public class NavigationTask : Task
|
||||
{
|
||||
public NavigationPoint NavigationPoint;
|
||||
public bool PlanningComplete = false;
|
||||
|
||||
public NavigationTask(NavigationPoint navigationPoint) {
|
||||
public NavigationTask(NavigationPoint navigationPoint)
|
||||
{
|
||||
NavigationPoint = navigationPoint;
|
||||
}
|
||||
|
||||
public override bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta) {
|
||||
public override bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta)
|
||||
{
|
||||
return NavigationPoint.IsReached(entity.GlobalTransform);
|
||||
}
|
||||
}
|
||||
|
||||
public class InteractionTask : Task {
|
||||
public class InteractionTask : Task
|
||||
{
|
||||
public Entity TargetEntity;
|
||||
|
||||
public InteractionTask(Entity entity) {
|
||||
public InteractionTask(Entity entity)
|
||||
{
|
||||
TargetEntity = entity;
|
||||
}
|
||||
|
||||
public override bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta) {
|
||||
public override bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta)
|
||||
{
|
||||
taskQueueComponent.EmitSignal("StartInteraction", entity, TargetEntity);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
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 +1,11 @@
|
|||
public class Axe : Entity { }
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
public class Axe : StaticBody
|
||||
{
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
[gd_scene load_steps=5 format=2]
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://assets/Objects/toolAxe.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://entities/Axe.cs" type="Script" id=2]
|
||||
[ext_resource path="res://components/CollectibleComponent.tscn" type="PackedScene" id=3]
|
||||
|
||||
[sub_resource type="CylinderShape" id=1]
|
||||
height = 0.846435
|
||||
radius = 0.687167
|
||||
|
||||
[node name="Axe" type="KinematicBody"]
|
||||
[node name="Axe" type="StaticBody"]
|
||||
collision_layer = 9
|
||||
collision_mask = 0
|
||||
script = ExtResource( 2 )
|
||||
|
@ -19,5 +18,3 @@ shape = SubResource( 1 )
|
|||
|
||||
[node name="toolAxe" parent="." instance=ExtResource( 1 )]
|
||||
transform = Transform( 0.707107, 0.707107, -3.09086e-08, 4.37114e-08, 1.91069e-15, 1, 0.707107, -0.707107, -3.09086e-08, -0.323064, 0.0760467, 0.348457 )
|
||||
|
||||
[node name="CollectibleComponent" parent="." instance=ExtResource( 3 )]
|
||||
|
|
|
@ -3,11 +3,13 @@ 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
|
||||
}
|
||||
|
@ -27,7 +29,8 @@ 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");
|
||||
|
||||
|
@ -39,52 +42,65 @@ 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 overrideMaterial = new SpatialMaterial();
|
||||
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.Velocity = new Vector3(
|
||||
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,
|
||||
(GD.Randf() * 2f - 1f) * 2
|
||||
|
@ -92,7 +108,8 @@ public class Chest : Entity, IInteractionInterface {
|
|||
GetParent().AddChild(bar);
|
||||
}
|
||||
|
||||
if (InteractionComponent != null) {
|
||||
if (InteractionComponent != null)
|
||||
{
|
||||
InteractionComponent.EndInteraction();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,8 +79,8 @@ tracks/2/keys = {
|
|||
|
||||
[sub_resource type="PrismMesh" id=15]
|
||||
|
||||
[sub_resource type="SphereShape" id=19]
|
||||
radius = 0.359562
|
||||
[sub_resource type="BoxShape" id=16]
|
||||
extents = Vector3( 0.19, 0.19, 0.33 )
|
||||
|
||||
[sub_resource type="CubeMesh" id=17]
|
||||
size = Vector3( 0.38, 0.38, 0.66 )
|
||||
|
@ -133,8 +133,8 @@ skeleton = NodePath("../..")
|
|||
[node name="ResourceContainer" type="Node" parent="."]
|
||||
|
||||
[node name="CollisionShape" type="CollisionShape" parent="."]
|
||||
transform = Transform( -0.866026, 0, 0.5, 0, 1, 0, -0.5, 0, -0.866026, 0, 0.110576, 0 )
|
||||
shape = SubResource( 19 )
|
||||
transform = Transform( -0.866026, 0, 0.5, 0, 1, 0, -0.5, 0, -0.866026, 0, 0.240716, 0 )
|
||||
shape = SubResource( 16 )
|
||||
|
||||
[node name="MeshInstance" type="MeshInstance" parent="CollisionShape" groups=["PhysicsGeometry"]]
|
||||
mesh = SubResource( 17 )
|
||||
|
|
|
@ -1,61 +1,30 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
public class Entity : KinematicBody {
|
||||
[Flags]
|
||||
public enum EntityMaskEnum {
|
||||
Obstacle = 1 << 0,
|
||||
Ground = 1 << 1,
|
||||
Water = 1 << 2
|
||||
}
|
||||
|
||||
[Export(PropertyHint.Flags, "Obstacle,Ground,Water")]
|
||||
public int EntityMask { get; set; }
|
||||
|
||||
public class Entity : KinematicBody
|
||||
{
|
||||
public Vector3 Velocity { get; set; } = Vector3.Zero;
|
||||
public float RotationalVelocity { get; set; } = 0;
|
||||
|
||||
private CollectibleComponent _collectibleComponent;
|
||||
|
||||
public override void _Ready() {
|
||||
base._Ready();
|
||||
|
||||
foreach (Node node in GetChildren()) {
|
||||
if (node is CollectibleComponent) {
|
||||
Debug.Assert(_collectibleComponent == null);
|
||||
_collectibleComponent = node as CollectibleComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void _PhysicsProcess(float delta) {
|
||||
base._PhysicsProcess(delta);
|
||||
|
||||
if (_collectibleComponent != null) {
|
||||
_collectibleComponent.PhysicsProcess(delta, this);
|
||||
}
|
||||
}
|
||||
|
||||
public CollectibleComponent GetCollectibleComponent() {
|
||||
return _collectibleComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 +1,61 @@
|
|||
public class GoldBar : Entity { }
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
public class GoldBar : KinematicBody
|
||||
{
|
||||
private Vector3 targetPosition;
|
||||
private bool hasTarget = false;
|
||||
public Vector3 velocity;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
targetPosition = GlobalTransform.origin;
|
||||
}
|
||||
|
||||
public void SetTarget(Vector3 target)
|
||||
{
|
||||
targetPosition = target;
|
||||
hasTarget = true;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
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
|
||||
{
|
||||
velocity.y = velocity.y - 9.81f * delta;
|
||||
}
|
||||
|
||||
velocity = MoveAndSlide(velocity, Vector3.Up);
|
||||
|
||||
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)
|
||||
{
|
||||
velocity = Vector3.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
[gd_scene load_steps=5 format=2]
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://entities/GoldBar.cs" type="Script" id=1]
|
||||
[ext_resource path="res://assets/CreatusPiratePack/Models/Items/gltf/Gold_Bar.glb" type="PackedScene" id=2]
|
||||
[ext_resource path="res://components/CollectibleComponent.tscn" type="PackedScene" id=3]
|
||||
|
||||
[sub_resource type="BoxShape" id=21]
|
||||
extents = Vector3( 0.354271, 0.0817164, 0.173406 )
|
||||
|
@ -17,10 +16,8 @@ script = ExtResource( 1 )
|
|||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.084728, 0 )
|
||||
shape = SubResource( 21 )
|
||||
|
||||
[node name="Geometry" type="Spatial" parent="."]
|
||||
[node name="Spatial" type="Spatial" parent="."]
|
||||
transform = Transform( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0 )
|
||||
|
||||
[node name="Gold_Bar" parent="Geometry" instance=ExtResource( 2 )]
|
||||
[node name="Gold_Bar" parent="Spatial" instance=ExtResource( 2 )]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 21.335, -0.022, -6.533 )
|
||||
|
||||
[node name="CollectibleComponent" parent="." instance=ExtResource( 3 )]
|
||||
|
|
|
@ -2,9 +2,14 @@ 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,21 +5,16 @@ 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;
|
||||
|
||||
public int WoodCount;
|
||||
public int GoldCount;
|
||||
public bool HasAxe;
|
||||
|
||||
public TaskQueueComponent TaskQueueComponent;
|
||||
public NavigationComponent NavigationComponent { get; private set; }
|
||||
public InteractionComponent InteractionComponent { get; set; }
|
||||
|
||||
[Signal]
|
||||
private delegate void WoodCountChanged(int woodCount);
|
||||
|
||||
[Signal]
|
||||
private delegate void GoldCountChanged(int goldCount);
|
||||
|
||||
|
@ -35,7 +30,8 @@ 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);
|
||||
|
@ -43,28 +39,33 @@ 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);
|
||||
AnimationNodeStateMachinePlayback stateMachine =
|
||||
var stateMachine =
|
||||
(AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
|
||||
stateMachine.Start("Idle");
|
||||
|
||||
_toolAttachement = (BoneAttachment)FindNode("ToolAttachement");
|
||||
if (_toolAttachement == null) {
|
||||
if (_toolAttachement == null)
|
||||
{
|
||||
GD.PushWarning("No ToolAttachement found!");
|
||||
}
|
||||
|
||||
|
@ -72,20 +73,25 @@ public class Player : Entity, IInteractionInterface {
|
|||
}
|
||||
|
||||
|
||||
public override void _PhysicsProcess(float delta) {
|
||||
public override void _PhysicsProcess(float delta)
|
||||
{
|
||||
base._PhysicsProcess(delta);
|
||||
|
||||
if (NavigationComponent == null) {
|
||||
if (NavigationComponent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (TaskQueueComponent != null && TaskQueueComponent.Queue.Count > 0) {
|
||||
if (TaskQueueComponent != null && TaskQueueComponent.Queue.Count > 0)
|
||||
{
|
||||
TaskQueueComponent.Process(this, delta);
|
||||
|
||||
if (TaskQueueComponent.Queue.Count > 0) {
|
||||
TaskQueueComponent.Task currentTask = TaskQueueComponent.Queue.Peek();
|
||||
if (TaskQueueComponent.Queue.Count > 0)
|
||||
{
|
||||
var 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);
|
||||
|
||||
|
@ -97,112 +103,115 @@ 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) {
|
||||
Entity entity = node as Entity;
|
||||
if (entity != null) {
|
||||
CollectibleComponent collectibleComponent = entity.GetCollectibleComponent();
|
||||
if (collectibleComponent != null) {
|
||||
collectibleComponent.SetTarget(GlobalTransform.origin);
|
||||
}
|
||||
foreach (Node node in _attractedItemList)
|
||||
{
|
||||
if (node is GoldBar)
|
||||
{
|
||||
GoldBar bar = (GoldBar)node;
|
||||
bar.SetTarget(GlobalTransform.origin);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
Entity entity = node as Entity;
|
||||
if (entity != null) {
|
||||
CollectibleComponent collectibleComponent = entity.GetCollectibleComponent();
|
||||
if (collectibleComponent != null) {
|
||||
collectibleComponent.UnsetTarget();
|
||||
}
|
||||
public void OnItemAttractorBodyExited(Node node)
|
||||
{
|
||||
if (node is GoldBar)
|
||||
{
|
||||
GoldBar bar = (GoldBar)node;
|
||||
bar.UnsetTarget();
|
||||
}
|
||||
|
||||
_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);
|
||||
} else if (body is Wood) {
|
||||
WoodCount++;
|
||||
EmitSignal("WoodCountChanged", WoodCount);
|
||||
}
|
||||
|
||||
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;
|
||||
HasAxe = true;
|
||||
} else if (toolName == "") {
|
||||
}
|
||||
else if (toolName == "")
|
||||
{
|
||||
_toolAttachement.Visible = false;
|
||||
HasAxe = 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) {
|
||||
if (!HasAxe) {
|
||||
GD.Print("Not chopping tree, player has no Axe!");
|
||||
InteractionComponent.EndInteraction();
|
||||
stateMachine.Travel("Shrug-loop");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
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,4 +1,4 @@
|
|||
[gd_scene load_steps=26 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]
|
||||
|
@ -28,6 +28,277 @@ radius = 0.1
|
|||
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"
|
||||
|
||||
|
@ -37,9 +308,6 @@ animation = "Idle-loop"
|
|||
[sub_resource type="AnimationNodeAnimation" id=3]
|
||||
animation = "Interaction-loop"
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id=35]
|
||||
animation = "Shrug-loop"
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id=4]
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id=5]
|
||||
|
@ -53,26 +321,15 @@ xfade_time = 0.1
|
|||
switch_mode = 2
|
||||
xfade_time = 0.3
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id=36]
|
||||
xfade_time = 0.1
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id=37]
|
||||
switch_mode = 2
|
||||
auto_advance = true
|
||||
xfade_time = 0.1
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachine" id=8]
|
||||
states/Hit/node = SubResource( 1 )
|
||||
states/Hit/position = Vector2( 413, 37 )
|
||||
states/Hit/position = Vector2( 415, 45 )
|
||||
states/Idle/node = SubResource( 2 )
|
||||
states/Idle/position = Vector2( 157, 37 )
|
||||
states/Idle/position = Vector2( 149, 39 )
|
||||
states/Interaction/node = SubResource( 3 )
|
||||
states/Interaction/position = Vector2( 157, 162 )
|
||||
states/Shrug-loop/node = SubResource( 35 )
|
||||
states/Shrug-loop/position = Vector2( -53, 37 )
|
||||
transitions = [ "Idle", "Hit", SubResource( 4 ), "Hit", "Idle", SubResource( 5 ), "Idle", "Interaction", SubResource( 6 ), "Interaction", "Idle", SubResource( 33 ), "Idle", "Shrug-loop", SubResource( 36 ), "Shrug-loop", "Idle", SubResource( 37 ) ]
|
||||
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"
|
||||
graph_offset = Vector2( -175, -42 )
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachinePlayback" id=34]
|
||||
|
||||
|
@ -140,17 +397,27 @@ generate_lightmap = false
|
|||
[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, 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 )
|
||||
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("../PirateAsset/AnimationPlayer")
|
||||
anim_player = NodePath("../AnimationPlayer")
|
||||
active = true
|
||||
parameters/playback = SubResource( 34 )
|
||||
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
using GodotComponentTest.components;
|
||||
using GodotComponentTest.entities;
|
||||
|
||||
public class Tree : StaticBody, IInteractionInterface {
|
||||
private readonly PackedScene _woodScene = GD.Load<PackedScene>("res://entities/Wood.tscn");
|
||||
|
||||
public class Tree : StaticBody, IInteractionInterface
|
||||
{
|
||||
[Export] public float ChopDuration = 2;
|
||||
public bool IsMouseOver;
|
||||
public InteractionComponent InteractionComponent { get; set; }
|
||||
|
@ -16,16 +14,13 @@ public class Tree : StaticBody, IInteractionInterface {
|
|||
private AnimationPlayer _animationPlayer;
|
||||
private float _health = 100;
|
||||
private bool _isBeingChopped;
|
||||
private bool _isDead;
|
||||
|
||||
[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");
|
||||
|
@ -38,61 +33,56 @@ 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 (!_isDead && _health == 0) {
|
||||
if (_health == 0)
|
||||
{
|
||||
InteractionComponent.EndInteraction();
|
||||
InteractionComponent.TargetEntity = null;
|
||||
GD.Print("Tree chopped!");
|
||||
|
||||
int numWoodLogs = (int)(GD.Randi() % 2) + 1;
|
||||
|
||||
foreach (int i in Enumerable.Range(1, numWoodLogs)) {
|
||||
Wood wood = (Wood)_woodScene.Instance();
|
||||
wood.Transform = new Transform(Transform.basis.Rotated(Vector3.Up, GD.Randf() * 2 * Mathf.Pi),
|
||||
Transform.origin + Vector3.Up * 0.8f);
|
||||
wood.Velocity = new Vector3(
|
||||
(GD.Randf() * 2f - 1f) * 1.2f,
|
||||
5 + GD.Randf() * 0.3f,
|
||||
(GD.Randf() * 2f - 1f) * 1.2f
|
||||
);
|
||||
GetParent().AddChild(wood);
|
||||
}
|
||||
|
||||
_isDead = true;
|
||||
|
||||
EmitSignal("TreeChopped", this);
|
||||
QueueFree();
|
||||
}
|
||||
}
|
||||
|
||||
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 overrideMaterial = new SpatialMaterial();
|
||||
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);
|
||||
|
@ -100,10 +90,11 @@ 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 )
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
public class Wood : Entity { }
|
|
@ -1,25 +0,0 @@
|
|||
[gd_scene load_steps=5 format=2]
|
||||
|
||||
[ext_resource path="res://entities/Wood.cs" type="Script" id=1]
|
||||
[ext_resource path="res://assets/KenneySurvivalKit/Models/resourceWood.glb" type="PackedScene" id=2]
|
||||
[ext_resource path="res://components/CollectibleComponent.tscn" type="PackedScene" id=3]
|
||||
|
||||
[sub_resource type="BoxShape" id=21]
|
||||
extents = Vector3( 0.344943, 0.0817164, 0.173406 )
|
||||
|
||||
[node name="Wood" type="KinematicBody"]
|
||||
collision_layer = 9
|
||||
collision_mask = 0
|
||||
input_ray_pickable = false
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="CollisionShape" type="CollisionShape" parent="."]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.084728, 0 )
|
||||
shape = SubResource( 21 )
|
||||
|
||||
[node name="Geometry" type="Spatial" parent="."]
|
||||
transform = Transform( 2.12132, 0, -2.12132, 0, 3, 0, 2.12132, 0, 2.12132, 0, 0, 0 )
|
||||
|
||||
[node name="resourceWood" parent="Geometry" instance=ExtResource( 2 )]
|
||||
|
||||
[node name="CollectibleComponent" parent="." instance=ExtResource( 3 )]
|
|
@ -1,49 +0,0 @@
|
|||
using System.Diagnostics;
|
||||
using Godot;
|
||||
|
||||
public class Workbench : Entity {
|
||||
public bool IsMouseOver;
|
||||
|
||||
private MeshInstance _geometry;
|
||||
|
||||
[Signal]
|
||||
public delegate void EntityClicked(Entity entity);
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready() {
|
||||
_geometry = GetNode<MeshInstance>("Geometry/workbench");
|
||||
Debug.Assert(_geometry != null);
|
||||
|
||||
Connect("input_event", this, nameof(OnAreaInputEvent));
|
||||
Connect("mouse_entered", this, nameof(OnAreaMouseEntered));
|
||||
Connect("mouse_exited", this, nameof(OnAreaMouseExited));
|
||||
}
|
||||
|
||||
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||
int shapeIndex) {
|
||||
if (IsMouseOver && inputEvent is InputEventMouseButton) {
|
||||
InputEventMouseButton mouseButtonEvent = (InputEventMouseButton)inputEvent;
|
||||
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed) {
|
||||
EmitSignal("EntityClicked", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAreaMouseEntered() {
|
||||
IsMouseOver = true;
|
||||
SpatialMaterial overrideMaterial = new();
|
||||
overrideMaterial.AlbedoColor = new Color(1, 0, 0);
|
||||
_geometry.MaterialOverride = overrideMaterial;
|
||||
}
|
||||
|
||||
public void OnAreaMouseExited() {
|
||||
IsMouseOver = false;
|
||||
_geometry.MaterialOverride = null;
|
||||
}
|
||||
|
||||
// // Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
// public override void _Process(float delta)
|
||||
// {
|
||||
//
|
||||
// }
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
[gd_scene load_steps=8 format=2]
|
||||
|
||||
[ext_resource path="res://assets/KenneySurvivalKit/Models/workbench.glb" type="PackedScene" id=1]
|
||||
[ext_resource path="res://entities/Workbench.cs" type="Script" id=2]
|
||||
|
||||
[sub_resource type="BoxShape" id=1]
|
||||
extents = Vector3( 0.19, 0.19, 0.33 )
|
||||
|
||||
[sub_resource type="CubeMesh" id=2]
|
||||
size = Vector3( 0.38, 0.38, 0.66 )
|
||||
|
||||
[sub_resource type="SpatialMaterial" id=3]
|
||||
flags_transparent = true
|
||||
albedo_color = Color( 0.380392, 0.145098, 0.145098, 0.501961 )
|
||||
|
||||
[sub_resource type="CubeMesh" id=4]
|
||||
|
||||
[sub_resource type="PrismMesh" id=5]
|
||||
|
||||
[node name="Workbench" type="KinematicBody"]
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="Geometry" parent="." instance=ExtResource( 1 )]
|
||||
transform = Transform( 2.26249, 0, -1.06354, 0, 2.5, 0, 1.06354, 0, 2.26249, 0, 0, 0 )
|
||||
|
||||
[node name="CollisionShape" type="CollisionShape" parent="."]
|
||||
transform = Transform( -1.29904, 0, 0.5, 0, 1.5, 0, -0.749999, 0, -0.866026, 0, 0.240716, 0 )
|
||||
shape = SubResource( 1 )
|
||||
|
||||
[node name="MeshInstance" type="MeshInstance" parent="CollisionShape" groups=["PhysicsGeometry"]]
|
||||
visible = false
|
||||
mesh = SubResource( 2 )
|
||||
material/0 = SubResource( 3 )
|
||||
|
||||
[node name="MountPoint" type="Spatial" parent="."]
|
||||
transform = Transform( -0.861434, 0, 0.507869, 0, 1, 0, -0.507869, 0, -0.861434, -0.429363, 0, 0.763898 )
|
||||
|
||||
[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 )
|
||||
|
||||
[node name="MeshInstance" type="MeshInstance" parent="MountPoint/Arrow"]
|
||||
transform = Transform( -0.1, 0, -1.24676e-08, 0, 0.1, 0, 1.24676e-08, 0, -0.1, 0, 0, 0.0394838 )
|
||||
mesh = SubResource( 4 )
|
||||
skeleton = NodePath("../..")
|
||||
|
||||
[node name="MeshInstance2" type="MeshInstance" parent="MountPoint/Arrow"]
|
||||
transform = Transform( -0.1, -1.24676e-08, 6.04182e-16, 0, -4.37114e-09, -0.1, 1.24676e-08, -0.1, 4.37114e-09, 0, 0, -0.151838 )
|
||||
mesh = SubResource( 5 )
|
||||
skeleton = NodePath("../..")
|
||||
|
||||
[editable path="Geometry"]
|
|
@ -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=5
|
||||
version/code=1
|
||||
version/name="1.0"
|
||||
package/unique_name="org.godotengine.$genname"
|
||||
package/name=""
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
[gd_resource type="ShaderMaterial" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://materials/shader/WorldTileTypeShader.gdshader" type="Shader" id=1]
|
||||
[ext_resource path="res://materials/shader/IslandColorRampShader.gdshader" type="Shader" id=1]
|
||||
|
||||
[resource]
|
||||
shader = ExtResource( 1 )
|
||||
shader_param/DeepWaterColor = Color( 0, 0, 0.6, 1 )
|
||||
shader_param/WaterColor = Color( 0, 0, 0.698039, 1 )
|
||||
shader_param/WaterColor = Color( 0, 0, 0.7, 1 )
|
||||
shader_param/LightWaterColor = Color( 0, 0, 1, 1 )
|
||||
shader_param/SandColor = Color( 0.8, 0.8, 0.1, 1 )
|
||||
shader_param/GrassColor = Color( 0, 0.6, 0, 1 )
|
|
@ -56,7 +56,7 @@ void fragment() {
|
|||
|
||||
// COLOR.rgb = color_ramp(texture_color.r * borderFalloffCircle(UV) * 1.8);
|
||||
COLOR.rgb = color_ramp(texture_color.r * texture(TextureMask, UV).r);
|
||||
COLOR.a = 1.0;
|
||||
COLOR.a = 0.8;
|
||||
// COLOR.rgb = vec3(1, 0, 0);
|
||||
}
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
shader_type canvas_item;
|
||||
|
||||
uniform vec4 DeepWaterColor : hint_color = vec4(0, 0, 0.6, 1);
|
||||
uniform vec4 WaterColor : hint_color = vec4(0, 0, 0.7, 1);
|
||||
uniform vec4 LightWaterColor : hint_color = vec4(0, 0, 1, 1);
|
||||
uniform vec4 SandColor : hint_color = vec4(0.8, 0.8, 0.1, 1);
|
||||
uniform vec4 GrassColor : hint_color = vec4(0, 0.6, 0, 1);
|
||||
uniform vec4 ForestColor : hint_color = vec4(0, 0.4, 0, 1);
|
||||
uniform vec4 RockColor : hint_color = vec4(0.5, 0.5, 0.4, 1);
|
||||
uniform vec4 SnowColor : hint_color = vec4(1);
|
||||
|
||||
vec2 rand2d(vec2 uv) {
|
||||
return vec2(fract(sin(dot(uv.xy,
|
||||
vec2(12.9898,78.233))) * 43758.5453123));
|
||||
}
|
||||
|
||||
float rand1d(vec2 uv){
|
||||
return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
vec2 voronoi_segment(vec2 uv, float columns, float rows) {
|
||||
vec2 index_uv = floor(vec2(uv.x * columns, uv.y * rows));
|
||||
vec2 fract_uv = fract(vec2(uv.x * columns, uv.y * rows));
|
||||
|
||||
float minimum_dist = 1.0;
|
||||
vec2 minimum_point;
|
||||
vec2 minimum_neighbour;
|
||||
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
vec2 neighbour = vec2(float(x), float(y));
|
||||
vec2 point = rand2d(index_uv + neighbour);
|
||||
|
||||
vec2 diff = neighbour + point - fract_uv;
|
||||
float dist = length(diff);
|
||||
|
||||
if (dist < minimum_dist) {
|
||||
minimum_dist = dist;
|
||||
minimum_point = point;
|
||||
minimum_neighbour = neighbour;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minimum_point;
|
||||
}
|
||||
|
||||
ivec2 voronoiCellId(vec2 uv, vec2 grid_size) {
|
||||
vec2 index_uv = floor(uv * grid_size);
|
||||
vec2 fract_uv = fract(uv * grid_size);
|
||||
|
||||
float minimum_dist = 1.0;
|
||||
vec2 minimum_point;
|
||||
vec2 minimum_neighbour;
|
||||
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
vec2 neighbour = vec2(float(x), float(y));
|
||||
vec2 point = rand2d(index_uv + neighbour);
|
||||
|
||||
vec2 diff = neighbour + point - fract_uv;
|
||||
float dist = length(diff);
|
||||
|
||||
if (dist < minimum_dist) {
|
||||
minimum_dist = dist;
|
||||
minimum_point = point;
|
||||
minimum_neighbour = index_uv + neighbour;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ivec2(minimum_neighbour);
|
||||
}
|
||||
|
||||
vec3 voronoi_cell_id_and_border_dist(vec2 uv, vec2 grid_size) {
|
||||
vec2 index_uv = floor(uv * grid_size);
|
||||
vec2 fract_uv = fract(uv * grid_size);
|
||||
|
||||
float minimum_dist = 1.0;
|
||||
vec2 minimum_neighbour;
|
||||
vec2 cell_point = rand2d(index_uv);
|
||||
float border_dist = 1.0;
|
||||
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
vec2 neighbour = vec2(float(x), float(y));
|
||||
vec2 point = rand2d(index_uv + neighbour);
|
||||
|
||||
vec2 diff = neighbour + point - fract_uv;
|
||||
float dist = length(diff);
|
||||
|
||||
if (dist < minimum_dist) {
|
||||
minimum_dist = dist;
|
||||
minimum_neighbour = index_uv + neighbour;
|
||||
|
||||
float cell_point_dist = length(neighbour + point - cell_point);
|
||||
border_dist = (cell_point_dist * 0.5 - dist);
|
||||
border_dist = 1.0 - dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vec3(minimum_neighbour, border_dist);
|
||||
}
|
||||
|
||||
vec4 biomeValue (vec2 uv, vec2 grid_size) {
|
||||
vec2 index_uv = floor(uv * grid_size);
|
||||
vec2 fract_uv = fract(uv * grid_size);
|
||||
|
||||
float minimum_dist = 1.0;
|
||||
vec2 minimum_point;
|
||||
vec2 minimum_neighbour;
|
||||
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
vec2 neighbour = vec2(float(x), float(y));
|
||||
vec2 point = rand2d(index_uv + neighbour);
|
||||
|
||||
vec2 diff = neighbour + point - fract_uv;
|
||||
float dist = length(diff);
|
||||
|
||||
if (dist < minimum_dist) {
|
||||
minimum_dist = dist;
|
||||
minimum_point = point;
|
||||
minimum_neighbour = index_uv + neighbour;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float biomeId = rand1d(minimum_neighbour);
|
||||
|
||||
if (biomeId < 0.2) {
|
||||
return SandColor;
|
||||
} else if (biomeId < 0.4) {
|
||||
return GrassColor;
|
||||
} else if (biomeId < 0.6) {
|
||||
return RockColor;
|
||||
} else if (biomeId < 0.8) {
|
||||
return SnowColor;
|
||||
} else {
|
||||
return ForestColor;
|
||||
}
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
vec2 uv = UV / 0.01;
|
||||
vec2 offset = vec2(sin(TIME * 0.6), cos(TIME * 0.6)) * 14.0;
|
||||
|
||||
ivec2 cellId = voronoiCellId(uv + offset, vec2(0.125, 0.125));
|
||||
|
||||
vec4 water_land_value = rand1d(vec2(cellId)) < 0.66 ? DeepWaterColor : GrassColor;
|
||||
vec4 biome_id_value = biomeValue(uv + offset, vec2(0.14, 0.14));
|
||||
|
||||
// COLOR = vec4(water_land_value.xyz, 0.4) + vec4 (biome_id_value.xyz, 0.3);
|
||||
|
||||
if (water_land_value == DeepWaterColor) {
|
||||
COLOR = water_land_value;
|
||||
} else {
|
||||
COLOR = biome_id_value;
|
||||
}
|
||||
|
||||
vec3 cellIdAndBorderDist = voronoi_cell_id_and_border_dist(uv + offset, vec2(0.125, 0.125));
|
||||
|
||||
//COLOR = vec4(rand2d(vec2(cellIdAndBorderDist.xy)), 0.0, cellIdAndBorderDist.z);
|
||||
COLOR = vec4(cellIdAndBorderDist.z, 0., 0., 1.0);
|
||||
}
|
|
@ -9,17 +9,17 @@
|
|||
config_version=4
|
||||
|
||||
_global_script_classes=[ {
|
||||
"base": "Node",
|
||||
"base": "Reference",
|
||||
"class": "ClickableComponent",
|
||||
"language": "GDScript",
|
||||
"path": "res://components/ClickableComponent.gd"
|
||||
}, {
|
||||
"base": "KinematicBody2D",
|
||||
"base": "Reference",
|
||||
"class": "CollisionLine",
|
||||
"language": "GDScript",
|
||||
"path": "res://utils/CollisionLine.gd"
|
||||
}, {
|
||||
"base": "Node",
|
||||
"base": "Reference",
|
||||
"class": "ColorComponent",
|
||||
"language": "GDScript",
|
||||
"path": "res://components/ColorComponent.gd"
|
||||
|
@ -54,7 +54,7 @@ _global_script_classes=[ {
|
|||
"language": "GDScript",
|
||||
"path": "res://utils/SpringDamper.gd"
|
||||
}, {
|
||||
"base": "Sprite",
|
||||
"base": "Reference",
|
||||
"class": "TintedSpriteComponent",
|
||||
"language": "GDScript",
|
||||
"path": "res://components/TintedSpriteComponent.gd"
|
||||
|
@ -114,11 +114,6 @@ Right={
|
|||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":0,"physical_scancode":68,"unicode":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
ToggleMainMenu={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":0,"physical_scancode":16777217,"unicode":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[layer_names]
|
||||
|
||||
|
@ -139,9 +134,5 @@ 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"
|
||||
|
|
187
scenes/Game.cs
187
scenes/Game.cs
|
@ -1,14 +1,8 @@
|
|||
using System.Diagnostics;
|
||||
using Godot;
|
||||
|
||||
public class Game : Spatial {
|
||||
private enum ActionMode {
|
||||
Default,
|
||||
Building
|
||||
}
|
||||
|
||||
private ActionMode _actionMode = ActionMode.Default;
|
||||
|
||||
public class Game : Spatial
|
||||
{
|
||||
private ImageTexture _blackWhitePatternTexture;
|
||||
private Camera _camera;
|
||||
private Vector3 _cameraOffset;
|
||||
|
@ -19,58 +13,59 @@ public class Game : Spatial {
|
|||
// ui elements
|
||||
private Label _framesPerSecondLabel;
|
||||
private Control _gameUi;
|
||||
private Label _woodCountLabel;
|
||||
private Button _generateWorldButton;
|
||||
private Label _goldCountLabel;
|
||||
private TextureRect _heightTextureRect;
|
||||
private Button _walkActionButton;
|
||||
private Button _buildActionButton;
|
||||
|
||||
// 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 ShaderMaterial _tileMaterial;
|
||||
private Label _tileOffsetLabel;
|
||||
private World _world;
|
||||
private TextureRect _worldTextureRect;
|
||||
private readonly PackedScene _workbenchScene = GD.Load<PackedScene>("res://entities/Workbench.tscn");
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready() {
|
||||
public override void _Ready()
|
||||
{
|
||||
// debugStatsContainer
|
||||
Container debugStatsContainer = (Container)FindNode("DebugStatsContainer");
|
||||
|
||||
_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
|
||||
Container worldGeneratorWidget = (Container)FindNode("WorldGeneratorWidget");
|
||||
_worldTextureRect = worldGeneratorWidget.GetNode<TextureRect>("WorldTextureRect");
|
||||
_heightTextureRect = worldGeneratorWidget.GetNode<TextureRect>("HeightTextureRect");
|
||||
Container worldGeneratorContainer = (Container)FindNode("WorldGeneratorContainer");
|
||||
_worldTextureRect = worldGeneratorContainer.GetNode<TextureRect>("WorldTextureRect");
|
||||
_heightTextureRect = worldGeneratorContainer.GetNode<TextureRect>("HeightTextureRect");
|
||||
_generateWorldButton = worldGeneratorContainer.GetNode<Button>("WorldGenerateButton");
|
||||
_gameUi = (Control)FindNode("GameUI");
|
||||
_woodCountLabel = _gameUi.GetNode<Label>("TopRight/WoodCount");
|
||||
Debug.Assert(_woodCountLabel != null);
|
||||
_goldCountLabel = _gameUi.GetNode<Label>("TopRight/GoldCount");
|
||||
_goldCountLabel = _gameUi.GetNode<Label>("GoldCount");
|
||||
Debug.Assert(_goldCountLabel != null);
|
||||
_walkActionButton = _gameUi.GetNode<Button>("Actions/WalkActionButton");
|
||||
Debug.Assert(_walkActionButton != null);
|
||||
_buildActionButton = _gameUi.GetNode<Button>("Actions/BuildActionButton");
|
||||
Debug.Assert(_buildActionButton != null);
|
||||
|
||||
// scene nodes
|
||||
_tileHighlight = GetNode<Spatial>("TileHighlight");
|
||||
|
@ -82,39 +77,40 @@ public class Game : Spatial {
|
|||
|
||||
_world = (World)FindNode("World");
|
||||
|
||||
// populate UI values
|
||||
Slider 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();
|
||||
Image image = new();
|
||||
Image image = new Image();
|
||||
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("WoodCountChanged", this, nameof(OnWoodCountChanged));
|
||||
_player.Connect("GoldCountChanged", this, nameof(OnGoldCountChanged));
|
||||
_world.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
_world.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
_world.Connect("OnWorldViewTileTypeImageChanged", this, nameof(OnWorldViewTileTypeImageChanged));
|
||||
_world.Connect("OnHeightmapImageChanged", this, nameof(OnHeightmapImageChanged));
|
||||
_walkActionButton.Connect("pressed", this, nameof(OnWalkActionPressed));
|
||||
_buildActionButton.Connect("pressed", this, nameof(OnBuildActionPressed));
|
||||
|
||||
// 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));
|
||||
|
||||
|
@ -123,39 +119,18 @@ public class Game : Spatial {
|
|||
WorldInfoComponent worldInfoComponent = _player.GetNode<WorldInfoComponent>("WorldInfo");
|
||||
|
||||
UpdateCurrentTile();
|
||||
|
||||
StartNewGame(2, 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 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() {
|
||||
public void UpdateCurrentTile()
|
||||
{
|
||||
// cast a ray from the camera to center
|
||||
Vector3 cameraNormal = _camera.ProjectRayNormal(_camera.GetViewport().Size * 0.5f);
|
||||
Vector3 cameraPosition = _camera.ProjectRayOrigin(_camera.GetViewport().Size * 0.5f);
|
||||
|
@ -163,9 +138,12 @@ public class Game : Spatial {
|
|||
|
||||
Vector3 centerCoord;
|
||||
|
||||
if (Mathf.Abs(cameraDir.y) > Globals.EpsPosition) {
|
||||
if (Mathf.Abs(cameraDir.y) > Globals.EpsPosition)
|
||||
{
|
||||
centerCoord = cameraPosition + cameraNormal * (-cameraPosition.y / cameraNormal.y);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
centerCoord = _camera.GlobalTranslation;
|
||||
centerCoord.y = 0;
|
||||
}
|
||||
|
@ -179,8 +157,10 @@ public class Game : Spatial {
|
|||
}
|
||||
|
||||
|
||||
public override void _Process(float delta) {
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
_framesPerSecondLabel.Text = Engine.GetFramesPerSecond().ToString();
|
||||
_lastTile = _currentTile;
|
||||
|
||||
UpdateCurrentTile();
|
||||
|
||||
|
@ -195,8 +175,18 @@ public class Game : Spatial {
|
|||
_camera.Transform = cameraTransform;
|
||||
}
|
||||
|
||||
|
||||
public void OnGenerateButton()
|
||||
{
|
||||
GD.Print("Generating");
|
||||
Slider 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) {
|
||||
int shapeIndex)
|
||||
{
|
||||
HexCell cellAtCursor = _hexGrid.GetHexAt(new Vector2(position.x, position.z));
|
||||
Transform highlightTransform = Transform.Identity;
|
||||
|
||||
|
@ -208,33 +198,19 @@ public class Game : Spatial {
|
|||
}
|
||||
|
||||
|
||||
public void OnTileClicked(HexTile3D tile) {
|
||||
if (_player == null) {
|
||||
return;
|
||||
}
|
||||
public void OnTileClicked(HexTile3D tile)
|
||||
{
|
||||
if (_player == null) return;
|
||||
|
||||
if (_actionMode == ActionMode.Building) {
|
||||
Workbench workbench = (Workbench)_workbenchScene.Instance();
|
||||
|
||||
workbench.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
||||
workbench.Transform = tile.GlobalTransform;
|
||||
|
||||
AddChild(workbench);
|
||||
_world.MarkCellUnwalkable(tile.Cell);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player.InteractionComponent != null) {
|
||||
_player.InteractionComponent.EmitSignal("InteractionEnd");
|
||||
}
|
||||
if (_player.InteractionComponent != null) _player.InteractionComponent.EmitSignal("InteractionEnd");
|
||||
|
||||
_player.TaskQueueComponent.Reset();
|
||||
_player.TaskQueueComponent.Queue.Enqueue(new TaskQueueComponent.NavigationTask(
|
||||
new NavigationPoint(tile.GlobalTranslation)));
|
||||
}
|
||||
|
||||
public void OnTileHovered(HexTile3D tile) {
|
||||
public void OnTileHovered(HexTile3D tile)
|
||||
{
|
||||
Transform highlightTransform = tile.GlobalTransform;
|
||||
_mouseTileHighlight.Transform = highlightTransform;
|
||||
_mouseWorldLabel.Text = highlightTransform.origin.ToString("F3");
|
||||
|
@ -244,11 +220,13 @@ public class Game : Spatial {
|
|||
_player.NavigationComponent.FindPath(_player, _player.GlobalTranslation, tile.GlobalTranslation);
|
||||
}
|
||||
|
||||
public void OnEntityClicked(Entity entity) {
|
||||
public void OnEntityClicked(Entity entity)
|
||||
{
|
||||
GD.Print("Clicked on entity at " + entity.GlobalTranslation);
|
||||
|
||||
Spatial mountPoint = (Spatial)entity.FindNode("MountPoint");
|
||||
if (mountPoint != null) {
|
||||
if (mountPoint != null)
|
||||
{
|
||||
_player.TaskQueueComponent.Reset();
|
||||
_player.TaskQueueComponent.Queue.Enqueue(new TaskQueueComponent.NavigationTask(
|
||||
new NavigationPoint(mountPoint.GlobalTransform)));
|
||||
|
@ -257,7 +235,8 @@ public class Game : Spatial {
|
|||
}
|
||||
|
||||
|
||||
public void ResetGameState() {
|
||||
public void ResetGameState()
|
||||
{
|
||||
Transform playerStartTransform = Transform.Identity;
|
||||
playerStartTransform.origin.y = 0;
|
||||
_player.Transform = playerStartTransform;
|
||||
|
@ -265,29 +244,30 @@ public class Game : Spatial {
|
|||
_player.NavigationComponent.PlanDirectPath(_player, playerStartTransform.origin, playerStartTransform.origin,
|
||||
playerStartTransform.basis.Quat());
|
||||
|
||||
_woodCountLabel.Text = "0";
|
||||
_goldCountLabel.Text = "0";
|
||||
_actionMode = ActionMode.Default;
|
||||
|
||||
foreach (Spatial entity in GetNode("Entities").GetChildren()) {
|
||||
foreach (Spatial entity in GetNode("Entities").GetChildren())
|
||||
{
|
||||
Transform entityTransform = entity.Transform;
|
||||
Vector2 entityPlanePos = new(entityTransform.origin.x, entityTransform.origin.z);
|
||||
Vector2 entityPlanePos = new Vector2(entityTransform.origin.x, entityTransform.origin.z);
|
||||
Vector2 entityOffsetCoordinates = _hexGrid.GetHexAt(entityPlanePos).OffsetCoords;
|
||||
entityTransform.origin.y = 0;
|
||||
entity.Transform = entityTransform;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHeightmapImageChanged(Image heightmapImage) {
|
||||
ImageTexture newHeightmapTexture = new();
|
||||
private void OnHeightmapImageChanged(Image heightmapImage)
|
||||
{
|
||||
ImageTexture newHeightmapTexture = new ImageTexture();
|
||||
newHeightmapTexture.CreateFromImage(heightmapImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
|
||||
_heightTextureRect.Texture = newHeightmapTexture;
|
||||
}
|
||||
|
||||
private void OnWorldViewTileTypeImageChanged(Image viewTileTypeImage) {
|
||||
ImageTexture newWorldTexture = new();
|
||||
private void OnWorldViewTileTypeImageChanged(Image viewTileTypeImage)
|
||||
{
|
||||
ImageTexture newWorldTexture = new ImageTexture();
|
||||
newWorldTexture.CreateFromImage(viewTileTypeImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
|
||||
|
@ -299,27 +279,12 @@ public class Game : Spatial {
|
|||
_tileMaterial.SetShaderParam("CoordinateOffsetV", (int)_world.WorldTextureCoordinateOffset.y);
|
||||
}
|
||||
|
||||
public void OnWoodCountChanged(int woodCount) {
|
||||
AnimationPlayer animationPlayer = _woodCountLabel.GetNode<AnimationPlayer>("AnimationPlayer");
|
||||
_woodCountLabel.Text = woodCount.ToString();
|
||||
animationPlayer.CurrentAnimation = "FlashLabel";
|
||||
animationPlayer.Seek(0);
|
||||
animationPlayer.Play();
|
||||
}
|
||||
|
||||
public void OnGoldCountChanged(int goldCount) {
|
||||
AnimationPlayer animationPlayer = _goldCountLabel.GetNode<AnimationPlayer>("AnimationPlayer");
|
||||
public void OnGoldCountChanged(int goldCount)
|
||||
{
|
||||
AnimationPlayer animationPlayer = _gameUi.GetNode<AnimationPlayer>("AnimationPlayer");
|
||||
_goldCountLabel.Text = goldCount.ToString();
|
||||
animationPlayer.CurrentAnimation = "FlashLabel";
|
||||
animationPlayer.Seek(0);
|
||||
animationPlayer.Play();
|
||||
}
|
||||
|
||||
public void OnWalkActionPressed() {
|
||||
_actionMode = ActionMode.Default;
|
||||
}
|
||||
|
||||
public void OnBuildActionPressed() {
|
||||
_actionMode = ActionMode.Building;
|
||||
}
|
||||
}
|
350
scenes/Game.tscn
350
scenes/Game.tscn
|
@ -1,51 +1,22 @@
|
|||
[gd_scene load_steps=20 format=2]
|
||||
[gd_scene load_steps=21 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.tscn" type="PackedScene" id=7]
|
||||
[ext_resource path="res://ui/WorldGeneratorUI.tscn" type="PackedScene" id=8]
|
||||
[ext_resource path="res://scenes/World.cs" type="Script" id=7]
|
||||
[ext_resource path="res://scenes/Game.cs" type="Script" id=9]
|
||||
[ext_resource path="res://entities/Wood.tscn" type="PackedScene" id=10]
|
||||
[ext_resource path="res://entities/Chest.tscn" type="PackedScene" id=11]
|
||||
[ext_resource path="res://ui/game_theme.tres" type="Theme" id=12]
|
||||
[ext_resource path="res://ui/action_buttongroup.tres" type="ButtonGroup" id=13]
|
||||
[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]
|
||||
|
||||
[sub_resource type="Animation" id=27]
|
||||
resource_name = "FlashLabel"
|
||||
length = 0.3
|
||||
tracks/0/type = "value"
|
||||
tracks/0/path = NodePath("WoodCount:rect_scale")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/keys = {
|
||||
"times": PoolRealArray( 0, 0.1, 0.3 ),
|
||||
"transitions": PoolRealArray( 1, 0.1701, 1 ),
|
||||
"update": 0,
|
||||
"values": [ Vector2( 1, 1 ), Vector2( 2, 2 ), Vector2( 1, 1 ) ]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id=28]
|
||||
length = 0.001
|
||||
tracks/0/type = "value"
|
||||
tracks/0/path = NodePath("WoodCount:rect_scale")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/keys = {
|
||||
"times": PoolRealArray( 0 ),
|
||||
"transitions": PoolRealArray( 1 ),
|
||||
"update": 0,
|
||||
"values": [ Vector2( 1, 1 ) ]
|
||||
}
|
||||
[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"
|
||||
|
@ -65,11 +36,15 @@ 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 )
|
||||
__meta__ = {
|
||||
"_edit_horizontal_guides_": [ -333.0 ]
|
||||
}
|
||||
|
||||
[node name="TileHighlight" parent="." instance=ExtResource( 5 )]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0 )
|
||||
|
@ -77,94 +52,42 @@ visible = false
|
|||
|
||||
[node name="MouseTileHighlight" parent="." instance=ExtResource( 5 )]
|
||||
|
||||
[node name="GameUI" type="Control" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
theme = ExtResource( 12 )
|
||||
|
||||
[node name="TopRight" type="HBoxContainer" parent="GameUI"]
|
||||
[node name="GameUI" type="HBoxContainer" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
margin_left = -206.0
|
||||
margin_left = -40.0
|
||||
margin_right = -10.0
|
||||
margin_bottom = 40.0
|
||||
grow_horizontal = 0
|
||||
mouse_filter = 2
|
||||
alignment = 2
|
||||
|
||||
[node name="WoodLabel" type="Label" parent="GameUI/TopRight"]
|
||||
margin_left = 4.0
|
||||
margin_top = 10.0
|
||||
margin_right = 53.0
|
||||
margin_bottom = 29.0
|
||||
text = "Wood"
|
||||
|
||||
[node name="WoodCount" type="Label" parent="GameUI/TopRight"]
|
||||
margin_left = 57.0
|
||||
margin_top = 10.0
|
||||
margin_right = 107.0
|
||||
margin_bottom = 29.0
|
||||
rect_min_size = Vector2( 50, 0 )
|
||||
rect_pivot_offset = Vector2( 25, 8 )
|
||||
text = "0"
|
||||
align = 1
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="GameUI/TopRight/WoodCount"]
|
||||
root_node = NodePath("../..")
|
||||
anims/FlashLabel = SubResource( 27 )
|
||||
anims/RESET = SubResource( 28 )
|
||||
|
||||
[node name="GoldLabel" type="Label" parent="GameUI/TopRight"]
|
||||
margin_left = 111.0
|
||||
margin_top = 10.0
|
||||
margin_right = 152.0
|
||||
margin_bottom = 29.0
|
||||
[node name="GoldLabel" type="Label" parent="GameUI"]
|
||||
margin_top = 13.0
|
||||
margin_right = 30.0
|
||||
margin_bottom = 27.0
|
||||
text = "Gold"
|
||||
|
||||
[node name="GoldCount" type="Label" parent="GameUI/TopRight"]
|
||||
margin_left = 156.0
|
||||
margin_top = 10.0
|
||||
margin_right = 206.0
|
||||
margin_bottom = 29.0
|
||||
[node name="GoldCount" type="Label" parent="GameUI"]
|
||||
margin_left = 34.0
|
||||
margin_top = 13.0
|
||||
margin_right = 84.0
|
||||
margin_bottom = 27.0
|
||||
rect_min_size = Vector2( 50, 0 )
|
||||
rect_pivot_offset = Vector2( 25, 8 )
|
||||
rect_pivot_offset = Vector2( 45, 8 )
|
||||
text = "0"
|
||||
align = 1
|
||||
align = 2
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="GameUI/TopRight/GoldCount"]
|
||||
root_node = NodePath("../..")
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="GameUI"]
|
||||
anims/FlashLabel = SubResource( 25 )
|
||||
|
||||
[node name="Actions" type="HBoxContainer" parent="GameUI"]
|
||||
margin_left = 10.0
|
||||
margin_top = 10.0
|
||||
margin_bottom = 40.0
|
||||
|
||||
[node name="WalkActionButton" type="Button" parent="GameUI/Actions"]
|
||||
margin_right = 58.0
|
||||
margin_bottom = 40.0
|
||||
rect_min_size = Vector2( 40, 40 )
|
||||
toggle_mode = true
|
||||
pressed = true
|
||||
group = ExtResource( 13 )
|
||||
text = "Walk"
|
||||
|
||||
[node name="BuildActionButton" type="Button" parent="GameUI/Actions"]
|
||||
margin_left = 62.0
|
||||
margin_right = 120.0
|
||||
margin_bottom = 40.0
|
||||
toggle_mode = true
|
||||
group = ExtResource( 13 )
|
||||
text = "Build"
|
||||
|
||||
[node name="DebugContainer" type="PanelContainer" parent="."]
|
||||
self_modulate = Color( 1, 1, 1, 0.443137 )
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -67.0
|
||||
margin_top = -34.0
|
||||
margin_left = -141.0
|
||||
margin_top = -172.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
mouse_filter = 2
|
||||
|
@ -174,8 +97,8 @@ size_flags_vertical = 3
|
|||
[node name="DebugStatsContainer" type="GridContainer" parent="DebugContainer"]
|
||||
margin_left = 7.0
|
||||
margin_top = 7.0
|
||||
margin_right = 60.0
|
||||
margin_bottom = 27.0
|
||||
margin_right = 134.0
|
||||
margin_bottom = 165.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
mouse_filter = 2
|
||||
|
@ -368,24 +291,22 @@ margin_bottom = 200.0
|
|||
text = "0"
|
||||
|
||||
[node name="Generator Container" type="Control" parent="."]
|
||||
visible = false
|
||||
margin_right = 40.0
|
||||
margin_bottom = 40.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="WorldGeneratorWidget" type="VBoxContainer" parent="Generator Container"]
|
||||
[node name="WorldGeneratorContainer" type="VBoxContainer" parent="Generator Container"]
|
||||
margin_left = 10.0
|
||||
margin_top = 10.0
|
||||
margin_right = 145.0
|
||||
margin_bottom = 94.0
|
||||
script = ExtResource( 1 )
|
||||
script = ExtResource( 12 )
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Generator Container/WorldGeneratorWidget"]
|
||||
visible = false
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Generator Container/WorldGeneratorContainer"]
|
||||
margin_right = 135.0
|
||||
margin_bottom = 16.0
|
||||
|
||||
[node name="WorldSizeSlider" type="HSlider" parent="Generator Container/WorldGeneratorWidget/HBoxContainer"]
|
||||
[node name="WorldSizeSlider" type="HSlider" parent="Generator Container/WorldGeneratorContainer/HBoxContainer"]
|
||||
margin_right = 123.0
|
||||
margin_bottom = 16.0
|
||||
size_flags_horizontal = 3
|
||||
|
@ -393,26 +314,26 @@ min_value = 1.0
|
|||
max_value = 256.0
|
||||
value = 1.0
|
||||
|
||||
[node name="WorldSizeLabel" type="Label" parent="Generator Container/WorldGeneratorWidget/HBoxContainer"]
|
||||
[node name="WorldSizeLabel" type="Label" parent="Generator Container/WorldGeneratorContainer/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/WorldGeneratorWidget"]
|
||||
visible = false
|
||||
[node name="WorldGenerateButton" type="Button" parent="Generator Container/WorldGeneratorContainer"]
|
||||
margin_top = 20.0
|
||||
margin_right = 135.0
|
||||
margin_bottom = 40.0
|
||||
text = "Generate"
|
||||
|
||||
[node name="ShowTexturesCheckButton" type="CheckButton" parent="Generator Container/WorldGeneratorWidget"]
|
||||
[node name="ShowTexturesCheckButton" type="CheckButton" parent="Generator Container/WorldGeneratorContainer"]
|
||||
margin_top = 44.0
|
||||
margin_right = 135.0
|
||||
margin_bottom = 40.0
|
||||
margin_bottom = 84.0
|
||||
text = "Textures"
|
||||
|
||||
[node name="WorldTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorWidget"]
|
||||
[node name="WorldTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorContainer"]
|
||||
visible = false
|
||||
margin_top = 88.0
|
||||
margin_right = 135.0
|
||||
|
@ -422,11 +343,11 @@ expand = true
|
|||
stretch_mode = 5
|
||||
flip_v = true
|
||||
|
||||
[node name="HeightTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorWidget"]
|
||||
[node name="HeightTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorContainer"]
|
||||
visible = false
|
||||
margin_top = 192.0
|
||||
margin_top = 88.0
|
||||
margin_right = 135.0
|
||||
margin_bottom = 292.0
|
||||
margin_bottom = 188.0
|
||||
rect_min_size = Vector2( 100, 100 )
|
||||
expand = true
|
||||
stretch_mode = 5
|
||||
|
@ -444,182 +365,63 @@ script = ExtResource( 15 )
|
|||
[node name="NavigationSystem" type="Node" parent="."]
|
||||
|
||||
[node name="Player" parent="." instance=ExtResource( 2 )]
|
||||
EntityMask = 2
|
||||
WorldNode = NodePath("../World")
|
||||
|
||||
[node name="WorldInfo" parent="Player" index="2"]
|
||||
WorldPath = NodePath("../../World")
|
||||
|
||||
[node name="Skeleton" parent="Player/Geometry/PirateAsset/Armature" index="0"]
|
||||
bones/4/bound_children = [ NodePath("ToolAttachement") ]
|
||||
|
||||
[node name="ToolAttachement" parent="Player/Geometry/PirateAsset/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 )
|
||||
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="1"]
|
||||
[node name="AnimationTree" parent="Player/Geometry" index="2"]
|
||||
parameters/playback = SubResource( 26 )
|
||||
|
||||
[node name="Entities" type="Spatial" parent="."]
|
||||
|
||||
[node name="Axe" parent="Entities" instance=ExtResource( 14 )]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1.03292, -2.38419e-07, -4.33215 )
|
||||
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( -0.825665, 0, 0.56416, 0, 1, 0, -0.56416, 0, -0.825665, -3.27709, 0, 1.02593 )
|
||||
|
||||
[node name="Wood" parent="Entities" instance=ExtResource( 10 )]
|
||||
transform = Transform( 0.791533, 0, 0.611126, 0, 1, 0, -0.611126, 0, 0.791533, -2.46279, 0, -0.631194 )
|
||||
[node name="World" type="Spatial" parent="."]
|
||||
script = ExtResource( 7 )
|
||||
|
||||
[node name="Wood2" parent="Entities" instance=ExtResource( 10 )]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1.66947, 0, -2.19408 )
|
||||
[node name="Chunks" type="Spatial" parent="World"]
|
||||
|
||||
[node name="Wood3" parent="Entities" instance=ExtResource( 10 )]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1.89011, 0, 1.70148 )
|
||||
[node name="TileMultiMeshInstance" type="MultiMeshInstance" parent="World"]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -2.5, 0 )
|
||||
multimesh = SubResource( 27 )
|
||||
|
||||
[node name="Wood4" parent="Entities" instance=ExtResource( 10 )]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.85616, 0, -2.01499 )
|
||||
[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="Wood5" parent="Entities" instance=ExtResource( 10 )]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.5591, 0, 1.55701 )
|
||||
[node name="Rocks" type="Spatial" parent="World/Assets"]
|
||||
|
||||
[node name="World" parent="." instance=ExtResource( 7 )]
|
||||
[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="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 )
|
||||
shadow_enabled = true
|
||||
directional_shadow_mode = 0
|
||||
|
||||
[node name="GameMenu" type="Control" parent="."]
|
||||
visible = false
|
||||
anchor_left = 0.1
|
||||
anchor_top = 0.1
|
||||
anchor_right = 0.9
|
||||
anchor_bottom = 0.9
|
||||
|
||||
[node name="MainMenu" type="Panel" parent="GameMenu"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="MainMenu" type="VBoxContainer" parent="GameMenu/MainMenu"]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -41.0
|
||||
margin_top = -22.0
|
||||
margin_right = 41.0
|
||||
margin_bottom = 22.0
|
||||
|
||||
[node name="Label" type="Label" parent="GameMenu/MainMenu/MainMenu"]
|
||||
margin_right = 82.0
|
||||
margin_bottom = 14.0
|
||||
text = "Pirate Game"
|
||||
align = 1
|
||||
|
||||
[node name="NewGameButton" type="Button" parent="GameMenu/MainMenu/MainMenu"]
|
||||
margin_top = 18.0
|
||||
margin_right = 82.0
|
||||
margin_bottom = 38.0
|
||||
text = "New Game"
|
||||
|
||||
[node name="QuitButton" type="Button" parent="GameMenu/MainMenu/MainMenu"]
|
||||
margin_top = 42.0
|
||||
margin_right = 82.0
|
||||
margin_bottom = 62.0
|
||||
text = "Quit"
|
||||
|
||||
[node name="NewGameMenu" type="Panel" parent="GameMenu"]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="MainMenu" type="VBoxContainer" parent="GameMenu/NewGameMenu"]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -41.0
|
||||
margin_top = -10.0
|
||||
margin_right = 41.0
|
||||
margin_bottom = 10.0
|
||||
|
||||
[node name="NewGameButton" type="Button" parent="GameMenu/NewGameMenu/MainMenu"]
|
||||
margin_right = 82.0
|
||||
margin_bottom = 20.0
|
||||
text = "New Game"
|
||||
|
||||
[node name="QuitButton" type="Button" parent="GameMenu/NewGameMenu/MainMenu"]
|
||||
margin_top = 24.0
|
||||
margin_right = 82.0
|
||||
margin_bottom = 44.0
|
||||
text = "Quit"
|
||||
|
||||
[node name="WorldGeneratorUI" parent="GameMenu/NewGameMenu" instance=ExtResource( 8 )]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -143.5
|
||||
margin_top = -160.0
|
||||
margin_right = 143.5
|
||||
margin_bottom = 160.0
|
||||
|
||||
[node name="VBoxContainer" parent="GameMenu/NewGameMenu/WorldGeneratorUI" index="0"]
|
||||
margin_left = 0.0
|
||||
margin_top = 21.0
|
||||
margin_right = 287.0
|
||||
margin_bottom = 299.0
|
||||
|
||||
[node name="Label" parent="GameMenu/NewGameMenu/WorldGeneratorUI/VBoxContainer" index="0"]
|
||||
text = "New World"
|
||||
|
||||
[node name="GameRunningMenu" type="Panel" parent="GameMenu"]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="GameMenu/GameRunningMenu"]
|
||||
margin_left = 107.0
|
||||
margin_top = 113.0
|
||||
margin_right = 148.0
|
||||
margin_bottom = 207.0
|
||||
custom_constants/separation = 20
|
||||
|
||||
[node name="Label" type="Label" parent="GameMenu/GameRunningMenu/VBoxContainer"]
|
||||
margin_right = 42.0
|
||||
margin_bottom = 14.0
|
||||
align = 1
|
||||
|
||||
[node name="SaveButton" type="Button" parent="GameMenu/GameRunningMenu/VBoxContainer"]
|
||||
margin_top = 34.0
|
||||
margin_right = 42.0
|
||||
margin_bottom = 54.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
text = "Save"
|
||||
|
||||
[node name="LoadButton" type="Button" parent="GameMenu/GameRunningMenu/VBoxContainer"]
|
||||
margin_top = 74.0
|
||||
margin_right = 42.0
|
||||
margin_bottom = 94.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
text = "Load"
|
||||
|
||||
[node name="QuitButton" type="Button" parent="GameMenu/GameRunningMenu/VBoxContainer"]
|
||||
margin_top = 114.0
|
||||
margin_right = 42.0
|
||||
margin_bottom = 134.0
|
||||
text = "Quit"
|
||||
|
||||
[connection signal="toggled" from="DebugContainer/DebugStatsContainer/DebugMenuButton" to="DebugContainer/DebugStatsContainer" method="_on_DebugMenuButton_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"]
|
||||
[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"]
|
||||
|
||||
[editable path="Player"]
|
||||
[editable path="Player/Geometry/PirateAsset"]
|
||||
[editable path="World"]
|
||||
[editable path="GameMenu/NewGameMenu/WorldGeneratorUI"]
|
||||
|
|
|
@ -1,43 +1,44 @@
|
|||
using System.Diagnostics;
|
||||
using Godot;
|
||||
|
||||
public class HexTile3D : Spatial {
|
||||
public class TileTypeInfo {
|
||||
public readonly string Name;
|
||||
public readonly Color Color;
|
||||
public readonly ushort TileTypeMask;
|
||||
|
||||
public TileTypeInfo(string name, Color color, ushort tileTypeMask) {
|
||||
Name = name;
|
||||
Color = color;
|
||||
TileTypeMask = tileTypeMask;
|
||||
}
|
||||
public class HexTile3D : Spatial
|
||||
{
|
||||
public enum TileType
|
||||
{
|
||||
Undefined,
|
||||
Sand,
|
||||
Grass,
|
||||
DeepGrass
|
||||
}
|
||||
|
||||
static public TileType[] ValidTileTypes = { TileType.Sand, TileType.Grass, TileType.DeepGrass };
|
||||
|
||||
// scene nodes
|
||||
private MeshInstance _mesh;
|
||||
private StaticBody _staticBody;
|
||||
|
||||
// signals
|
||||
[Signal]
|
||||
private delegate void TileClicked(HexTile3D tile3d);
|
||||
delegate void TileClicked(HexTile3D tile3d);
|
||||
|
||||
[Signal]
|
||||
private delegate void TileHovered(HexTile3D tile3d);
|
||||
delegate void TileHovered(HexTile3D tile3d);
|
||||
|
||||
// other member variables
|
||||
private SpatialMaterial _previousMaterial;
|
||||
|
||||
private readonly HexGrid _hexGrid;
|
||||
private HexGrid _hexGrid;
|
||||
|
||||
public HexCell Cell = new();
|
||||
public bool IsMouseOver;
|
||||
public HexCell Cell = new HexCell();
|
||||
public bool IsMouseOver = false;
|
||||
public MeshInstance Mesh;
|
||||
|
||||
public Vector2 OffsetCoords {
|
||||
get => Cell.OffsetCoords;
|
||||
public Vector2 OffsetCoords
|
||||
{
|
||||
get { return Cell.OffsetCoords; }
|
||||
|
||||
set {
|
||||
set
|
||||
{
|
||||
Cell.OffsetCoords = value;
|
||||
Transform tile3dTransform = Transform;
|
||||
Vector2 cellPlaneCoords = _hexGrid.GetHexCenter(Cell);
|
||||
|
@ -47,12 +48,16 @@ public class HexTile3D : Spatial {
|
|||
}
|
||||
}
|
||||
|
||||
private HexTile3D() {
|
||||
public TileType Type { get; set; }
|
||||
|
||||
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");
|
||||
|
||||
|
@ -60,22 +65,28 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
@ -85,7 +96,8 @@ public class HexTile3D : Spatial {
|
|||
// _mesh.MaterialOverride = clonedMaterial;
|
||||
}
|
||||
|
||||
public void OnAreaMouseExited() {
|
||||
public void OnAreaMouseExited()
|
||||
{
|
||||
IsMouseOver = false;
|
||||
_mesh.MaterialOverride = _previousMaterial;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://materials/WorldTileTypeMaterial.tres" type="Material" id=1]
|
||||
[ext_resource path="res://materials/IslandColorRampShader.tres" type="Material" id=1]
|
||||
|
||||
[sub_resource type="OpenSimplexNoise" id=3]
|
||||
seed = 57
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using GoDotLog;
|
||||
|
||||
public class StreamContainer : Spatial {
|
||||
public class StreamContainer : Spatial
|
||||
{
|
||||
// readonly variables
|
||||
private readonly Transform _deactivatedTileTransform = new(Basis.Identity, Vector3.Up * 1000);
|
||||
|
||||
private readonly Transform _deactivatedTileTransform = new Transform(Basis.Identity, Vector3.Up * 1000);
|
||||
|
||||
// scene nodes
|
||||
private MeshInstance _bounds;
|
||||
private Spatial _activeTiles;
|
||||
|
@ -14,45 +18,50 @@ public class StreamContainer : Spatial {
|
|||
private MultiMeshInstance _tileMultiMesh;
|
||||
|
||||
// resources
|
||||
private readonly PackedScene _hexTileScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
||||
private PackedScene _hexTileScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
||||
|
||||
// exports
|
||||
[Export] public Vector2 Dimensions = new(8, 4);
|
||||
[Export] public Vector2 Dimensions = new Vector2(8, 4);
|
||||
[Export] public NodePath World;
|
||||
[Export] private bool ShowHexTiles;
|
||||
[Export] private bool ShowHexTiles = false;
|
||||
|
||||
[Signal]
|
||||
private delegate void TileClicked(HexTile3D tile3d);
|
||||
|
||||
delegate void TileClicked(HexTile3D tile3d);
|
||||
[Signal]
|
||||
private delegate void TileHovered(HexTile3D tile3d);
|
||||
delegate void TileHovered(HexTile3D tile3d);
|
||||
|
||||
// other members
|
||||
private Rect2 _currentOffsetCoordRect;
|
||||
private Rect2 _oldOffsetCoordRect;
|
||||
private HexGrid _hexGrid;
|
||||
|
||||
private readonly Dictionary<Vector2, HexTile3D> _coordToTile = new();
|
||||
private readonly Dictionary<HexTile3D, int> _tileToInstanceIndex = new();
|
||||
public List<Vector2> RemovedCoords = new();
|
||||
public List<Vector2> AddedCoords = new();
|
||||
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>();
|
||||
|
||||
public Rect2 CurrentOffsetCoordRect => _currentOffsetCoordRect;
|
||||
|
||||
public void SetWorld(TileWorld tileWorld) {
|
||||
TileWorld = tileWorld;
|
||||
public Rect2 CurrentOffsetCoordRect
|
||||
{
|
||||
get { return _currentOffsetCoordRect; }
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -66,12 +75,13 @@ 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
|
||||
|
@ -94,13 +104,15 @@ 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();
|
||||
|
@ -111,7 +123,8 @@ 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));
|
||||
|
@ -121,52 +134,65 @@ 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(coord_x, coord_y);
|
||||
Mathf.CeilToInt(expandedRect.Size.y) + 20))
|
||||
{
|
||||
Vector2 coord = new Vector2(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(coord_x, coord_y);
|
||||
Mathf.CeilToInt(_currentOffsetCoordRect.Size.y)))
|
||||
{
|
||||
Vector2 coord = new Vector2(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;
|
||||
}
|
||||
}
|
||||
|
@ -174,41 +200,49 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -216,50 +250,57 @@ 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(tile3D.GlobalTransform.basis.Rotated(Vector3.Up, Mathf.Deg2Rad(30)).Scaled(scale),
|
||||
tile3D.GlobalTransform.origin + Vector3.Up * -2.5f);
|
||||
|
||||
|
||||
Transform instanceTransform = new Transform(tile3D.GlobalTransform.basis.Rotated(Vector3.Up, Mathf.Deg2Rad(30)).Scaled(scale), tile3D.GlobalTransform.origin + Vector3.Up * -2.5f);
|
||||
|
||||
_tileMultiMesh.Multimesh.SetInstanceTransform(instanceIndex, instanceTransform);
|
||||
}
|
||||
|
||||
public void OnTileDeactivate(HexTile3D tile3D, Vector2 coord) {
|
||||
public void OnTileDeactivate(HexTile3D tile3D, Vector2 coord)
|
||||
{
|
||||
int instanceIndex = _tileToInstanceIndex[tile3D];
|
||||
_tileMultiMesh.Multimesh.SetInstanceTransform(instanceIndex, _deactivatedTileTransform);
|
||||
|
||||
|
||||
tile3D.Type = HexTile3D.TileType.Undefined;
|
||||
_unusedTiles.Enqueue(tile3D);
|
||||
_coordToTile.Remove(coord);
|
||||
RemovedCoords.Add(coord);
|
||||
}
|
||||
|
||||
public void OnTileClicked(HexTile3D tile) {
|
||||
public void OnTileClicked(HexTile3D tile)
|
||||
{
|
||||
EmitSignal("TileClicked", tile);
|
||||
}
|
||||
|
||||
public void OnTileHovered(HexTile3D tile) {
|
||||
|
||||
public void OnTileHovered(HexTile3D tile)
|
||||
{
|
||||
EmitSignal("TileHovered", tile);
|
||||
}
|
||||
|
||||
public void OnWorldGenerated() {
|
||||
foreach (Spatial node in _activeTiles.GetChildren()) {
|
||||
public void OnWorldGenerated()
|
||||
{
|
||||
foreach (Spatial node in _activeTiles.GetChildren())
|
||||
{
|
||||
HexTile3D tile = (HexTile3D)node;
|
||||
if (tile == null) {
|
||||
if (tile == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Transform tileTransform = tile.GlobalTransform;
|
||||
tileTransform.origin.y = TileWorld.GetHeightAtOffset(tile.OffsetCoords);
|
||||
tile.GlobalTransform = tileTransform;
|
||||
|
||||
|
||||
OnTileActivate(tile);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@ 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;
|
||||
|
@ -20,7 +21,8 @@ public class TileWorld : Spatial {
|
|||
private Spatial _environmentNode;
|
||||
private readonly Array<Spatial> _grassAssets = new();
|
||||
|
||||
private enum GenerationState {
|
||||
private enum GenerationState
|
||||
{
|
||||
Heightmap,
|
||||
Color,
|
||||
Objects,
|
||||
|
@ -32,7 +34,8 @@ public class TileWorld : Spatial {
|
|||
private delegate void WorldGenerated();
|
||||
|
||||
// public members
|
||||
public enum MapType {
|
||||
public enum MapType
|
||||
{
|
||||
Noise,
|
||||
Debug,
|
||||
Flat
|
||||
|
@ -59,7 +62,8 @@ 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();
|
||||
|
||||
|
@ -79,15 +83,18 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -99,7 +106,8 @@ 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);
|
||||
|
@ -122,10 +130,12 @@ 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;
|
||||
|
@ -143,7 +153,8 @@ public class TileWorld : Spatial {
|
|||
|
||||
OnMapGenerationStart();
|
||||
|
||||
switch (GenerationMapType) {
|
||||
switch (GenerationMapType)
|
||||
{
|
||||
case MapType.Debug:
|
||||
GenerateDebugMap();
|
||||
break;
|
||||
|
@ -156,7 +167,8 @@ public class TileWorld : Spatial {
|
|||
}
|
||||
}
|
||||
|
||||
private void GenerateDebugMap() {
|
||||
private void GenerateDebugMap()
|
||||
{
|
||||
ColormapImage = new Image();
|
||||
ColormapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
||||
|
||||
|
@ -166,8 +178,10 @@ 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,
|
||||
|
@ -183,7 +197,8 @@ public class TileWorld : Spatial {
|
|||
}
|
||||
|
||||
|
||||
private void GenerateFlatMap() {
|
||||
private void GenerateFlatMap()
|
||||
{
|
||||
ColormapImage = new Image();
|
||||
ColormapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
||||
|
||||
|
@ -193,8 +208,10 @@ 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));
|
||||
}
|
||||
|
@ -207,7 +224,8 @@ public class TileWorld : Spatial {
|
|||
}
|
||||
|
||||
|
||||
private void GenerateNoiseMap() {
|
||||
private void GenerateNoiseMap()
|
||||
{
|
||||
HeightmapImage = new Image();
|
||||
HeightmapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
||||
|
||||
|
@ -227,23 +245,28 @@ 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;
|
||||
|
@ -253,9 +276,10 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -271,52 +295,66 @@ 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);
|
||||
|
@ -325,7 +363,9 @@ public class TileWorld : Spatial {
|
|||
Entities.AddChild(chestAsset);
|
||||
MarkCellUnwalkable(cell);
|
||||
}
|
||||
} else if (IsColorWater(colorValue)) {
|
||||
}
|
||||
else if (IsColorWater(colorValue))
|
||||
{
|
||||
MarkCellUnwalkable(cell);
|
||||
}
|
||||
}
|
||||
|
@ -335,13 +375,16 @@ 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;
|
||||
|
@ -354,7 +397,9 @@ 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());
|
||||
|
@ -362,30 +407,49 @@ 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 Vector2 OffsetToTextureCoord(Vector2 offsetCoord) {
|
||||
|
||||
public HexTile3D.TileType GetTileTypeAtOffset(Vector2 offsetCoord)
|
||||
{
|
||||
if (!IsOffsetCoordValid(offsetCoord))
|
||||
{
|
||||
return HexTile3D.TileType.Undefined;
|
||||
}
|
||||
|
||||
return HexTile3D.ValidTileTypes[_tileTypeRandom.Next(HexTile3D.ValidTileTypes.Length)];
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -403,7 +467,8 @@ public class TileWorld : Spatial {
|
|||
}
|
||||
|
||||
|
||||
public void SetTileColorAtOffset(Vector2 offsetCoord, Color color) {
|
||||
public void SetTileColorAtOffset(Vector2 offsetCoord, Color color)
|
||||
{
|
||||
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
|
||||
|
||||
ColormapImage.Lock();
|
||||
|
@ -411,27 +476,32 @@ 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;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[ext_resource path="res://scenes/TileWorld.cs" type="Script" id=1]
|
||||
[ext_resource path="res://icon.png" type="Texture" id=2]
|
||||
[ext_resource path="res://materials/WorldTileTypeMaterial.tres" type="Material" id=3]
|
||||
[ext_resource path="res://materials/IslandColorRampShader.tres" type="Material" id=3]
|
||||
[ext_resource path="res://materials/IslandHeightmapFalloffShader.tres" type="Material" id=4]
|
||||
[ext_resource path="res://entities/rockB.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://entities/rockC.tscn" type="PackedScene" id=6]
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://icon.png" type="Texture" id=1]
|
||||
[ext_resource path="res://materials/shader/VoronoiBasedBiomes2D.gdshader" type="Shader" id=2]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id=2]
|
||||
shader = ExtResource( 2 )
|
||||
shader_param/DeepWaterColor = Color( 0, 0, 0.6, 1 )
|
||||
shader_param/WaterColor = Color( 0, 0, 0.7, 1 )
|
||||
shader_param/LightWaterColor = Color( 0, 0, 1, 1 )
|
||||
shader_param/SandColor = Color( 0.8, 0.8, 0.1, 1 )
|
||||
shader_param/GrassColor = Color( 0, 0.6, 0, 1 )
|
||||
shader_param/ForestColor = Color( 0, 0.4, 0, 1 )
|
||||
shader_param/RockColor = Color( 0.5, 0.5, 0.4, 1 )
|
||||
shader_param/SnowColor = Color( 1, 1, 1, 1 )
|
||||
|
||||
[node name="Node2D" type="Node2D"]
|
||||
|
||||
[node name="Sprite" type="Sprite" parent="."]
|
||||
material = SubResource( 2 )
|
||||
position = Vector2( 195, 368 )
|
||||
scale = Vector2( 5.89062, 5.29688 )
|
||||
texture = ExtResource( 1 )
|
616
scenes/World.cs
616
scenes/World.cs
|
@ -4,11 +4,12 @@ using System.Diagnostics;
|
|||
using System.Linq;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using Priority_Queue;
|
||||
|
||||
public class World : Spatial {
|
||||
public enum GenerationState {
|
||||
Empty,
|
||||
public class World : Spatial
|
||||
{
|
||||
public enum GenerationState
|
||||
{
|
||||
Undefined,
|
||||
Heightmap,
|
||||
TileType,
|
||||
Objects,
|
||||
|
@ -16,30 +17,32 @@ public class World : Spatial {
|
|||
}
|
||||
|
||||
// constants
|
||||
public int ChunkSize = 14;
|
||||
public const int ChunkSize = 12;
|
||||
public const int NumChunkRows = 3;
|
||||
public const int NumChunkColumns = NumChunkRows;
|
||||
|
||||
|
||||
private readonly System.Collections.Generic.Dictionary<int, HexTile3D.TileTypeInfo> _tileTypeInfos = new();
|
||||
private static readonly Color RockColor = new(0.5f, 0.5f, 0.4f);
|
||||
private static readonly Color GrassColor = new(0, 0.4f, 0);
|
||||
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 Godot.Collections.Dictionary<Vector2, WorldChunk> _cachedWorldChunks;
|
||||
private readonly List<Vector2> _addedChunkIndices = new();
|
||||
private readonly List<WorldChunk> _deactivatedWorldChunks = new();
|
||||
private readonly List<WorldChunk> _unusedWorldChunks = new();
|
||||
private readonly Image _heightmapImage = new();
|
||||
private readonly List<Vector2> _removedChunkIndices = new();
|
||||
private readonly Image _tileTypeMapImage = new();
|
||||
private int FrameCounter;
|
||||
|
||||
// referenced scenes
|
||||
private readonly PackedScene _worldChunkScene = GD.Load<PackedScene>("res://scenes/WorldChunk.tscn");
|
||||
|
||||
private List<Vector2> _activeChunkIndices = new();
|
||||
private Rect2 _centerChunkRect;
|
||||
private readonly List<Spatial> _removedSpatialNodes = new();
|
||||
|
||||
// delegate void OnCoordClicked(Vector2 world_pos);
|
||||
|
||||
// other members
|
||||
private Vector2 _centerPlaneCoord;
|
||||
private Vector2 _chunkIndexNorthEast;
|
||||
private Vector2 _chunkIndexSouthWest;
|
||||
private Array<Spatial> _grassAssets;
|
||||
|
@ -57,9 +60,10 @@ public class World : Spatial {
|
|||
public HexGrid HexGrid = new();
|
||||
public int Seed = 0;
|
||||
|
||||
public GenerationState State = GenerationState.Empty;
|
||||
public GenerationState State = GenerationState.Done;
|
||||
public Vector2 WorldTextureCoordinateOffset;
|
||||
|
||||
|
||||
// ui elements
|
||||
|
||||
// scene nodes
|
||||
|
@ -89,60 +93,43 @@ public class World : Spatial {
|
|||
[Signal]
|
||||
private delegate void TileHovered(HexTile3D tile3d);
|
||||
|
||||
public World() {
|
||||
public World()
|
||||
{
|
||||
Debug.Assert(ChunkSize % 2 == 0);
|
||||
|
||||
_cachedWorldChunks = new Godot.Collections.Dictionary<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);
|
||||
|
||||
_tileMultiMeshInstance = (MultiMeshInstance)FindNode("TileMultiMeshInstance");
|
||||
Debug.Assert(_tileMultiMeshInstance != null);
|
||||
_tileMultiMeshInstance.Multimesh.InstanceCount =
|
||||
ChunkSize * ChunkSize * NumChunkColumns * NumChunkRows;
|
||||
_usedTileMeshInstances = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
foreach (Spatial asset in GetNode<Node>("Assets/Trees").GetChildren()) _treeAssets.Add(asset);
|
||||
|
||||
_tileTypeInfos[0] = new HexTile3D.TileTypeInfo("Undefined", Colors.Black, 0xffff);
|
||||
LoadTileTypeInfo("DeepWater", (int)Entity.EntityMaskEnum.Water);
|
||||
LoadTileTypeInfo("Water", (int)Entity.EntityMaskEnum.Water);
|
||||
LoadTileTypeInfo("LightWater", (int)Entity.EntityMaskEnum.Water);
|
||||
LoadTileTypeInfo("Sand", (int)Entity.EntityMaskEnum.Ground);
|
||||
LoadTileTypeInfo("Grass", (int)Entity.EntityMaskEnum.Ground);
|
||||
LoadTileTypeInfo("Forest", (int)Entity.EntityMaskEnum.Ground);
|
||||
LoadTileTypeInfo("Rock", (int)Entity.EntityMaskEnum.Ground);
|
||||
LoadTileTypeInfo("Sand", (int)Entity.EntityMaskEnum.Ground);
|
||||
SetCenterPlaneCoord(Vector2.Zero);
|
||||
}
|
||||
|
||||
private void LoadTileTypeInfo(string tileTypeName, ushort tileTypeMask) {
|
||||
ShaderMaterial worldTileTypeShaderMaterial =
|
||||
GD.Load<ShaderMaterial>("res://materials/WorldTileTypeMaterial.tres");
|
||||
|
||||
Color tileTypeColor = (Color)worldTileTypeShaderMaterial.GetShaderParam(tileTypeName + "Color");
|
||||
_tileTypeInfos[tileTypeColor.ToRgba32()] =
|
||||
new HexTile3D.TileTypeInfo(tileTypeName, tileTypeColor, tileTypeMask);
|
||||
}
|
||||
|
||||
public void InitNoiseGenerator() {
|
||||
public void InitNoiseGenerator()
|
||||
{
|
||||
_noiseGenerator = new OpenSimplexNoise();
|
||||
|
||||
_noiseGenerator.Seed = Seed;
|
||||
|
@ -152,36 +139,22 @@ public class World : Spatial {
|
|||
_noiseGenerator.Lacunarity = 2;
|
||||
}
|
||||
|
||||
public void Reset() {
|
||||
foreach (Spatial chunkChild in Chunks.GetChildren()) {
|
||||
chunkChild.QueueFree();
|
||||
}
|
||||
|
||||
// foreach (WorldChunk chunk in _cachedWorldChunks.Values) {
|
||||
// chunk.QueueFree();
|
||||
// }
|
||||
|
||||
_cachedWorldChunks.Clear();
|
||||
_addedChunkIndices.Clear();
|
||||
|
||||
_tileMultiMeshInstance.Multimesh.InstanceCount =
|
||||
ChunkSize * ChunkSize * NumChunkColumns * NumChunkRows;
|
||||
_usedTileMeshInstances = 0;
|
||||
|
||||
State = GenerationState.Empty;
|
||||
}
|
||||
|
||||
public WorldChunk GetOrCreateWorldChunk(Vector2 chunkIndex, Color debugColor) {
|
||||
public WorldChunk GetOrCreateWorldChunk(Vector2 chunkIndex, Color debugColor)
|
||||
{
|
||||
WorldChunk chunk;
|
||||
|
||||
if (IsChunkCached(chunkIndex)) {
|
||||
if (IsChunkCached(chunkIndex))
|
||||
return _cachedWorldChunks[chunkIndex];
|
||||
}
|
||||
|
||||
if (_deactivatedWorldChunks.Count > 0) {
|
||||
chunk = _deactivatedWorldChunks.First();
|
||||
_deactivatedWorldChunks.RemoveAt(0);
|
||||
} else {
|
||||
if (_unusedWorldChunks.Count > 0)
|
||||
{
|
||||
chunk = _unusedWorldChunks.First();
|
||||
_unusedWorldChunks.RemoveAt(0);
|
||||
|
||||
GD.Print("Reusing chunk from former index " + chunk.ChunkIndex + " at new index " + chunkIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
chunk = CreateWorldChunk(chunkIndex, debugColor);
|
||||
}
|
||||
|
||||
|
@ -190,14 +163,15 @@ public class World : Spatial {
|
|||
return chunk;
|
||||
}
|
||||
|
||||
private bool IsChunkCached(Vector2 chunkIndex) {
|
||||
private bool IsChunkCached(Vector2 chunkIndex)
|
||||
{
|
||||
return _cachedWorldChunks.ContainsKey(chunkIndex);
|
||||
}
|
||||
|
||||
|
||||
private WorldChunk CreateWorldChunk(Vector2 chunkIndex, Color debugColor) {
|
||||
private WorldChunk CreateWorldChunk(Vector2 chunkIndex, Color debugColor)
|
||||
{
|
||||
WorldChunk result = (WorldChunk)_worldChunkScene.Instance();
|
||||
result.SetSize(ChunkSize);
|
||||
Chunks.AddChild(result);
|
||||
result.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
result.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
|
@ -217,16 +191,15 @@ public class World : Spatial {
|
|||
return result;
|
||||
}
|
||||
|
||||
private bool IsColorEqualApprox(Color colorA, Color colorB) {
|
||||
private bool IsColorEqualApprox(Color colorA, Color colorB)
|
||||
{
|
||||
Vector3 colorDifference = new(colorA.r - colorB.r, colorA.g - colorB.g, colorA.b - colorB.b);
|
||||
return colorDifference.LengthSquared() < 0.1 * 0.1;
|
||||
}
|
||||
|
||||
private Spatial SelectAsset(Vector2 textureCoord, Array<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;
|
||||
|
||||
int assetIndex = randomGenerator.Next(assets.Count);
|
||||
Spatial assetInstance = (Spatial)assets[assetIndex].Duplicate();
|
||||
|
@ -241,47 +214,41 @@ public class World : Spatial {
|
|||
return assetInstance;
|
||||
}
|
||||
|
||||
private void PopulateChunk(WorldChunk chunk) {
|
||||
private void PopulateChunk(WorldChunk chunk)
|
||||
{
|
||||
Random environmentRandom = new(Seed);
|
||||
|
||||
chunk.CreateUnlockedTileTypeImage();
|
||||
Image tileTypeImage = chunk.TileTypeOffscreenViewport.GetTexture().GetData();
|
||||
tileTypeImage.Lock();
|
||||
|
||||
foreach (int textureCoordU in Enumerable.Range(0, chunk.Size)) {
|
||||
foreach (int textureCoordV in Enumerable.Range(0, chunk.Size)) {
|
||||
Vector2 textureCoord = new(textureCoordU, textureCoordV);
|
||||
Vector2 offsetCoord = chunk.ChunkIndex * ChunkSize + textureCoord;
|
||||
foreach (int textureCoordU in Enumerable.Range(0, chunk.Size))
|
||||
foreach (int textureCoordV in Enumerable.Range(0, chunk.Size))
|
||||
{
|
||||
Color colorValue = tileTypeImage.GetPixel(textureCoordU, textureCoordV);
|
||||
Vector2 textureCoord = new(textureCoordU, textureCoordV);
|
||||
Vector2 offsetCoord = chunk.ChunkIndex * ChunkSize + textureCoord;
|
||||
|
||||
HexTile3D.TileTypeInfo tileTypeInfo = GetTileTypeInfoAtOffset(offsetCoord);
|
||||
if (IsColorEqualApprox(colorValue, RockColor))
|
||||
{
|
||||
Spatial rockAsset = SelectAsset(textureCoord, _rockAssets, environmentRandom, 0.15);
|
||||
if (rockAsset != null) chunk.Entities.AddChild(rockAsset);
|
||||
// TODO: MarkCellUnwalkable(cell);
|
||||
}
|
||||
else if (IsColorEqualApprox(colorValue, GrassColor) || IsColorEqualApprox(colorValue, DarkGrassColor))
|
||||
{
|
||||
Spatial grassAsset = SelectAsset(textureCoord, _grassAssets, environmentRandom, 0.15);
|
||||
if (grassAsset != null) chunk.Entities.AddChild(grassAsset);
|
||||
|
||||
if (tileTypeInfo.Name == "Rock") {
|
||||
Spatial rockAsset = SelectAsset(textureCoord, _rockAssets, environmentRandom, 0.15);
|
||||
if (rockAsset != null) {
|
||||
chunk.Entities.AddChild(rockAsset);
|
||||
MarkCellUnwalkable(HexGrid.GetHexAtOffset(offsetCoord));
|
||||
}
|
||||
} else if (tileTypeInfo.Name == "Grass" || tileTypeInfo.Name == "DarkGrass") {
|
||||
Spatial grassAsset = SelectAsset(textureCoord, _grassAssets, environmentRandom, 0.15);
|
||||
if (grassAsset != null) {
|
||||
chunk.Entities.AddChild(grassAsset);
|
||||
}
|
||||
Tree treeAsset = SelectAsset(textureCoord, _treeAssets, environmentRandom, 0.05) as Tree;
|
||||
if (treeAsset != null)
|
||||
{
|
||||
chunk.Entities.AddChild(treeAsset);
|
||||
treeAsset.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
||||
}
|
||||
|
||||
Tree treeAsset = SelectAsset(textureCoord, _treeAssets, environmentRandom, 0.05) as Tree;
|
||||
if (treeAsset != null) {
|
||||
chunk.Entities.AddChild(treeAsset);
|
||||
treeAsset.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
||||
treeAsset.Connect("TreeChopped", this, nameof(OnBlockingSpatialRemoved));
|
||||
MarkCellUnwalkable(HexGrid.GetHexAtOffset(offsetCoord));
|
||||
}
|
||||
|
||||
// TODO: MarkCellUnwalkable(cell);
|
||||
// else if (environmentRandom.NextDouble() < 0.01)
|
||||
} else if (tileTypeInfo.Name == "Water" || tileTypeInfo.Name == "LightWater" ||
|
||||
tileTypeInfo.Name == "DeepWater") {
|
||||
Spatial rockAsset = SelectAsset(textureCoord, _rockAssets, environmentRandom, 0.01);
|
||||
if (rockAsset != null) {
|
||||
chunk.Entities.AddChild(rockAsset);
|
||||
MarkCellUnwalkable(HexGrid.GetHexAtOffset(offsetCoord));
|
||||
}
|
||||
// TODO: MarkCellUnwalkable(cell);
|
||||
// else if (environmentRandom.NextDouble() < 0.01)
|
||||
// {
|
||||
// var chestAsset = (Chest)_chestScene.Instance();
|
||||
// var assetTransform = Transform.Identity;
|
||||
|
@ -291,35 +258,52 @@ 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 && State != GenerationState.Empty) {
|
||||
public void UpdateCenterChunkFromPlaneCoord(Vector2 planeCoord)
|
||||
{
|
||||
if (State != GenerationState.Done)
|
||||
{
|
||||
GD.PrintErr("Cannot update chunk to new planeCoord " + planeCoord + ": Chunk generation not yet finished!");
|
||||
return;
|
||||
}
|
||||
|
||||
GD.Print("Update Chunks: " + FrameCounter);
|
||||
|
||||
// mark all chunks as retired
|
||||
Godot.Collections.Dictionary<Vector2, WorldChunk> oldCachedChunks = new(_cachedWorldChunks);
|
||||
|
||||
// set new center chunk
|
||||
CenterChunkIndex = GetChunkTupleFromPlaneCoord(planeCoord);
|
||||
|
||||
WorldChunk currentChunk = GetOrCreateWorldChunk(CenterChunkIndex,
|
||||
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
|
||||
|
||||
|
||||
_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(CenterChunkIndex + new Vector2(-1, -1));
|
||||
|
@ -335,57 +319,50 @@ public class World : Spatial {
|
|||
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(+1, +1));
|
||||
|
||||
// clear unused chunks
|
||||
_deactivatedWorldChunks.Clear();
|
||||
_unusedWorldChunks.Clear();
|
||||
_addedChunkIndices.Clear();
|
||||
|
||||
foreach (Vector2 oldChunkIndex in oldCachedChunks.Keys) {
|
||||
if (!_activeChunkIndices.Contains(oldChunkIndex)) {
|
||||
foreach (Vector2 oldChunkIndex in oldCachedChunks.Keys)
|
||||
if (!_activeChunkIndices.Contains(oldChunkIndex))
|
||||
DeactivateChunk(oldCachedChunks[oldChunkIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Vector2 activeChunkIndex in _activeChunkIndices) {
|
||||
foreach (Vector2 activeChunkIndex in _activeChunkIndices)
|
||||
{
|
||||
WorldChunk chunk = GetOrCreateWorldChunk(activeChunkIndex,
|
||||
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
|
||||
_cachedWorldChunks[activeChunkIndex] = chunk;
|
||||
}
|
||||
|
||||
Debug.Assert(_activeChunkIndices.Count == NumChunkRows * NumChunkColumns);
|
||||
|
||||
foreach (Vector2 chunkKey in _activeChunkIndices) {
|
||||
if (!oldCachedChunks.ContainsKey(chunkKey)) {
|
||||
foreach (Vector2 chunkKey in _activeChunkIndices)
|
||||
if (!oldCachedChunks.ContainsKey(chunkKey))
|
||||
{
|
||||
ActivateChunk(_cachedWorldChunks[chunkKey], chunkKey);
|
||||
State = GenerationState.Heightmap;
|
||||
}
|
||||
}
|
||||
|
||||
WorldChunk currentChunk = GetOrCreateWorldChunk(CenterChunkIndex,
|
||||
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
|
||||
|
||||
_centerChunkRect = new Rect2(
|
||||
new Vector2(currentChunk.Transform.origin.x, currentChunk.Transform.origin.z)
|
||||
+ currentChunk.PlaneRect.Position,
|
||||
currentChunk.PlaneRect.Size);
|
||||
|
||||
UpdateChunkBounds();
|
||||
|
||||
UpdateNavigationBounds();
|
||||
}
|
||||
|
||||
private void ActivateChunk(WorldChunk chunk, Vector2 chunkIndex) {
|
||||
private void ActivateChunk(WorldChunk chunk, Vector2 chunkIndex)
|
||||
{
|
||||
chunk.SetChunkIndex(chunkIndex, HexGrid);
|
||||
chunk.UpdateTileTransforms();
|
||||
|
||||
_addedChunkIndices.Add(chunk.ChunkIndex);
|
||||
GD.Print("Generating noise for chunk " + chunk.ChunkIndex);
|
||||
GenerateChunkNoiseMap(chunk);
|
||||
}
|
||||
|
||||
private void DeactivateChunk(WorldChunk chunk) {
|
||||
private void DeactivateChunk(WorldChunk chunk)
|
||||
{
|
||||
GD.Print("Clearing chunk index: " + chunk.ChunkIndex);
|
||||
_cachedWorldChunks.Remove(chunk.ChunkIndex);
|
||||
chunk.ClearContent();
|
||||
_deactivatedWorldChunks.Add(chunk);
|
||||
_unusedWorldChunks.Add(chunk);
|
||||
}
|
||||
|
||||
private void GenerateChunkNoiseMap(WorldChunk chunk) {
|
||||
private void GenerateChunkNoiseMap(WorldChunk chunk)
|
||||
{
|
||||
Vector2 chunkIndex = chunk.ChunkIndex;
|
||||
|
||||
ImageTexture noiseImageTexture = new();
|
||||
|
@ -395,38 +372,37 @@ public class World : Spatial {
|
|||
chunk.SetNoisemap(noiseImageTexture);
|
||||
}
|
||||
|
||||
private void RemoveChunk(Vector2 cachedChunkKey) {
|
||||
private void RemoveChunk(Vector2 cachedChunkKey)
|
||||
{
|
||||
_cachedWorldChunks.Remove(cachedChunkKey);
|
||||
_removedChunkIndices.Add(cachedChunkKey);
|
||||
|
||||
foreach (WorldChunk chunk in Chunks.GetChildren()) {
|
||||
if (chunk.ChunkIndex == new Vector2(cachedChunkKey.x, cachedChunkKey.y)) {
|
||||
foreach (WorldChunk chunk in Chunks.GetChildren())
|
||||
if (chunk.ChunkIndex == new Vector2(cachedChunkKey.x, cachedChunkKey.y))
|
||||
chunk.QueueFree();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Vector2 GetChunkTupleFromPlaneCoord(Vector2 planeCoord) {
|
||||
HexCell hexCell = HexGrid.GetHexAt(planeCoord);
|
||||
return GetChunkIndexFromOffsetCoord(hexCell.OffsetCoords);
|
||||
private Vector2 GetChunkTupleFromPlaneCoord(Vector2 planeCoord)
|
||||
{
|
||||
HexCell centerOffsetCoord = HexGrid.GetHexAt(planeCoord);
|
||||
return (centerOffsetCoord.OffsetCoords / ChunkSize).Floor();
|
||||
}
|
||||
|
||||
private Vector2 GetChunkIndexFromOffsetCoord(Vector2 offsetCoord) {
|
||||
return (offsetCoord / ChunkSize).Floor();
|
||||
}
|
||||
|
||||
public void SetCenterPlaneCoord(Vector2 centerPlaneCoord) {
|
||||
if (State != GenerationState.Done) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_centerChunkRect.HasPoint(centerPlaneCoord)) {
|
||||
public void SetCenterPlaneCoord(Vector2 centerPlaneCoord)
|
||||
{
|
||||
if (!_centerChunkRect.HasPoint(centerPlaneCoord))
|
||||
{
|
||||
UpdateCenterChunkFromPlaneCoord(centerPlaneCoord);
|
||||
|
||||
UpdateChunkBounds();
|
||||
|
||||
UpdateNavigationBounds();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateWorldViewTexture() {
|
||||
private void UpdateWorldViewTexture()
|
||||
{
|
||||
int worldChunkSize = ChunkSize;
|
||||
int numWorldChunkRows = NumChunkRows;
|
||||
int numWorldChunkColumns = NumChunkColumns;
|
||||
|
@ -436,7 +412,8 @@ public class World : Spatial {
|
|||
_tileTypeMapImage.Create(worldChunkSize * numWorldChunkColumns, worldChunkSize * numWorldChunkRows, false,
|
||||
Image.Format.Rgba8);
|
||||
|
||||
foreach (Vector2 chunkIndex in _activeChunkIndices) {
|
||||
foreach (Vector2 chunkIndex in _activeChunkIndices)
|
||||
{
|
||||
WorldChunk worldChunk = GetOrCreateWorldChunk(chunkIndex, Colors.White);
|
||||
|
||||
_heightmapImage.BlendRect(
|
||||
|
@ -454,7 +431,7 @@ public class World : Spatial {
|
|||
_heightmapTexture.CreateFromImage(_heightmapImage);
|
||||
|
||||
_viewTileTypeTexture = new ImageTexture();
|
||||
_viewTileTypeTexture.CreateFromImage(_tileTypeMapImage, (uint)Texture.FlagsEnum.ConvertToLinear);
|
||||
_viewTileTypeTexture.CreateFromImage(_tileTypeMapImage);
|
||||
|
||||
WorldTextureCoordinateOffset = _chunkIndexSouthWest * worldChunkSize;
|
||||
|
||||
|
@ -462,316 +439,113 @@ public class World : Spatial {
|
|||
EmitSignal("OnHeightmapImageChanged", _heightmapImage);
|
||||
}
|
||||
|
||||
private void UpdateChunkBounds() {
|
||||
private void UpdateChunkBounds()
|
||||
{
|
||||
_chunkIndexSouthWest = Vector2.Inf;
|
||||
_chunkIndexNorthEast = -Vector2.Inf;
|
||||
|
||||
foreach (Vector2 chunkIndex in _activeChunkIndices) {
|
||||
if (chunkIndex.x <= _chunkIndexSouthWest.x && chunkIndex.y <= _chunkIndexSouthWest.y) {
|
||||
foreach (Vector2 chunkIndex in _activeChunkIndices)
|
||||
{
|
||||
WorldChunk worldChunk = GetOrCreateWorldChunk(chunkIndex, Colors.White);
|
||||
|
||||
if (chunkIndex.x <= _chunkIndexSouthWest.x && chunkIndex.y <= _chunkIndexSouthWest.y)
|
||||
_chunkIndexSouthWest = chunkIndex;
|
||||
} else if (chunkIndex.x >= _chunkIndexNorthEast.x && chunkIndex.y >= _chunkIndexNorthEast.y) {
|
||||
else if (chunkIndex.x >= _chunkIndexNorthEast.x && chunkIndex.y >= _chunkIndexNorthEast.y)
|
||||
_chunkIndexNorthEast = chunkIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateNavigationBounds() {
|
||||
private void UpdateNavigationBounds()
|
||||
{
|
||||
HexCell cellSouthWest = HexGrid.GetHexAtOffset(_chunkIndexSouthWest * ChunkSize);
|
||||
// Chunks have their cells ordered from south west (0,0) to north east (ChunkSize, ChunkSize). For the
|
||||
// north east cell we have to add the chunk size to get to the actual corner cell.
|
||||
HexCell cellNorthEast =
|
||||
HexGrid.GetHexAtOffset(_chunkIndexNorthEast * ChunkSize + Vector2.One * (ChunkSize - 1));
|
||||
|
||||
HexCell centerCell =
|
||||
HexGrid.GetHexAtOffset(((cellNorthEast.OffsetCoords - cellSouthWest.OffsetCoords) / 2).Round());
|
||||
int numCells = ChunkSize * Math.Max(NumChunkColumns, NumChunkRows);
|
||||
|
||||
HexGrid.SetBoundsOffset(cellSouthWest, ChunkSize * new Vector2(NumChunkColumns, NumChunkRows));
|
||||
}
|
||||
|
||||
public 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;
|
||||
Color tileTypeColor = GetTileTypeColorAtOffset(nextOffset);
|
||||
|
||||
if (_tileTypeInfos.TryGetValue(tileTypeColor.ToRgba32(), out HexTile3D.TileTypeInfo info)) {
|
||||
int tileTypeMask = info.TileTypeMask;
|
||||
if ((entity.EntityMask ^ tileTypeMask) != 0) {
|
||||
nextHexCost = 0;
|
||||
}
|
||||
} else {
|
||||
GD.Print("Could not find tile type info for color " + tileTypeColor);
|
||||
}
|
||||
}
|
||||
|
||||
return nextHexCost;
|
||||
}
|
||||
|
||||
private HexTile3D.TileTypeInfo GetTileTypeInfoAtOffset(Vector2 offsetCoord) {
|
||||
Color tileTypeColor = GetTileTypeColorAtOffset(offsetCoord);
|
||||
if (_tileTypeInfos.TryGetValue(tileTypeColor.ToRgba32(), out HexTile3D.TileTypeInfo info)) {
|
||||
return info;
|
||||
}
|
||||
|
||||
return _tileTypeInfos[0];
|
||||
}
|
||||
|
||||
public Color GetTileTypeColorAtOffset(Vector2 offsetCoord) {
|
||||
Vector2 chunkIndex = GetChunkIndexFromOffsetCoord(offsetCoord);
|
||||
|
||||
if (!_cachedWorldChunks.ContainsKey(chunkIndex)) {
|
||||
return Colors.Black;
|
||||
}
|
||||
|
||||
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
||||
Vector2 textureCoordinate = offsetCoord - Vector2.One * ChunkSize * chunkIndex;
|
||||
|
||||
Color tileTypeColor = chunk.TileTypeImage.GetPixel((int)textureCoordinate.x, (int)textureCoordinate.y);
|
||||
return tileTypeColor;
|
||||
}
|
||||
|
||||
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) {
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
GenerationState oldState = State;
|
||||
|
||||
UpdateGenerationState();
|
||||
|
||||
if (oldState != GenerationState.Done && State == GenerationState.Done) {
|
||||
if (oldState != GenerationState.Done && State == GenerationState.Done)
|
||||
UpdateWorldViewTexture();
|
||||
}
|
||||
|
||||
while (_removedSpatialNodes.Count > 0) {
|
||||
GD.Print("Queueing deletion of " + _removedSpatialNodes[0]);
|
||||
_removedSpatialNodes[0].QueueFree();
|
||||
_removedSpatialNodes.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateGenerationState() {
|
||||
if (State == GenerationState.Heightmap) {
|
||||
private void UpdateGenerationState()
|
||||
{
|
||||
FrameCounter++;
|
||||
|
||||
if (State == GenerationState.Heightmap)
|
||||
{
|
||||
int numChunksGeneratingHeightmap = 0;
|
||||
foreach (Vector2 chunkIndex in _addedChunkIndices) {
|
||||
foreach (Vector2 chunkIndex in _addedChunkIndices)
|
||||
{
|
||||
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
||||
if (chunk.HeightMapFrameCount > 0) {
|
||||
numChunksGeneratingHeightmap++;
|
||||
}
|
||||
if (chunk.HeightMapFrameCount > 0) numChunksGeneratingHeightmap++;
|
||||
}
|
||||
|
||||
if (numChunksGeneratingHeightmap == 0) {
|
||||
if (numChunksGeneratingHeightmap == 0)
|
||||
{
|
||||
// assign height map images
|
||||
foreach (Vector2 chunkIndex in _addedChunkIndices) {
|
||||
foreach (Vector2 chunkIndex in _addedChunkIndices)
|
||||
{
|
||||
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
||||
chunk.SetHeightmap(chunk.HeightmapOffscreenViewport.GetTexture());
|
||||
}
|
||||
|
||||
GD.Print("Switching to TileType Generation: " + FrameCounter);
|
||||
State = GenerationState.TileType;
|
||||
}
|
||||
} else if (State == GenerationState.TileType) {
|
||||
}
|
||||
else if (State == GenerationState.TileType)
|
||||
{
|
||||
int numChunksGeneratingTileType = 0;
|
||||
foreach (Vector2 chunkIndex in _addedChunkIndices) {
|
||||
foreach (Vector2 chunkIndex in _addedChunkIndices)
|
||||
{
|
||||
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
||||
if (chunk.TileTypeMapFrameCount > 0) {
|
||||
numChunksGeneratingTileType++;
|
||||
}
|
||||
if (chunk.TileTypeMapFrameCount > 0) numChunksGeneratingTileType++;
|
||||
}
|
||||
|
||||
if (numChunksGeneratingTileType == 0) {
|
||||
if (numChunksGeneratingTileType == 0)
|
||||
{
|
||||
GD.Print("Switching to Object Generation: " + FrameCounter);
|
||||
State = GenerationState.Objects;
|
||||
}
|
||||
} else if (State == GenerationState.Objects) {
|
||||
}
|
||||
else if (State == GenerationState.Objects)
|
||||
{
|
||||
// generate objects
|
||||
foreach (Vector2 chunkIndex in _addedChunkIndices) {
|
||||
foreach (Vector2 chunkIndex in _addedChunkIndices)
|
||||
PopulateChunk(_cachedWorldChunks[chunkIndex]);
|
||||
}
|
||||
|
||||
_addedChunkIndices.Clear();
|
||||
|
||||
GD.Print("Generation done: " + FrameCounter);
|
||||
State = GenerationState.Done;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEntityClicked(Entity entity) {
|
||||
private void OnEntityClicked(Entity entity)
|
||||
{
|
||||
EmitSignal("EntityClicked", entity);
|
||||
}
|
||||
|
||||
public void OnTileClicked(HexTile3D tile) {
|
||||
if (State != GenerationState.Done) {
|
||||
return;
|
||||
}
|
||||
|
||||
public void OnTileClicked(HexTile3D tile)
|
||||
{
|
||||
EmitSignal("TileClicked", tile);
|
||||
}
|
||||
|
||||
public void OnTileHovered(HexTile3D tile) {
|
||||
if (State != GenerationState.Done) {
|
||||
return;
|
||||
}
|
||||
|
||||
public void OnTileHovered(HexTile3D tile)
|
||||
{
|
||||
EmitSignal("TileHovered", tile);
|
||||
HexTile3D.TileTypeInfo tileTypeInfo = GetTileTypeInfoAtOffset(tile.OffsetCoords);
|
||||
}
|
||||
|
||||
public void OnBlockingSpatialRemoved(Spatial spatialNode) {
|
||||
if (spatialNode.IsQueuedForDeletion()) {
|
||||
return;
|
||||
}
|
||||
|
||||
HexGrid.RemoveObstacle(HexGrid.GetHexAt(new Vector2(spatialNode.GlobalTranslation.x,
|
||||
spatialNode.GlobalTranslation.z)));
|
||||
_removedSpatialNodes.Add(spatialNode);
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
[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 )
|
|
@ -3,7 +3,8 @@ using System.Linq;
|
|||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
public class WorldChunk : Spatial {
|
||||
public class WorldChunk : Spatial
|
||||
{
|
||||
private readonly PackedScene _hexTile3DScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
||||
private MultiMeshInstance _multiMeshInstance;
|
||||
private readonly Array<int> _tileInstanceIndices = new();
|
||||
|
@ -27,11 +28,10 @@ public class WorldChunk : Spatial {
|
|||
[Export] public Texture HeightMap;
|
||||
public int HeightMapFrameCount;
|
||||
|
||||
public Image TileTypeImage;
|
||||
public Viewport HeightmapOffscreenViewport;
|
||||
[Export] public Texture NavigationMap;
|
||||
|
||||
public bool NoiseTextureCheckerboardOverlay = false;
|
||||
public bool NoiseTextureCheckerboardOverlay = true;
|
||||
|
||||
// signals
|
||||
[Signal]
|
||||
|
@ -47,7 +47,7 @@ public class WorldChunk : Spatial {
|
|||
|
||||
// scene nodes
|
||||
private MeshInstance PlaneRectMesh;
|
||||
public int Size = 32;
|
||||
[Export] public int Size = 32;
|
||||
|
||||
// resources
|
||||
|
||||
|
@ -56,24 +56,32 @@ 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;
|
||||
|
||||
Transform planeRectTransform = Transform.Identity;
|
||||
planeRectTransform =
|
||||
|
@ -104,12 +112,16 @@ public class WorldChunk : Spatial {
|
|||
|
||||
Tiles = (Spatial)FindNode("Tiles");
|
||||
Debug.Assert(Tiles != null);
|
||||
|
||||
SetSize(World.ChunkSize);
|
||||
}
|
||||
|
||||
public void SetSize(int size) {
|
||||
public void SetSize(int size)
|
||||
{
|
||||
Size = size;
|
||||
|
||||
if (TileTypeOffscreenViewport != null) {
|
||||
if (TileTypeOffscreenViewport != null)
|
||||
{
|
||||
TileTypeOffscreenViewport.Size = Vector2.One * size;
|
||||
HeightmapOffscreenViewport.Size = Vector2.One * size;
|
||||
_noiseMask.Transform = Transform2D.Identity.Scaled(Vector2.One * size / _noiseMask.Texture.GetSize().x);
|
||||
|
@ -119,9 +131,10 @@ public class WorldChunk : Spatial {
|
|||
}
|
||||
}
|
||||
|
||||
public void SetChunkIndex(Vector2 chunkIndex, HexGrid hexGrid) {
|
||||
public void SetChunkIndex(Vector2 chunkIndex, HexGrid hexGrid)
|
||||
{
|
||||
ChunkIndex = chunkIndex;
|
||||
float chunkSize = Size;
|
||||
float chunkSize = World.ChunkSize;
|
||||
|
||||
Vector2 planeCoordSouthWest = hexGrid.GetHexCenterFromOffset(chunkIndex * chunkSize);
|
||||
|
||||
|
@ -135,60 +148,62 @@ public class WorldChunk : Spatial {
|
|||
new Vector2(localPlaneCoordSouthWest.x, localPlaneCoordNorthEast.y),
|
||||
new Vector2(localPlaneCoordNorthEast.x - localPlaneCoordSouthWest.x,
|
||||
localPlaneCoordSouthWest.y - localPlaneCoordNorthEast.y)
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
public void InitializeTileInstances(Vector2 chunkIndex, MultiMeshInstance multiMeshInstance,
|
||||
int tileInstanceIndexStart) {
|
||||
int tileInstanceIndexStart)
|
||||
{
|
||||
_multiMeshInstance = multiMeshInstance;
|
||||
_tileInstanceIndices.Clear();
|
||||
|
||||
int chunkSize = Size;
|
||||
int chunkSize = World.ChunkSize;
|
||||
|
||||
foreach (Spatial node in Tiles.GetChildren()) {
|
||||
foreach (Spatial node in Tiles.GetChildren())
|
||||
node.QueueFree();
|
||||
}
|
||||
|
||||
foreach (int i in Enumerable.Range(0, chunkSize)) {
|
||||
foreach (int j in Enumerable.Range(0, chunkSize)) {
|
||||
HexTile3D tile3D = (HexTile3D)_hexTile3DScene.Instance();
|
||||
tile3D.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
tile3D.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
foreach (int i in Enumerable.Range(0, chunkSize))
|
||||
foreach (int j in Enumerable.Range(0, chunkSize))
|
||||
{
|
||||
HexTile3D tile3D = (HexTile3D)_hexTile3DScene.Instance();
|
||||
tile3D.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
tile3D.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
|
||||
tile3D.Cell.OffsetCoords = new Vector2(chunkIndex * chunkSize + new Vector2(i, j));
|
||||
_tileInstanceIndices.Add(tileInstanceIndexStart + _tileInstanceIndices.Count);
|
||||
tile3D.Cell.OffsetCoords = new Vector2(chunkIndex * World.ChunkSize + new Vector2(i, j));
|
||||
_tileInstanceIndices.Add(tileInstanceIndexStart + _tileInstanceIndices.Count);
|
||||
|
||||
Transform tileTransform = Transform.Identity;
|
||||
Vector2 centerPlaneCoord = _hexGrid.GetHexCenterFromOffset(new Vector2(i, j));
|
||||
tileTransform.origin = new Vector3(centerPlaneCoord.x, 0, centerPlaneCoord.y);
|
||||
tile3D.Transform = tileTransform;
|
||||
Transform tileTransform = Transform.Identity;
|
||||
Vector2 centerPlaneCoord = _hexGrid.GetHexCenterFromOffset(new Vector2(i, j));
|
||||
tileTransform.origin = new Vector3(centerPlaneCoord.x, 0, centerPlaneCoord.y);
|
||||
tile3D.Transform = tileTransform;
|
||||
|
||||
Tiles.AddChild(tile3D);
|
||||
}
|
||||
Tiles.AddChild(tile3D);
|
||||
}
|
||||
|
||||
_multiMeshInstance.Multimesh.VisibleInstanceCount = _multiMeshInstance.Multimesh.InstanceCount;
|
||||
|
||||
GD.Print("Chunk: " + chunkIndex + " Last index: " + _tileInstanceIndices.Last());
|
||||
}
|
||||
|
||||
public void ClearContent() {
|
||||
foreach (Spatial child in Entities.GetChildren()) {
|
||||
public void ClearContent()
|
||||
{
|
||||
foreach (Spatial child in Entities.GetChildren())
|
||||
child.QueueFree();
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTileTransforms() {
|
||||
public void UpdateTileTransforms()
|
||||
{
|
||||
Transform chunkTransform = Transform.Identity;
|
||||
Vector2 chunkOriginPlaneCoord = _hexGrid.GetHexCenterFromOffset(ChunkIndex * Size);
|
||||
Vector2 chunkOriginPlaneCoord = _hexGrid.GetHexCenterFromOffset(ChunkIndex * World.ChunkSize);
|
||||
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;
|
||||
GD.Print("Updating transforms for instances of chunk " + ChunkIndex + " origin: " + chunkTransform.origin);
|
||||
|
||||
foreach (int i in Enumerable.Range(0, _tileInstanceIndices.Count))
|
||||
{
|
||||
int column = i % World.ChunkSize;
|
||||
int row = i / World.ChunkSize;
|
||||
|
||||
Vector2 tilePlaneCoord =
|
||||
_hexGrid.GetHexCenterFromOffset(new Vector2(column, row));
|
||||
|
@ -196,17 +211,17 @@ public class WorldChunk : Spatial {
|
|||
Transform hexTransform = new(tileOrientation,
|
||||
chunkTransform.origin + new Vector3(tilePlaneCoord.x, 0, tilePlaneCoord.y));
|
||||
|
||||
if (_showHexTiles) {
|
||||
if (_showHexTiles)
|
||||
hexTransform = new Transform(tileOrientation.Scaled(Vector3.One * 0.95f),
|
||||
hexTransform.origin);
|
||||
}
|
||||
|
||||
_multiMeshInstance.Multimesh.SetInstanceTransform(_tileInstanceIndices[i], hexTransform);
|
||||
}
|
||||
}
|
||||
|
||||
// other members
|
||||
public void SaveToFile(string chunkName) {
|
||||
public void SaveToFile(string chunkName)
|
||||
{
|
||||
Image image = new();
|
||||
|
||||
image.CreateFromData(Size, Size, false, Image.Format.Rgba8, TileTypeMap.GetData().GetData());
|
||||
|
@ -219,10 +234,13 @@ 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);
|
||||
|
@ -230,7 +248,8 @@ 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());
|
||||
|
@ -239,29 +258,25 @@ public class WorldChunk : Spatial {
|
|||
TileTypeMapFrameCount = 1;
|
||||
}
|
||||
|
||||
public void CreateUnlockedTileTypeImage() {
|
||||
TileTypeImage = TileTypeOffscreenViewport.GetTexture().GetData();
|
||||
TileTypeImage.Lock();
|
||||
}
|
||||
|
||||
public override void _Process(float delta) {
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
Texture tileTypeTexture = TileTypeOffscreenViewport.GetTexture();
|
||||
|
||||
if (NoiseTextureCheckerboardOverlay) {
|
||||
if (NoiseTextureCheckerboardOverlay)
|
||||
{
|
||||
Image tileTypeImage = tileTypeTexture.GetData();
|
||||
tileTypeImage.Lock();
|
||||
|
||||
foreach (int i in Enumerable.Range(0, Size)) {
|
||||
foreach (int j in Enumerable.Range(0, Size)) {
|
||||
Vector2 textureCoord = new(i, j);
|
||||
Color baseColor = tileTypeImage.GetPixelv(textureCoord);
|
||||
foreach (int i in Enumerable.Range(0, Size))
|
||||
foreach (int j in Enumerable.Range(0, Size))
|
||||
{
|
||||
Vector2 textureCoord = new(i, j);
|
||||
Color baseColor = tileTypeImage.GetPixelv(textureCoord);
|
||||
|
||||
if ((i + j) % 2 == 0) {
|
||||
tileTypeImage.SetPixelv(textureCoord, baseColor);
|
||||
} else {
|
||||
tileTypeImage.SetPixelv(textureCoord, baseColor * 0.6f);
|
||||
}
|
||||
}
|
||||
if ((i + j) % 2 == 0)
|
||||
tileTypeImage.SetPixelv(textureCoord, baseColor);
|
||||
else
|
||||
tileTypeImage.SetPixelv(textureCoord, baseColor * 0.6f);
|
||||
}
|
||||
|
||||
tileTypeImage.Unlock();
|
||||
|
@ -280,26 +295,24 @@ public class WorldChunk : Spatial {
|
|||
//RectMaterial.Uv1Triplanar = true;
|
||||
PlaneRectMesh.SetSurfaceMaterial(0, _rectMaterial);
|
||||
|
||||
if (HeightMapFrameCount == 0) {
|
||||
HeightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
||||
}
|
||||
if (HeightMapFrameCount == 0) HeightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
||||
|
||||
HeightMapFrameCount = HeightMapFrameCount > 0 ? HeightMapFrameCount - 1 : 0;
|
||||
|
||||
if (TileTypeMapFrameCount == 0) {
|
||||
TileTypeOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
||||
}
|
||||
if (TileTypeMapFrameCount == 0) TileTypeOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
||||
|
||||
TileTypeMapFrameCount = TileTypeMapFrameCount > 0 ? TileTypeMapFrameCount - 1 : 0;
|
||||
|
||||
PlaneRectMesh.MaterialOverride = null;
|
||||
}
|
||||
|
||||
public void OnTileClicked(HexTile3D tile) {
|
||||
public void OnTileClicked(HexTile3D tile)
|
||||
{
|
||||
EmitSignal("TileClicked", tile);
|
||||
}
|
||||
|
||||
public void OnTileHovered(HexTile3D tile) {
|
||||
public void OnTileHovered(HexTile3D tile)
|
||||
{
|
||||
EmitSignal("TileHovered", tile);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
[gd_scene load_steps=10 format=2]
|
||||
|
||||
[ext_resource path="res://scenes/WorldChunk.cs" type="Script" id=1]
|
||||
[ext_resource path="res://materials/WorldTileTypeMaterial.tres" type="Material" id=2]
|
||||
[ext_resource path="res://materials/IslandColorRampShader.tres" type="Material" id=2]
|
||||
[ext_resource path="res://assets/TestHeightmap.tres" type="Texture" id=3]
|
||||
[ext_resource path="res://assets/4x4checkerColor.png" type="Texture" id=4]
|
||||
[ext_resource path="res://addons/gdhexgrid/icon.png" type="Texture" id=6]
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
public class EditorUI : Control {
|
||||
public enum InputMode {
|
||||
public class EditorUI : Control
|
||||
{
|
||||
public enum InputMode
|
||||
{
|
||||
None,
|
||||
Grass,
|
||||
Sand,
|
||||
|
@ -34,7 +35,8 @@ 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
|
||||
|
@ -67,65 +69,74 @@ 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) {
|
||||
Array gameGeometries = GetTree().GetNodesInGroup("GameGeometry");
|
||||
foreach (Spatial mesh in gameGeometries) {
|
||||
if (mesh != null) {
|
||||
public void OnGameGeometryCheckBoxToggled(bool pressed)
|
||||
{
|
||||
var gameGeometries = GetTree().GetNodesInGroup("GameGeometry");
|
||||
foreach (Spatial mesh in gameGeometries)
|
||||
if (mesh != null)
|
||||
mesh.Visible = pressed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnPhysicsGeometryCheckBoxToggled(bool pressed) {
|
||||
Array physicsGeometries = GetTree().GetNodesInGroup("PhysicsGeometry");
|
||||
foreach (Spatial mesh in physicsGeometries) {
|
||||
if (mesh != null) {
|
||||
public void OnPhysicsGeometryCheckBoxToggled(bool pressed)
|
||||
{
|
||||
var 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();
|
||||
public void UpdateTileMaterial()
|
||||
{
|
||||
if (_navigationGeometryCheckBox.Pressed)
|
||||
{
|
||||
ImageTexture newWorldTexture = new ImageTexture();
|
||||
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();
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageTexture newWorldTexture = new ImageTexture();
|
||||
newWorldTexture.CreateFromImage(_tileWorld.ColormapImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
|
||||
|
@ -134,8 +145,10 @@ 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,7 +1,9 @@
|
|||
using System.Diagnostics;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
public class HexTile3DMaterialAssign : Spatial {
|
||||
public class HexTile3DMaterialAssign : Spatial
|
||||
{
|
||||
// Declare member variables here. Examples:
|
||||
// private int a = 2;
|
||||
// private string b = "text";
|
||||
|
@ -13,9 +15,10 @@ 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));
|
||||
|
@ -27,39 +30,42 @@ 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 = new Image();
|
||||
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,56 +1,65 @@
|
|||
using System.Diagnostics;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
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 World _world;
|
||||
private TileWorld _tileWorld;
|
||||
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");
|
||||
_world = GetNode<World>("World");
|
||||
_tileWorld = GetNode<TileWorld>("TileWorld");
|
||||
_tileWorld.Connect("WorldGenerated", this, nameof(OnWorldGenerated));
|
||||
_streamContainer = GetNode<StreamContainer>("StreamContainer");
|
||||
|
||||
_streamContainer.SetCenterTile(_currentTile);
|
||||
|
||||
_player = GetNode<Player>("Player");
|
||||
_playerNavigationComponent = _player.GetNode<NavigationComponent>("Navigation");
|
||||
|
||||
// connect signals
|
||||
_world.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
_world.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
_world.Connect("OnWorldViewTileTypeImageChanged", this, nameof(OnWorldViewTileTypeImageChanged));
|
||||
_world.Connect("OnHeightmapImageChanged", this, nameof(OnHeightmapImageChanged));
|
||||
|
||||
|
||||
// input handling
|
||||
// _groundLayer.Connect("input_event", this, nameof(OnGroundLayerInputEvent));
|
||||
_streamContainer.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||
_streamContainer.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||
|
||||
CorrectEntityGridPositions();
|
||||
}
|
||||
|
||||
public void CorrectEntityGridPositions() {
|
||||
public void CorrectEntityGridPositions()
|
||||
{
|
||||
Spatial entitiesNode = GetNode<Spatial>("Entities");
|
||||
if (entitiesNode == null) {
|
||||
if (entitiesNode == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
Vector2 cellPlaneCoords = _hexGrid.GetHexCenterFromOffset(entityCell.OffsetCoords);
|
||||
Vector3 entityGlobalTranslation = entity.GlobalTranslation;
|
||||
entityGlobalTranslation.x = cellPlaneCoords.x;
|
||||
|
@ -59,61 +68,79 @@ public class NavigationTests : Spatial {
|
|||
}
|
||||
}
|
||||
|
||||
private void OnHeightmapImageChanged(Image heightmapImage) {
|
||||
ImageTexture newHeightmapTexture = new();
|
||||
newHeightmapTexture.CreateFromImage(heightmapImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
}
|
||||
public void OnWorldGenerated()
|
||||
{
|
||||
_streamContainer.OnWorldGenerated();
|
||||
|
||||
private void OnWorldViewTileTypeImageChanged(Image viewTileTypeImage) {
|
||||
ImageTexture newWorldTexture = new();
|
||||
newWorldTexture.CreateFromImage(viewTileTypeImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
// Properly place the Player
|
||||
Vector2 centerTileCoord = (Vector2.One * _tileWorld.Size / 2).Round();
|
||||
Vector3 worldCenterTileCoords = _tileWorld.GetTileWorldCenterFromOffset(centerTileCoord);
|
||||
worldCenterTileCoords.y = _tileWorld.GetHeightAtOffset(centerTileCoord);
|
||||
Transform playerTransform = Transform.Identity;
|
||||
playerTransform.origin = worldCenterTileCoords;
|
||||
_player.Transform = playerTransform;
|
||||
|
||||
ImageTexture newWorldTexture = new ImageTexture();
|
||||
newWorldTexture.CreateFromImage(_tileWorld.ColormapImage,
|
||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
|
||||
_tileMaterial.SetShaderParam("TextureSize", (int)newWorldTexture.GetSize().x);
|
||||
_tileMaterial.SetShaderParam("CoordinateOffsetU", (int)_world.WorldTextureCoordinateOffset.x);
|
||||
_tileMaterial.SetShaderParam("CoordinateOffsetV", (int)_world.WorldTextureCoordinateOffset.y);
|
||||
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.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.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=26 format=2]
|
||||
[gd_scene load_steps=25 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,7 +11,6 @@
|
|||
[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]
|
||||
|
||||
|
@ -290,21 +289,18 @@ script = ExtResource( 4 )
|
|||
|
||||
[node name="Player" parent="." instance=ExtResource( 1 )]
|
||||
collision_mask = 1
|
||||
WorldNode = NodePath("../World")
|
||||
TileWorldNode = NodePath("../TileWorld")
|
||||
|
||||
[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="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="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 )]
|
||||
|
||||
|
@ -378,10 +374,8 @@ 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/PirateAsset"]
|
||||
[editable path="Player/Geometry"]
|
||||
[editable path="TileWorld"]
|
||||
[editable path="StreamContainer"]
|
||||
[editable path="Entities/Chest"]
|
||||
|
|
|
@ -1,68 +1,84 @@
|
|||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Godot.Collections;
|
||||
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<InteractionComponent> endedInteractions = new();
|
||||
List<NodePair> invalidInteractionPairs = new List<NodePair>();
|
||||
List<InteractionComponent> endedInteractions = new List<InteractionComponent>();
|
||||
|
||||
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();
|
||||
public void OnStartInteraction(Entity owningEntity, Entity targetEntity)
|
||||
{
|
||||
InteractionComponent interactionComponent = new InteractionComponent();
|
||||
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,11 +1,12 @@
|
|||
using System;
|
||||
|
||||
public class LookupWorldSystem : IWorldSystemInterface {
|
||||
public void RegisterEntityComponent(Entity entity, Component component) {
|
||||
throw new NotImplementedException();
|
||||
public class LookupWorldSystem : IWorldSystemInterface
|
||||
{
|
||||
public void RegisterEntityComponent(Entity entity, Component component)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void Update(float delta) {
|
||||
throw new NotImplementedException();
|
||||
public void Update(float delta)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
public interface IWorldSystemInterface {
|
||||
public interface IWorldSystemInterface
|
||||
{
|
||||
void RegisterEntityComponent(Entity entity, Component component);
|
||||
void Update(float delta);
|
||||
}
|
|
@ -1,22 +1,27 @@
|
|||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
using GoDotTest;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
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();
|
||||
public void TestHexCellSimple()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
Debug.Assert(cell.CubeCoords == new Vector3(0, 0, 0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHexCellEqualityInequality() {
|
||||
HexCell cellA = new();
|
||||
HexCell cellB = new();
|
||||
public void TestHexCellEqualityInequality()
|
||||
{
|
||||
HexCell cellA = new HexCell();
|
||||
HexCell cellB = new HexCell();
|
||||
|
||||
cellA.AxialCoords = new Vector2(2, 3);
|
||||
cellB.AxialCoords = new Vector2(2, 3);
|
||||
|
@ -32,8 +37,9 @@ public class HexCellTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestAxialCoords() {
|
||||
HexCell cell = new(1, 1, -2);
|
||||
public void TestAxialCoords()
|
||||
{
|
||||
HexCell cell = new HexCell(1, 1, -2);
|
||||
Debug.Assert(cell.AxialCoords == new Vector2(1, 1));
|
||||
|
||||
cell = new HexCell(1, -1);
|
||||
|
@ -45,8 +51,9 @@ public class HexCellTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestAxialCoordsRounded() {
|
||||
HexCell cell = new(new Vector2(-0.1f, 0.6f));
|
||||
public void TestAxialCoordsRounded()
|
||||
{
|
||||
HexCell cell = new HexCell(new Vector2(-0.1f, 0.6f));
|
||||
Debug.Assert(cell.CubeCoords == new Vector3(0, 1, -1));
|
||||
|
||||
cell = new HexCell(new Vector2(4.2f, -5.5f));
|
||||
|
@ -54,15 +61,17 @@ public class HexCellTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestConversion() {
|
||||
HexCell cell = new();
|
||||
public void TestConversion()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
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();
|
||||
public void TestRounding()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
Debug.Assert(cell.RoundCoords(new Vector3(0.1f, 0.5f, -0.6f)) == new Vector3(0, 1, -1));
|
||||
Debug.Assert(cell.RoundCoords(new Vector3(-0.4f, -1.3f, 1.7f)) == new Vector3(-1, -1, 2));
|
||||
|
||||
|
@ -71,8 +80,9 @@ public class HexCellTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestCoords() {
|
||||
HexCell cell = new();
|
||||
public void TestCoords()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
|
||||
// from cubic positive
|
||||
cell.CubeCoords = new Vector3(2, 1, -3);
|
||||
|
@ -94,8 +104,9 @@ public class HexCellTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestNearby() {
|
||||
HexCell cell = new(new Vector2(1, 2));
|
||||
public void TestNearby()
|
||||
{
|
||||
HexCell cell = new HexCell(new Vector2(1, 2));
|
||||
|
||||
// adjacent
|
||||
HexCell otherCell = cell.GetAdjacent(HexCell.DIR_N);
|
||||
|
@ -117,8 +128,9 @@ public class HexCellTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestDistance() {
|
||||
HexCell cell = new();
|
||||
public void TestDistance()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
Debug.Assert(cell.DistanceTo(new HexCell(new Vector2(0, 0))) == 3);
|
||||
|
@ -128,71 +140,80 @@ public class HexCellTests : TestClass {
|
|||
|
||||
|
||||
[Test]
|
||||
public void TestLineTo() {
|
||||
HexCell cell = new();
|
||||
public void TestLineTo()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
HexCell[] path = cell.LineTo(new HexCell(5, 2));
|
||||
|
||||
HexCell[] pathExpected = {
|
||||
new(1, 2),
|
||||
new(2, 2),
|
||||
new(3, 2),
|
||||
new(4, 2),
|
||||
new(5, 2)
|
||||
HexCell[] pathExpected =
|
||||
{
|
||||
new HexCell(1, 2),
|
||||
new HexCell(2, 2),
|
||||
new HexCell(3, 2),
|
||||
new HexCell(4, 2),
|
||||
new HexCell(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();
|
||||
public void TestLineToAngled()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
HexCell[] path = cell.LineTo(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)
|
||||
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)
|
||||
};
|
||||
|
||||
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();
|
||||
public void TestLineEdge()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
HexCell[] path = cell.LineTo(new HexCell(3, 4));
|
||||
|
||||
HexCell[] pathExpected = {
|
||||
new(1, 2),
|
||||
new(2, 2),
|
||||
new(2, 3),
|
||||
new(2, 4),
|
||||
new(3, 4)
|
||||
HexCell[] pathExpected =
|
||||
{
|
||||
new HexCell(1, 2),
|
||||
new HexCell(2, 2),
|
||||
new HexCell(2, 3),
|
||||
new HexCell(2, 4),
|
||||
new HexCell(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);
|
||||
|
@ -200,8 +221,9 @@ public class HexCellTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestCellDirections() {
|
||||
HexCell cell = new();
|
||||
public void TestCellDirections()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
|
||||
HexCell cellN = HexCell.FromOffsetCoords(new Vector2(0, 1));
|
||||
HexCell cellNW = HexCell.FromOffsetCoords(new Vector2(-1, 0));
|
||||
|
@ -230,7 +252,8 @@ 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));
|
||||
|
@ -260,8 +283,9 @@ public class HexCellTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestNextCellAlongLine() {
|
||||
HexCell cell = new();
|
||||
public void TestNextCellAlongLine()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
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,43 +7,50 @@ using Xunit;
|
|||
|
||||
namespace GodotComponentTest.tests;
|
||||
|
||||
public class HexGridPathFindingTests : TestClass {
|
||||
public class HexGridPathFindingTests : TestClass
|
||||
{
|
||||
private HexGrid _hexGrid;
|
||||
private HexCell _hexCell;
|
||||
|
||||
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 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 Vector2[] _obstacles = {
|
||||
new(2, 1),
|
||||
new(3, 1),
|
||||
new(4, 1),
|
||||
new(1, 2),
|
||||
new(3, 2),
|
||||
new(1, 3),
|
||||
new(2, 3)
|
||||
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),
|
||||
};
|
||||
|
||||
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)));
|
||||
|
@ -56,8 +63,9 @@ public class HexGridPathFindingTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestNegativeBounds() {
|
||||
HexGrid grid = new();
|
||||
public void TestNegativeBounds()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
grid.SetBounds(new Vector2(-5, -5), new Vector2(-2, -2));
|
||||
|
||||
Assert.Equal(grid.PathCostDefault, grid.GetHexCost(new Vector2(-2, -2)));
|
||||
|
@ -68,8 +76,9 @@ public class HexGridPathFindingTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestNegativeBoundsAlt() {
|
||||
HexGrid grid = new();
|
||||
public void TestNegativeBoundsAlt()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
grid.SetBounds(new Vector2(-3, -3), new Vector2(2, 2));
|
||||
|
||||
Assert.Equal(grid.PathCostDefault, grid.GetHexCost(new Vector2(-3, -3)));
|
||||
|
@ -80,7 +89,8 @@ public class HexGridPathFindingTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestGridObstacles() {
|
||||
public void TestGridObstacles()
|
||||
{
|
||||
Assert.Equal(_obstacles.Length, _hexGrid.Obstacles.Count);
|
||||
|
||||
// Adding an obstacle
|
||||
|
@ -100,7 +110,8 @@ 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))));
|
||||
|
||||
|
@ -109,12 +120,14 @@ 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);
|
||||
|
@ -125,10 +138,12 @@ public class HexGridPathFindingTests : TestClass {
|
|||
Assert.Equal(14, _hexGrid.GetMoveCost(new Vector2(0, 0), HexCell.DIR_N));
|
||||
}
|
||||
|
||||
private void ComparePath(List<HexCell> expected, List<HexCell> path) {
|
||||
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);
|
||||
|
@ -136,8 +151,10 @@ public class HexGridPathFindingTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestStraightLine() {
|
||||
List<HexCell> expectedPath = new() {
|
||||
public void TestStraightLine()
|
||||
{
|
||||
List<HexCell> expectedPath = new List<HexCell>()
|
||||
{
|
||||
_positionA,
|
||||
new HexCell(new Vector2(3, 0)),
|
||||
new HexCell(new Vector2(4, 0)),
|
||||
|
@ -167,8 +184,10 @@ public class HexGridPathFindingTests : TestClass {
|
|||
// }
|
||||
|
||||
[Test]
|
||||
public void TestObstacle() {
|
||||
List<HexCell> expectedPath = new() {
|
||||
public void TestObstacle()
|
||||
{
|
||||
List<HexCell> expectedPath = new List<HexCell>()
|
||||
{
|
||||
_positionA,
|
||||
new HexCell(new Vector2(3, 0)),
|
||||
new HexCell(new Vector2(4, 0)),
|
||||
|
@ -181,8 +200,10 @@ public class HexGridPathFindingTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestWalls() {
|
||||
Vector3[] walls = {
|
||||
public void TestWalls()
|
||||
{
|
||||
Vector3[] walls =
|
||||
{
|
||||
HexCell.DIR_N,
|
||||
HexCell.DIR_NE,
|
||||
HexCell.DIR_SE,
|
||||
|
@ -191,11 +212,13 @@ 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> expectedPath = new List<HexCell>()
|
||||
{
|
||||
_positionA,
|
||||
new HexCell(new Vector2(1, 1)),
|
||||
new HexCell(new Vector2(0, 1)),
|
||||
|
@ -207,11 +230,13 @@ 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> expectedPath = new List<HexCell>()
|
||||
{
|
||||
_positionA,
|
||||
new HexCell(new Vector2(1, 1)),
|
||||
_positionG
|
||||
|
@ -221,17 +246,20 @@ public class HexGridPathFindingTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestRoughTerrain() {
|
||||
List<HexCell> shortPath = new() {
|
||||
public void TestRoughTerrain()
|
||||
{
|
||||
List<HexCell> shortPath = new List<HexCell>()
|
||||
{
|
||||
_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> longPath = new List<HexCell>()
|
||||
{
|
||||
_positionA,
|
||||
new HexCell(new Vector2(1, 1)),
|
||||
new HexCell(new Vector2(0, 2)),
|
||||
|
@ -240,7 +268,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,15 +1,19 @@
|
|||
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();
|
||||
public void TestGetAt()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
float w = grid.HexSize.x;
|
||||
float h = grid.HexSize.y;
|
||||
|
||||
|
@ -20,8 +24,9 @@ public class HexGridTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestGetCellsForLineSimple() {
|
||||
HexGrid grid = new();
|
||||
public void TestGetCellsForLineSimple()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
|
||||
List<HexCell> lineCells =
|
||||
grid.GetCellsForLine(new Vector2(0, 0), grid.GetHexCenterFromOffset(new Vector2(0, 2)));
|
||||
|
@ -41,8 +46,9 @@ public class HexGridTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestGetCellsDiagonal() {
|
||||
HexGrid grid = new();
|
||||
public void TestGetCellsDiagonal()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
|
||||
List<HexCell> lineCells =
|
||||
grid.GetCellsForLine(new Vector2(0, 0), grid.GetHexCenterFromOffset(new Vector2(2, 1)));
|
||||
|
@ -62,8 +68,9 @@ public class HexGridTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestGetCellsForLineAlongEdge() {
|
||||
HexGrid grid = new();
|
||||
public void TestGetCellsForLineAlongEdge()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
|
||||
List<HexCell> lineCells =
|
||||
grid.GetCellsForLine(new Vector2(0, -0.0001f), grid.GetHexCenterFromOffset(new Vector2(2, 0)));
|
||||
|
@ -83,12 +90,13 @@ public class HexGridTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void GetTestsInfiniteLoop() {
|
||||
HexGrid grid = new();
|
||||
|
||||
Vector2 fromPlane = new(-2.31678f, -5.024752f);
|
||||
Vector2 toPlane = new(-2.599937f, -6.134028f);
|
||||
|
||||
public void GetTestsInfiniteLoop()
|
||||
{
|
||||
HexGrid grid = new HexGrid();
|
||||
|
||||
Vector2 fromPlane = new Vector2(-2.31678f, -5.024752f);
|
||||
Vector2 toPlane = new Vector2(-2.599937f, -6.134028f);
|
||||
|
||||
List<HexCell> cellList = grid.GetCellsForLine(fromPlane, toPlane);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
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");
|
||||
|
@ -9,12 +10,14 @@ 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,35 +6,41 @@ using Xunit;
|
|||
|
||||
namespace GodotComponentTest.tests;
|
||||
|
||||
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);
|
||||
public class Plane2DTests : TestClass
|
||||
{
|
||||
public Plane2DTests(Node testScene) : base(testScene)
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistAngled() {
|
||||
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
public void Plane2DDistSimple()
|
||||
{
|
||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(0, -1));
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistLineSegment() {
|
||||
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
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());
|
||||
|
||||
Assert.True(
|
||||
Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(-1, 0)) - 1) < float.Epsilon);
|
||||
Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(-1, 0)) - 1) < Single.Epsilon);
|
||||
Assert.True(Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(0, 1)) - 1) <
|
||||
float.Epsilon);
|
||||
Single.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()) -
|
||||
|
@ -42,20 +48,22 @@ public class Plane2DTests : TestClass {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DTestIsParallel() {
|
||||
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
public void Plane2DTestIsParallel()
|
||||
{
|
||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
|
||||
Assert.True(plane2D.IsParallelToDir(new Vector2(1, 1.00001f).Normalized()));
|
||||
Assert.True(plane2D.IsParallelToDir(new Vector2(1, 0.99999f).Normalized()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Plane2DDistLineSegmentParallel() {
|
||||
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
public void Plane2DDistLineSegmentParallel()
|
||||
{
|
||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||
|
||||
Assert.Equal(float.PositiveInfinity,
|
||||
Assert.Equal(Single.PositiveInfinity,
|
||||
plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(1, 1.00001f).Normalized()));
|
||||
Assert.Equal(float.NegativeInfinity,
|
||||
Assert.Equal(Single.NegativeInfinity,
|
||||
plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(1, 0.99999f).Normalized()));
|
||||
}
|
||||
}
|
|
@ -1,29 +1,37 @@
|
|||
using System;
|
||||
using Godot;
|
||||
using GodotComponentTest.utils;
|
||||
using GoDotTest;
|
||||
using Xunit;
|
||||
|
||||
namespace GodotComponentTest.tests;
|
||||
|
||||
public class StreamContainerTests : TestClass {
|
||||
private readonly Node _testScene;
|
||||
public class StreamContainerTests : TestClass
|
||||
{
|
||||
private Node _testScene = null;
|
||||
private TileWorld _tileWorld;
|
||||
private StreamContainer _streamContainer;
|
||||
|
||||
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) {
|
||||
|
||||
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)
|
||||
{
|
||||
_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();
|
||||
}
|
||||
}
|
||||
|
@ -32,17 +40,20 @@ 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,26 +1,21 @@
|
|||
extends CenterContainer
|
||||
extends VBoxContainer
|
||||
|
||||
onready var SeedLineEdit: LineEdit
|
||||
onready var ChunkSizeSpinBox: SpinBox
|
||||
#onready var GameScene: PackedScene = preload ("res://scenes/Game.tscn")
|
||||
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():
|
||||
SeedLineEdit = find_node("SeedLineEdit")
|
||||
assert(SeedLineEdit)
|
||||
world_size_label = find_node("WorldSizeLabel")
|
||||
world_size_slider = find_node("WorldSizeSlider");
|
||||
|
||||
ChunkSizeSpinBox = find_node("ChunkSizeSpinBox")
|
||||
assert(ChunkSizeSpinBox)
|
||||
world_size_slider.value = 4
|
||||
|
||||
func _on_HSlider_value_changed(value):
|
||||
world_size_label.text = str(value)
|
||||
|
||||
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))
|
||||
func _on_ShowTexturesCheckButton_toggled(button_pressed):
|
||||
WorldTextureRect.visible = button_pressed
|
||||
HeightTextureRect.visible = button_pressed
|
||||
|
|
|
@ -1,128 +0,0 @@
|
|||
[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 = 61.0
|
||||
margin_right = 303.0
|
||||
margin_bottom = 339.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_top = 218.0
|
||||
margin_right = 287.0
|
||||
margin_bottom = 238.0
|
||||
size_flags_horizontal = 3
|
||||
text = "Generate"
|
||||
|
||||
[node name="Back" type="Button" parent="VBoxContainer"]
|
||||
margin_top = 258.0
|
||||
margin_right = 287.0
|
||||
margin_bottom = 278.0
|
||||
size_flags_horizontal = 3
|
||||
text = "Back"
|
||||
|
||||
[connection signal="pressed" from="VBoxContainer/GridContainer/RefreshSeedButton" to="." method="_on_RefreshSeedButton_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/GenerateButton" to="." method="_on_GenerateButton_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/Back" to="." method="_on_GenerateButton_pressed"]
|
|
@ -1,21 +0,0 @@
|
|||
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,5 +0,0 @@
|
|||
[gd_resource type="ButtonGroup" format=2]
|
||||
|
||||
[resource]
|
||||
resource_local_to_scene = false
|
||||
resource_name = "ActionButtonGroup"
|
|
@ -1,11 +0,0 @@
|
|||
[gd_resource type="Theme" load_steps=3 format=2]
|
||||
|
||||
[sub_resource type="DynamicFontData" id=3]
|
||||
font_path = "res://assets/Fonts/LuckiestGuy/LuckiestGuy-Regular.ttf"
|
||||
|
||||
[sub_resource type="DynamicFont" id=2]
|
||||
size = 18
|
||||
font_data = SubResource( 3 )
|
||||
|
||||
[resource]
|
||||
default_font = SubResource( 2 )
|
|
@ -1,63 +1,76 @@
|
|||
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));
|
||||
|
@ -68,7 +81,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));
|
||||
|
@ -78,15 +91,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,39 +5,43 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using Godot;
|
||||
|
||||
namespace Namespace;
|
||||
namespace Namespace
|
||||
{
|
||||
using UnderlyingType = UInt64;
|
||||
|
||||
using UnderlyingType = UInt64;
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
public class ExportFlagsEnumAttribute : ExportAttribute
|
||||
{
|
||||
public ExportFlagsEnumAttribute(Type enumType)
|
||||
: base(PropertyHint.Flags, GetFlagsEnumHintString(enumType))
|
||||
{ }
|
||||
|
||||
[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>());
|
||||
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;
|
||||
}
|
||||
|
||||
flag <<= 1;
|
||||
}
|
||||
|
||||
if (value == flag) {
|
||||
if (!flagNamesByFlag.TryGetValue(flag, out List<string> names)) {
|
||||
names = new List<string>();
|
||||
flagNamesByFlag.Add(flag, names);
|
||||
if (value == flag)
|
||||
{
|
||||
if (!flagNamesByFlag.TryGetValue(flag, out List<string> names))
|
||||
{
|
||||
names = new List<string>();
|
||||
flagNamesByFlag.Add(flag, names);
|
||||
}
|
||||
names.Add(name);
|
||||
}
|
||||
|
||||
names.Add(name);
|
||||
}
|
||||
return string.Join(", ", flagNamesByFlag.Values.Select(flagNames => string.Join(" / ", flagNames)));
|
||||
}
|
||||
|
||||
return string.Join(", ", flagNamesByFlag.Values.Select(flagNames => string.Join(" / ", flagNames)));
|
||||
}
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
using System;
|
||||
using Godot;
|
||||
|
||||
public class NavigationPoint {
|
||||
public class NavigationPoint
|
||||
{
|
||||
[Flags]
|
||||
public enum NavigationFlags {
|
||||
public enum NavigationFlags
|
||||
{
|
||||
Position = 1,
|
||||
Orientation = 2
|
||||
}
|
||||
|
@ -14,43 +16,52 @@ 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) {
|
||||
bool goalReached = false;
|
||||
Vector2 positionError = new Vector2(WorldPosition.x - worldTransform.origin.x,
|
||||
public bool IsReached(Transform worldTransform)
|
||||
{
|
||||
var goalReached = false;
|
||||
var positionError = new Vector2(WorldPosition.x - worldTransform.origin.x,
|
||||
WorldPosition.z - worldTransform.origin.z);
|
||||
float positionErrorSquared = positionError.LengthSquared();
|
||||
var positionErrorSquared = positionError.LengthSquared();
|
||||
worldTransform.basis.Quat();
|
||||
float orientationError = Mathf.Abs(worldTransform.basis.Quat().AngleTo(WorldOrientation));
|
||||
float angleError = Mathf.Abs(Globals.CalcPlaneAngle(worldTransform) - WorldAngle);
|
||||
var orientationError = Mathf.Abs(worldTransform.basis.Quat().AngleTo(WorldOrientation));
|
||||
var 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,39 +1,47 @@
|
|||
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) <= DistancePrecision;
|
||||
return (Mathf.Abs(normalDotDir) <= Plane2D.DistancePrecision);
|
||||
}
|
||||
|
||||
public float DistanceToLineSegment(Vector2 point, Vector2 dir) {
|
||||
public float DistanceToLineSegment(Vector2 point, Vector2 dir)
|
||||
{
|
||||
float normalDotDir = Normal.Dot(dir);
|
||||
|
||||
if (Mathf.Abs(normalDotDir) > DistancePrecision) {
|
||||
if (Mathf.Abs(normalDotDir) > Plane2D.DistancePrecision)
|
||||
{
|
||||
return (_planePoint.Dot(Normal) - point.Dot(Normal)) / normalDotDir;
|
||||
}
|
||||
|
||||
if (normalDotDir < 0) {
|
||||
return float.PositiveInfinity;
|
||||
if (normalDotDir < 0)
|
||||
{
|
||||
return Single.PositiveInfinity;
|
||||
}
|
||||
|
||||
return float.NegativeInfinity;
|
||||
return Single.NegativeInfinity;
|
||||
}
|
||||
}
|
|
@ -1,19 +1,23 @@
|
|||
// Based on: allenchou.net/2015/04/game-math-precise-control-over-numeric-springing/
|
||||
|
||||
using System.Diagnostics;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
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;
|
||||
|
@ -26,7 +30,8 @@ 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;
|
||||
|
@ -39,24 +44,27 @@ 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) {
|
||||
(Vector3, Vector3) defaultResult = Calc(x, v, xt, h);
|
||||
public (Vector3, Vector3) CalcClampedSpeed(Vector3 x, Vector3 v, Vector3 xt, float h, float speedMax)
|
||||
{
|
||||
var 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) {
|
||||
(float, float) result_x = Calc(x.x, v.x, xt.x, h);
|
||||
(float, float) result_z = Calc(x.z, v.z, xt.z, h);
|
||||
|
||||
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);
|
||||
|
||||
Vector3 x_new = x;
|
||||
Vector3 v_new = v;
|
||||
|
@ -66,23 +74,24 @@ public class SpringDamper {
|
|||
|
||||
x_new.z = result_z.Item1;
|
||||
v_new.z = result_z.Item2;
|
||||
|
||||
Vector3 result_v_xz = new(
|
||||
|
||||
Vector3 result_v_xz = new Vector3(
|
||||
(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