Compare commits
21 Commits
WorldChunk
...
main
Author | SHA1 | Date |
---|---|---|
Martin Felis | 3e251d2843 | |
Martin Felis | a74145fc57 | |
Martin Felis | 0a46a5fc10 | |
Martin Felis | 7bdda54112 | |
Martin Felis | 60000a8570 | |
Martin Felis | 29153c2d35 | |
Martin Felis | ee859886f0 | |
Martin Felis | c34c704b38 | |
Martin Felis | 4c9f6e5815 | |
Martin Felis | ce53cdba6a | |
Martin Felis | b6b11228a5 | |
Martin Felis | c2cce1ae0f | |
Martin Felis | 06b808c10d | |
Martin Felis | a5a94d1b89 | |
Martin Felis | 7d0e0b23bd | |
Martin Felis | 883e256101 | |
Martin Felis | 593c2f556b | |
Martin Felis | 453cfcde00 | |
Martin Felis | cfb731c27e | |
Martin Felis | bfd5eef2f5 | |
Martin Felis | 2109c6b6ec |
|
@ -1,8 +1,28 @@
|
||||||
.import/*
|
# Godot 4+ specific ignores
|
||||||
.mono/*
|
.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
|
||||||
.idea/*
|
.idea/*
|
||||||
android/*
|
android/*
|
||||||
|
|
||||||
|
# project specific ignores
|
||||||
|
addons/gdhexgrid/addons/gut
|
||||||
|
ass
|
||||||
|
assets/KenneySurvivalKit/Previews
|
||||||
|
|
||||||
*.swp
|
*.swp
|
||||||
*.apk
|
*.apk
|
||||||
*.idsig
|
*.idsig
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public static class Globals
|
public static class Globals {
|
||||||
{
|
|
||||||
public const float EpsPosition = 0.01f;
|
public const float EpsPosition = 0.01f;
|
||||||
public const float EpsPositionSquared = EpsPosition * EpsPosition;
|
public const float EpsPositionSquared = EpsPosition * EpsPosition;
|
||||||
public const float EpsRadians = 0.1f * Mathf.Pi / 180f;
|
public const float EpsRadians = 0.1f * Mathf.Pi / 180f;
|
||||||
public const float EpsRadiansSquared = EpsRadians * EpsRadians;
|
public const float EpsRadiansSquared = EpsRadians * EpsRadians;
|
||||||
|
|
||||||
public static float CalcPlaneAngle(Transform worldTransform)
|
public static float CalcPlaneAngle(Transform worldTransform) {
|
||||||
{
|
|
||||||
return worldTransform.basis.x.SignedAngleTo(Vector3.Right.Rotated(Vector3.Up, Mathf.Pi * 0.5f), -Vector3.Up);
|
return worldTransform.basis.x.SignedAngleTo(Vector3.Right.Rotated(Vector3.Up, Mathf.Pi * 0.5f), -Vector3.Up);
|
||||||
}
|
}
|
||||||
}
|
}
|
188
HexCell.cs
188
HexCell.cs
|
@ -3,18 +3,24 @@ using System.Linq;
|
||||||
using Godot;
|
using Godot;
|
||||||
using GodotComponentTest.utils;
|
using GodotComponentTest.utils;
|
||||||
|
|
||||||
public class HexCell : IEquatable<HexCell>
|
public class HexCell : IEquatable<HexCell> {
|
||||||
{
|
public override bool Equals(object obj) {
|
||||||
public override bool Equals(object obj)
|
if (ReferenceEquals(null, obj)) {
|
||||||
{
|
return false;
|
||||||
if (ReferenceEquals(null, obj)) return false;
|
}
|
||||||
if (ReferenceEquals(this, obj)) return true;
|
|
||||||
if (obj.GetType() != this.GetType()) return false;
|
if (ReferenceEquals(this, obj)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.GetType() != GetType()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return Equals((HexCell)obj);
|
return Equals((HexCell)obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode() {
|
||||||
{
|
|
||||||
return _cubeCoords.GetHashCode();
|
return _cubeCoords.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,8 +35,7 @@ public class HexCell : IEquatable<HexCell>
|
||||||
public static readonly Vector3 DIR_SW = new(-1, 0, 1);
|
public static readonly Vector3 DIR_SW = new(-1, 0, 1);
|
||||||
public static readonly Vector3 DIR_NW = new(-1, 1, 0);
|
public static readonly Vector3 DIR_NW = new(-1, 1, 0);
|
||||||
|
|
||||||
public static readonly Vector3[] NeighborDirections =
|
public static readonly Vector3[] NeighborDirections = {
|
||||||
{
|
|
||||||
DIR_N,
|
DIR_N,
|
||||||
DIR_NW,
|
DIR_NW,
|
||||||
DIR_SW,
|
DIR_SW,
|
||||||
|
@ -39,13 +44,13 @@ public class HexCell : IEquatable<HexCell>
|
||||||
DIR_NE
|
DIR_NE
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly Vector2 CornerNW = new Vector2(-Width / 4, -Height / 2);
|
private static readonly Vector2 CornerNW = new(-Width / 4, -Height / 2);
|
||||||
private static readonly Vector2 CornerNE = new Vector2(Width / 4, -Height / 2);
|
private static readonly Vector2 CornerNE = new(Width / 4, -Height / 2);
|
||||||
private static readonly Vector2 CornerE = new Vector2(Width / 2, 0);
|
private static readonly Vector2 CornerE = new(Width / 2, 0);
|
||||||
private static readonly Vector2 CornerSE = new Vector2(Width / 4, Height / 2);
|
private static readonly Vector2 CornerSE = new(Width / 4, Height / 2);
|
||||||
private static readonly Vector2 CornerSW = new Vector2(-Width / 4, Height / 2);
|
private static readonly Vector2 CornerSW = new(-Width / 4, Height / 2);
|
||||||
private static readonly Vector2 CornerW = new Vector2(-Width / 2, 0);
|
private static readonly Vector2 CornerW = new(-Width / 2, 0);
|
||||||
private static readonly Vector2 PlaneNormalN = new Vector2(0, 1);
|
private static readonly Vector2 PlaneNormalN = new(0, 1);
|
||||||
|
|
||||||
private static readonly Vector2 PlaneNormalNE =
|
private static readonly Vector2 PlaneNormalNE =
|
||||||
-new Vector2(Mathf.Cos(Mathf.Deg2Rad(30)), -Mathf.Sin(Mathf.Deg2Rad(30)));
|
-new Vector2(Mathf.Cos(Mathf.Deg2Rad(30)), -Mathf.Sin(Mathf.Deg2Rad(30)));
|
||||||
|
@ -53,76 +58,61 @@ public class HexCell : IEquatable<HexCell>
|
||||||
private static readonly Vector2 PlaneNormalSE =
|
private static readonly Vector2 PlaneNormalSE =
|
||||||
-new Vector2(Mathf.Cos(Mathf.Deg2Rad(-30)), -Mathf.Sin(Mathf.Deg2Rad(-30)));
|
-new Vector2(Mathf.Cos(Mathf.Deg2Rad(-30)), -Mathf.Sin(Mathf.Deg2Rad(-30)));
|
||||||
|
|
||||||
private static readonly Vector2 PlaneNormalS = new Vector2(0, -1);
|
private static readonly Vector2 PlaneNormalS = new(0, -1);
|
||||||
|
|
||||||
private static readonly Vector2 PlaneNormalSW =
|
private static readonly Vector2 PlaneNormalSW = new(Mathf.Cos(Mathf.Deg2Rad(30)), -Mathf.Sin(Mathf.Deg2Rad(30)));
|
||||||
new Vector2(Mathf.Cos(Mathf.Deg2Rad(30)), -Mathf.Sin(Mathf.Deg2Rad(30)));
|
|
||||||
|
|
||||||
private static readonly Vector2 PlaneNormalNW =
|
private static readonly Vector2 PlaneNormalNW = new(Mathf.Cos(Mathf.Deg2Rad(-30)), -Mathf.Sin(Mathf.Deg2Rad(-30)));
|
||||||
new Vector2(Mathf.Cos(Mathf.Deg2Rad(-30)), -Mathf.Sin(Mathf.Deg2Rad(-30)));
|
|
||||||
|
|
||||||
private static readonly Plane2D[] BoundaryPlanes =
|
private static readonly Plane2D[] BoundaryPlanes = {
|
||||||
{
|
new(CornerNE, PlaneNormalN),
|
||||||
new Plane2D(CornerNE, PlaneNormalN),
|
new(CornerNW, PlaneNormalNW),
|
||||||
new Plane2D(CornerNW, PlaneNormalNW),
|
new(CornerW, PlaneNormalSW),
|
||||||
new Plane2D(CornerW, PlaneNormalSW),
|
new(CornerSW, PlaneNormalS),
|
||||||
new Plane2D(CornerSW, PlaneNormalS),
|
new(CornerSE, PlaneNormalSE),
|
||||||
new Plane2D(CornerSE, PlaneNormalSE),
|
new(CornerE, PlaneNormalNE)
|
||||||
new Plane2D(CornerE, PlaneNormalNE),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public HexCell()
|
public HexCell() { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public HexCell(float cubeX, float cubeY, float cubeZ)
|
public HexCell(float cubeX, float cubeY, float cubeZ) {
|
||||||
{
|
|
||||||
CubeCoords = RoundCoords(new Vector3(cubeX, cubeY, cubeZ));
|
CubeCoords = RoundCoords(new Vector3(cubeX, cubeY, cubeZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool Equals(HexCell other)
|
public virtual bool Equals(HexCell other) {
|
||||||
{
|
if (other == null) {
|
||||||
if (other == null)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CubeCoords == other.CubeCoords;
|
return CubeCoords == other.CubeCoords;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator ==(HexCell cellA, HexCell cellB)
|
public static bool operator ==(HexCell cellA, HexCell cellB) {
|
||||||
{
|
|
||||||
return Equals(cellA, cellB);
|
return Equals(cellA, cellB);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator !=(HexCell cellA, HexCell cellB)
|
public static bool operator !=(HexCell cellA, HexCell cellB) {
|
||||||
{
|
|
||||||
return !(cellA == cellB);
|
return !(cellA == cellB);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HexCell(Vector3 cubeCoords)
|
public HexCell(Vector3 cubeCoords) {
|
||||||
{
|
|
||||||
CubeCoords = cubeCoords;
|
CubeCoords = cubeCoords;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HexCell(float axialX, float axialY)
|
public HexCell(float axialX, float axialY) {
|
||||||
{
|
|
||||||
AxialCoords = new Vector2(axialX, axialY);
|
AxialCoords = new Vector2(axialX, axialY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HexCell(Vector2 axialCoords)
|
public HexCell(Vector2 axialCoords) {
|
||||||
{
|
|
||||||
AxialCoords = axialCoords;
|
AxialCoords = axialCoords;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HexCell(HexCell other)
|
public HexCell(HexCell other) {
|
||||||
{
|
|
||||||
CubeCoords = other.CubeCoords;
|
CubeCoords = other.CubeCoords;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HexCell FromOffsetCoords(Vector2 offsetCoords)
|
public static HexCell FromOffsetCoords(Vector2 offsetCoords) {
|
||||||
{
|
HexCell result = new();
|
||||||
HexCell result = new HexCell();
|
|
||||||
result.OffsetCoords = offsetCoords;
|
result.OffsetCoords = offsetCoords;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -130,13 +120,10 @@ public class HexCell : IEquatable<HexCell>
|
||||||
|
|
||||||
private Vector3 _cubeCoords;
|
private Vector3 _cubeCoords;
|
||||||
|
|
||||||
public Vector3 CubeCoords
|
public Vector3 CubeCoords {
|
||||||
{
|
get => _cubeCoords;
|
||||||
get { return _cubeCoords; }
|
set {
|
||||||
set
|
if (Mathf.Abs(value.x + value.y + value.z) > 0.0001) {
|
||||||
{
|
|
||||||
if (Mathf.Abs(value.x + value.y + value.z) > 0.0001)
|
|
||||||
{
|
|
||||||
GD.Print("Warning: Invalid cube coordinates for hex (x + y + z != 0): ", value.ToString());
|
GD.Print("Warning: Invalid cube coordinates for hex (x + y + z != 0): ", value.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,25 +131,21 @@ public class HexCell : IEquatable<HexCell>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 AxialCoords
|
public Vector2 AxialCoords {
|
||||||
{
|
get => new(CubeCoords.x, CubeCoords.y);
|
||||||
get => new Vector2(CubeCoords.x, CubeCoords.y);
|
|
||||||
|
|
||||||
set { CubeCoords = AxialToCubeCoords(value); }
|
set => CubeCoords = AxialToCubeCoords(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 OffsetCoords
|
public Vector2 OffsetCoords {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
int x = (int)CubeCoords.x;
|
int x = (int)CubeCoords.x;
|
||||||
int y = (int)CubeCoords.y;
|
int y = (int)CubeCoords.y;
|
||||||
int offY = y + (x - (x & 1)) / 2;
|
int offY = y + (x - (x & 1)) / 2;
|
||||||
return new Vector2(x, offY);
|
return new Vector2(x, offY);
|
||||||
}
|
}
|
||||||
|
|
||||||
set
|
set {
|
||||||
{
|
|
||||||
int x = (int)value.x;
|
int x = (int)value.x;
|
||||||
int y = (int)value.y;
|
int y = (int)value.y;
|
||||||
int cubeY = y - (x - (x & 1)) / 2;
|
int cubeY = y - (x - (x & 1)) / 2;
|
||||||
|
@ -170,51 +153,40 @@ public class HexCell : IEquatable<HexCell>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 AxialToCubeCoords(Vector2 axialCoords)
|
public Vector3 AxialToCubeCoords(Vector2 axialCoords) {
|
||||||
{
|
|
||||||
return new Vector3(axialCoords.x, axialCoords.y, -axialCoords.x - axialCoords.y);
|
return new Vector3(axialCoords.x, axialCoords.y, -axialCoords.x - axialCoords.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 RoundCoords(Vector2 coords)
|
public Vector3 RoundCoords(Vector2 coords) {
|
||||||
{
|
|
||||||
Vector3 cubeCoords = AxialToCubeCoords(coords);
|
Vector3 cubeCoords = AxialToCubeCoords(coords);
|
||||||
|
|
||||||
return RoundCoords(cubeCoords);
|
return RoundCoords(cubeCoords);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 RoundCoords(Vector3 cubeCoords)
|
public Vector3 RoundCoords(Vector3 cubeCoords) {
|
||||||
{
|
Vector3 rounded = new(
|
||||||
Vector3 rounded = new Vector3(
|
|
||||||
Mathf.Round(cubeCoords.x),
|
Mathf.Round(cubeCoords.x),
|
||||||
Mathf.Round(cubeCoords.y),
|
Mathf.Round(cubeCoords.y),
|
||||||
Mathf.Round(cubeCoords.z));
|
Mathf.Round(cubeCoords.z));
|
||||||
|
|
||||||
Vector3 diffs = (rounded - cubeCoords).Abs();
|
Vector3 diffs = (rounded - cubeCoords).Abs();
|
||||||
if (diffs.x > diffs.y && diffs.x > diffs.z)
|
if (diffs.x > diffs.y && diffs.x > diffs.z) {
|
||||||
{
|
|
||||||
rounded.x = -rounded.y - rounded.z;
|
rounded.x = -rounded.y - rounded.z;
|
||||||
}
|
} else if (diffs.y > diffs.z) {
|
||||||
else if (diffs.y > diffs.z)
|
|
||||||
{
|
|
||||||
rounded.y = -rounded.x - rounded.z;
|
rounded.y = -rounded.x - rounded.z;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
rounded.z = -rounded.x - rounded.y;
|
rounded.z = -rounded.x - rounded.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rounded;
|
return rounded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HexCell GetAdjacent(Vector3 dir)
|
public HexCell GetAdjacent(Vector3 dir) {
|
||||||
{
|
return new HexCell(CubeCoords + dir);
|
||||||
return new HexCell(this.CubeCoords + dir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public HexCell[] GetAllAdjacent()
|
public HexCell[] GetAllAdjacent() {
|
||||||
{
|
return new[] {
|
||||||
return new[]
|
|
||||||
{
|
|
||||||
GetAdjacent(DIR_NE),
|
GetAdjacent(DIR_NE),
|
||||||
GetAdjacent(DIR_SE),
|
GetAdjacent(DIR_SE),
|
||||||
GetAdjacent(DIR_S),
|
GetAdjacent(DIR_S),
|
||||||
|
@ -224,8 +196,7 @@ public class HexCell : IEquatable<HexCell>
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public int DistanceTo(HexCell target)
|
public int DistanceTo(HexCell target) {
|
||||||
{
|
|
||||||
return (int)(
|
return (int)(
|
||||||
Mathf.Abs(_cubeCoords.x - target.CubeCoords.x)
|
Mathf.Abs(_cubeCoords.x - target.CubeCoords.x)
|
||||||
+ Mathf.Abs(_cubeCoords.y - target.CubeCoords.y)
|
+ Mathf.Abs(_cubeCoords.y - target.CubeCoords.y)
|
||||||
|
@ -233,16 +204,14 @@ public class HexCell : IEquatable<HexCell>
|
||||||
) / 2;
|
) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HexCell[] LineTo(HexCell target)
|
public HexCell[] LineTo(HexCell target) {
|
||||||
{
|
HexCell nudgedTarget = new();
|
||||||
HexCell nudgedTarget = new HexCell();
|
|
||||||
nudgedTarget.CubeCoords = target.CubeCoords + new Vector3(1.0e-6f, 2.0e-6f, -3.0e-6f);
|
nudgedTarget.CubeCoords = target.CubeCoords + new Vector3(1.0e-6f, 2.0e-6f, -3.0e-6f);
|
||||||
int steps = DistanceTo(target);
|
int steps = DistanceTo(target);
|
||||||
|
|
||||||
HexCell[] path = new HexCell[steps + 1];
|
HexCell[] path = new HexCell[steps + 1];
|
||||||
|
|
||||||
foreach (int dist in Enumerable.Range(0, steps))
|
foreach (int dist in Enumerable.Range(0, steps)) {
|
||||||
{
|
|
||||||
path[dist] = new HexCell();
|
path[dist] = new HexCell();
|
||||||
path[dist].CubeCoords = CubeCoords.LinearInterpolate(nudgedTarget.CubeCoords, (float)dist / steps);
|
path[dist].CubeCoords = CubeCoords.LinearInterpolate(nudgedTarget.CubeCoords, (float)dist / steps);
|
||||||
}
|
}
|
||||||
|
@ -252,28 +221,23 @@ public class HexCell : IEquatable<HexCell>
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void QueryClosestCellBoundary(Vector2 pointLocal, Vector2 dir, out int neighbourIndex, out float distance)
|
public void QueryClosestCellBoundary(Vector2 pointLocal, Vector2 dir, out int neighbourIndex, out float distance) {
|
||||||
{
|
distance = float.PositiveInfinity;
|
||||||
distance = Single.PositiveInfinity;
|
|
||||||
neighbourIndex = 0;
|
neighbourIndex = 0;
|
||||||
foreach (int i in Enumerable.Range(0, 6))
|
foreach (int i in Enumerable.Range(0, 6)) {
|
||||||
{
|
if (BoundaryPlanes[i].Normal.Dot(dir) >= Plane2D.DistancePrecision) {
|
||||||
if (BoundaryPlanes[i].Normal.Dot(dir) >= Plane2D.DistancePrecision)
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float planeDistance = BoundaryPlanes[i].DistanceToLineSegment(pointLocal, dir);
|
float planeDistance = BoundaryPlanes[i].DistanceToLineSegment(pointLocal, dir);
|
||||||
if (planeDistance > Single.NegativeInfinity && planeDistance < distance)
|
if (planeDistance > float.NegativeInfinity && planeDistance < distance) {
|
||||||
{
|
|
||||||
distance = planeDistance;
|
distance = planeDistance;
|
||||||
neighbourIndex = i;
|
neighbourIndex = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public HexCell NextCellAlongLine(Vector2 pointLocal, Vector2 dir)
|
public HexCell NextCellAlongLine(Vector2 pointLocal, Vector2 dir) {
|
||||||
{
|
|
||||||
int planeIndex;
|
int planeIndex;
|
||||||
|
|
||||||
QueryClosestCellBoundary(pointLocal, dir, out planeIndex, out _);
|
QueryClosestCellBoundary(pointLocal, dir, out planeIndex, out _);
|
||||||
|
|
205
HexGrid.cs
205
HexGrid.cs
|
@ -4,8 +4,7 @@ using Godot;
|
||||||
using Priority_Queue;
|
using Priority_Queue;
|
||||||
using AxialCoordDirectionPair = System.Tuple<Godot.Vector2, Godot.Vector3>;
|
using AxialCoordDirectionPair = System.Tuple<Godot.Vector2, Godot.Vector3>;
|
||||||
|
|
||||||
public class HexGrid : Resource
|
public class HexGrid : Resource {
|
||||||
{
|
|
||||||
private readonly Vector2 _baseHexSize = new(1, Mathf.Sqrt(3) / 2);
|
private readonly Vector2 _baseHexSize = new(1, Mathf.Sqrt(3) / 2);
|
||||||
private Rect2 _boundsAxialCoords = new(-Vector2.Inf, Vector2.Inf);
|
private Rect2 _boundsAxialCoords = new(-Vector2.Inf, Vector2.Inf);
|
||||||
private Rect2 _boundsOffsetCoords = new(-Vector2.Inf, Vector2.Inf);
|
private Rect2 _boundsOffsetCoords = new(-Vector2.Inf, Vector2.Inf);
|
||||||
|
@ -24,18 +23,15 @@ public class HexGrid : Resource
|
||||||
|
|
||||||
public float PathCostDefault = 1;
|
public float PathCostDefault = 1;
|
||||||
|
|
||||||
public HexGrid()
|
public HexGrid() {
|
||||||
{
|
|
||||||
HexScale = new Vector2(1, 1);
|
HexScale = new Vector2(1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 HexSize => _hexSize;
|
public Vector2 HexSize => _hexSize;
|
||||||
|
|
||||||
public Vector2 HexScale
|
public Vector2 HexScale {
|
||||||
{
|
|
||||||
get => _hexScale;
|
get => _hexScale;
|
||||||
set
|
set {
|
||||||
{
|
|
||||||
_hexScale = value;
|
_hexScale = value;
|
||||||
_hexSize = _baseHexSize * _hexScale;
|
_hexSize = _baseHexSize * _hexScale;
|
||||||
_hexTransform = new Transform2D(
|
_hexTransform = new Transform2D(
|
||||||
|
@ -48,135 +44,129 @@ public class HexGrid : Resource
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 GetHexCenter(HexCell cell)
|
public Vector2 GetHexCenter(HexCell cell) {
|
||||||
{
|
|
||||||
return _hexTransform * cell.AxialCoords;
|
return _hexTransform * cell.AxialCoords;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 GetHexCenterFromOffset(Vector2 offsetCoord)
|
public Vector2 GetHexCenterFromOffset(Vector2 offsetCoord) {
|
||||||
{
|
HexCell cell = new HexCell();
|
||||||
var cell = new HexCell();
|
|
||||||
cell.OffsetCoords = offsetCoord;
|
cell.OffsetCoords = offsetCoord;
|
||||||
return GetHexCenter(cell);
|
return GetHexCenter(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 GetHexCenterVec3FromOffset(Vector2 offsetCoord)
|
public Vector3 GetHexCenterVec3FromOffset(Vector2 offsetCoord) {
|
||||||
{
|
HexCell cell = new HexCell();
|
||||||
var cell = new HexCell();
|
|
||||||
cell.OffsetCoords = offsetCoord;
|
cell.OffsetCoords = offsetCoord;
|
||||||
var hexCenter = GetHexCenter(cell);
|
Vector2 hexCenter = GetHexCenter(cell);
|
||||||
return new Vector3(hexCenter.x, 0, hexCenter.y);
|
return new Vector3(hexCenter.x, 0, hexCenter.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HexCell GetHexAtOffset(Vector2 offsetCoord)
|
public HexCell GetHexAtOffset(Vector2 offsetCoord) {
|
||||||
{
|
HexCell cell = new HexCell();
|
||||||
var cell = new HexCell();
|
|
||||||
cell.OffsetCoords = offsetCoord;
|
cell.OffsetCoords = offsetCoord;
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HexCell GetHexAt(Vector2 planeCoord)
|
public HexCell GetHexAt(Vector2 planeCoord) {
|
||||||
{
|
HexCell result = new HexCell(_hexTransformInv * planeCoord);
|
||||||
var result = new HexCell(_hexTransformInv * planeCoord);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetBounds(Vector2 minAxial, Vector2 maxAxial)
|
public void SetBounds(Vector2 minAxial, Vector2 maxAxial) {
|
||||||
{
|
|
||||||
SetBounds(new HexCell(minAxial), new HexCell(maxAxial));
|
SetBounds(new HexCell(minAxial), new HexCell(maxAxial));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetBounds(HexCell minCell, HexCell maxCell)
|
public void SetBounds(HexCell minCell, HexCell maxCell) {
|
||||||
{
|
|
||||||
_minCoords = minCell;
|
_minCoords = minCell;
|
||||||
_maxCoords = maxCell;
|
_maxCoords = maxCell;
|
||||||
_boundsAxialCoords = new Rect2(_minCoords.AxialCoords,
|
_boundsAxialCoords = new Rect2(_minCoords.AxialCoords,
|
||||||
_maxCoords.AxialCoords - _minCoords.AxialCoords + Vector2.One);
|
_maxCoords.AxialCoords - _minCoords.AxialCoords + Vector2.One);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetBounds(HexCell center, int size)
|
public void SetBounds(HexCell center, int size) {
|
||||||
{
|
Vector2 centerOffset = center.OffsetCoords;
|
||||||
var centerOffset = center.OffsetCoords;
|
|
||||||
SetBounds(GetHexAtOffset(centerOffset - Vector2.One * size / 2),
|
SetBounds(GetHexAtOffset(centerOffset - Vector2.One * size / 2),
|
||||||
GetHexAtOffset(centerOffset + Vector2.One * size / 2));
|
GetHexAtOffset(centerOffset + Vector2.One * size / 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetBoundsOffset(HexCell cellSouthEast, Vector2 size)
|
public void SetBoundsOffset(HexCell cellSouthEast, Vector2 size) {
|
||||||
{
|
|
||||||
_boundsOffsetCoords = new Rect2(cellSouthEast.OffsetCoords, size);
|
_boundsOffsetCoords = new Rect2(cellSouthEast.OffsetCoords, size);
|
||||||
_boundsAxialCoords = new Rect2(-Vector2.Inf, Vector2.Inf);
|
_boundsAxialCoords = new Rect2(-Vector2.Inf, Vector2.Inf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddObstacle(Vector2 axialCoords, float cost = 0)
|
public void AddObstacle(Vector2 axialCoords, float cost = 0) {
|
||||||
{
|
|
||||||
AddObstacle(new HexCell(axialCoords), cost);
|
AddObstacle(new HexCell(axialCoords), cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddObstacle(HexCell cell, float cost = 0)
|
public void AddObstacle(HexCell cell, float cost = 0) {
|
||||||
{
|
|
||||||
Obstacles[cell.AxialCoords] = cost;
|
Obstacles[cell.AxialCoords] = cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveObstacle(HexCell cell)
|
public void RemoveObstacle(HexCell cell) {
|
||||||
{
|
|
||||||
Obstacles.Remove(cell.AxialCoords);
|
Obstacles.Remove(cell.AxialCoords);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void AddBarrier(Vector2 axialCoords, Vector3 directionCube, float cost = 0)
|
public void AddBarrier(Vector2 axialCoords, Vector3 directionCube, float cost = 0) {
|
||||||
{
|
|
||||||
AddBarrier(new HexCell(axialCoords), directionCube, cost);
|
AddBarrier(new HexCell(axialCoords), directionCube, cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddBarrier(HexCell cell, Vector3 directionCube, float cost = 0)
|
public void AddBarrier(HexCell cell, Vector3 directionCube, float cost = 0) {
|
||||||
{
|
|
||||||
Barriers.Add((cell.AxialCoords, directionCube), cost);
|
Barriers.Add((cell.AxialCoords, directionCube), cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveBarrier(HexCell cell, Vector3 directionCube)
|
public void RemoveBarrier(HexCell cell, Vector3 directionCube) {
|
||||||
{
|
if (Barriers.ContainsKey((cell.AxialCoords, directionCube))) {
|
||||||
if (Barriers.ContainsKey((cell.AxialCoords, directionCube))) Barriers.Remove((cell.AxialCoords, directionCube));
|
Barriers.Remove((cell.AxialCoords, directionCube));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetHexCost(HexCell cell)
|
public float GetHexCost(HexCell cell) {
|
||||||
{
|
|
||||||
return GetHexCost(cell.AxialCoords);
|
return GetHexCost(cell.AxialCoords);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetHexCost(Vector2 axialCoords)
|
public float GetHexCost(Vector2 axialCoords) {
|
||||||
{
|
if (!_boundsAxialCoords.HasPoint(axialCoords)) {
|
||||||
if (!_boundsAxialCoords.HasPoint(axialCoords)) return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!_boundsOffsetCoords.HasPoint(new HexCell(axialCoords).OffsetCoords)) return 0;
|
if (!_boundsOffsetCoords.HasPoint(new HexCell(axialCoords).OffsetCoords)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
float value;
|
float value;
|
||||||
return Obstacles.TryGetValue(axialCoords, out value) ? value : PathCostDefault;
|
return Obstacles.TryGetValue(axialCoords, out value) ? value : PathCostDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetMoveCost(Vector2 axialCoords, Vector3 directionCube)
|
public float GetMoveCost(Vector2 axialCoords, Vector3 directionCube) {
|
||||||
{
|
HexCell startCell = new HexCell(axialCoords);
|
||||||
var startCell = new HexCell(axialCoords);
|
HexCell targetCell = new HexCell(startCell.CubeCoords + directionCube);
|
||||||
var targetCell = new HexCell(startCell.CubeCoords + directionCube);
|
|
||||||
|
|
||||||
var cost = GetHexCost(axialCoords);
|
float cost = GetHexCost(axialCoords);
|
||||||
if (cost == 0) return 0;
|
if (cost == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
cost = GetHexCost(targetCell.AxialCoords);
|
cost = GetHexCost(targetCell.AxialCoords);
|
||||||
if (cost == 0) return 0;
|
if (cost == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
float barrierCost;
|
float barrierCost;
|
||||||
if (Barriers.ContainsKey((axialCoords, directionCube)))
|
if (Barriers.ContainsKey((axialCoords, directionCube))) {
|
||||||
{
|
|
||||||
barrierCost = Barriers[(axialCoords, directionCube)];
|
barrierCost = Barriers[(axialCoords, directionCube)];
|
||||||
if (barrierCost == 0) return 0;
|
if (barrierCost == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
cost += barrierCost;
|
cost += barrierCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Barriers.ContainsKey((targetCell.AxialCoords, -directionCube)))
|
if (Barriers.ContainsKey((targetCell.AxialCoords, -directionCube))) {
|
||||||
{
|
|
||||||
barrierCost = Barriers[(targetCell.AxialCoords, -directionCube)];
|
barrierCost = Barriers[(targetCell.AxialCoords, -directionCube)];
|
||||||
if (barrierCost == 0) return 0;
|
if (barrierCost == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
cost += barrierCost;
|
cost += barrierCost;
|
||||||
}
|
}
|
||||||
|
@ -185,32 +175,29 @@ public class HexGrid : Resource
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public HexCell GetClosestWalkableCell(HexCell fromCell, HexCell toCell)
|
public HexCell GetClosestWalkableCell(HexCell fromCell, HexCell toCell) {
|
||||||
{
|
if (GetHexCost(toCell) == 0) {
|
||||||
if (GetHexCost(toCell) == 0)
|
HexCell[] line = fromCell.LineTo(toCell);
|
||||||
{
|
|
||||||
var line = fromCell.LineTo(toCell);
|
|
||||||
|
|
||||||
foreach (var i in Enumerable.Range(1, line.Length))
|
foreach (int i in Enumerable.Range(1, line.Length)) {
|
||||||
if (GetHexCost(line[i]) == 0)
|
if (GetHexCost(line[i]) == 0) {
|
||||||
{
|
|
||||||
toCell = line[i - 1];
|
toCell = line[i - 1];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return toCell;
|
return toCell;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<HexCell> FindPath(HexCell startHex, HexCell goalHex)
|
public List<HexCell> FindPath(HexCell startHex, HexCell goalHex) {
|
||||||
{
|
Vector2 goalAxialCoords = goalHex.AxialCoords;
|
||||||
var goalAxialCoords = goalHex.AxialCoords;
|
|
||||||
|
|
||||||
var frontier = new SimplePriorityQueue<Vector2, float>();
|
SimplePriorityQueue<Vector2, float> frontier = new SimplePriorityQueue<Vector2, float>();
|
||||||
frontier.Enqueue(startHex.AxialCoords, 0);
|
frontier.Enqueue(startHex.AxialCoords, 0);
|
||||||
var cameFrom =
|
Dictionary<Vector2, Vector2> cameFrom =
|
||||||
new Dictionary<Vector2, Vector2>();
|
new Dictionary<Vector2, Vector2>();
|
||||||
var costSoFar =
|
Dictionary<Vector2, float> costSoFar =
|
||||||
new Dictionary<Vector2, float>();
|
new Dictionary<Vector2, float>();
|
||||||
|
|
||||||
cameFrom.Add(startHex.AxialCoords, startHex.AxialCoords);
|
cameFrom.Add(startHex.AxialCoords, startHex.AxialCoords);
|
||||||
|
@ -218,34 +205,34 @@ public class HexGrid : Resource
|
||||||
|
|
||||||
FindPathCheckedCellCount = 0;
|
FindPathCheckedCellCount = 0;
|
||||||
|
|
||||||
while (frontier.Any())
|
while (frontier.Any()) {
|
||||||
{
|
|
||||||
FindPathCheckedCellCount++;
|
FindPathCheckedCellCount++;
|
||||||
var currentHex = new HexCell(frontier.Dequeue());
|
HexCell currentHex = new HexCell(frontier.Dequeue());
|
||||||
var currentAxial = currentHex.AxialCoords;
|
Vector2 currentAxial = currentHex.AxialCoords;
|
||||||
|
|
||||||
if (currentHex == goalHex) break;
|
if (currentHex == goalHex) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var nextHex in currentHex.GetAllAdjacent())
|
foreach (HexCell nextHex in currentHex.GetAllAdjacent()) {
|
||||||
{
|
Vector2 nextAxial = nextHex.AxialCoords;
|
||||||
var nextAxial = nextHex.AxialCoords;
|
float nextCost = GetMoveCost(currentAxial, new HexCell(nextAxial - currentHex.AxialCoords).CubeCoords);
|
||||||
var nextCost = GetMoveCost(currentAxial, new HexCell(nextAxial - currentHex.AxialCoords).CubeCoords);
|
|
||||||
|
|
||||||
if (nextHex == goalHex && GetHexCost(nextAxial) == 0)
|
if (nextHex == goalHex && GetHexCost(nextAxial) == 0) {
|
||||||
{
|
|
||||||
// Goal ist an obstacle
|
// Goal ist an obstacle
|
||||||
cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
|
cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
|
||||||
frontier.Clear();
|
frontier.Clear();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextCost == 0) continue;
|
if (nextCost == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
nextCost += costSoFar[currentHex.AxialCoords];
|
nextCost += costSoFar[currentHex.AxialCoords];
|
||||||
if (!costSoFar.ContainsKey(nextHex.AxialCoords) || nextCost < costSoFar[nextHex.AxialCoords])
|
if (!costSoFar.ContainsKey(nextHex.AxialCoords) || nextCost < costSoFar[nextHex.AxialCoords]) {
|
||||||
{
|
|
||||||
costSoFar[nextHex.AxialCoords] = nextCost;
|
costSoFar[nextHex.AxialCoords] = nextCost;
|
||||||
var priority = nextCost + nextHex.DistanceTo(goalHex);
|
float priority = nextCost + nextHex.DistanceTo(goalHex);
|
||||||
|
|
||||||
frontier.Enqueue(nextHex.AxialCoords, priority);
|
frontier.Enqueue(nextHex.AxialCoords, priority);
|
||||||
cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
|
cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
|
||||||
|
@ -255,18 +242,18 @@ public class HexGrid : Resource
|
||||||
|
|
||||||
// GD.Print("Checked Cell Count: " + FindPathCheckedCellCount);
|
// GD.Print("Checked Cell Count: " + FindPathCheckedCellCount);
|
||||||
|
|
||||||
var result = new List<HexCell>();
|
List<HexCell> result = new List<HexCell>();
|
||||||
if (!cameFrom.ContainsKey(goalHex.AxialCoords))
|
if (!cameFrom.ContainsKey(goalHex.AxialCoords)) {
|
||||||
{
|
|
||||||
GD.Print("Failed to find path from " + startHex + " to " + goalHex);
|
GD.Print("Failed to find path from " + startHex + " to " + goalHex);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetHexCost(goalAxialCoords) != 0) result.Add(goalHex);
|
if (GetHexCost(goalAxialCoords) != 0) {
|
||||||
|
result.Add(goalHex);
|
||||||
|
}
|
||||||
|
|
||||||
var pathHex = goalHex;
|
HexCell pathHex = goalHex;
|
||||||
while (pathHex != startHex)
|
while (pathHex != startHex) {
|
||||||
{
|
|
||||||
pathHex = new HexCell(cameFrom[pathHex.AxialCoords]);
|
pathHex = new HexCell(cameFrom[pathHex.AxialCoords]);
|
||||||
result.Insert(0, pathHex);
|
result.Insert(0, pathHex);
|
||||||
}
|
}
|
||||||
|
@ -275,22 +262,20 @@ public class HexGrid : Resource
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<HexCell> GetCellsForLine(Vector2 fromPlane, Vector2 toPlane)
|
public List<HexCell> GetCellsForLine(Vector2 fromPlane, Vector2 toPlane) {
|
||||||
{
|
List<HexCell> result = new List<HexCell>();
|
||||||
var result = new List<HexCell>();
|
|
||||||
|
|
||||||
var distance = (toPlane - fromPlane).Length();
|
float distance = (toPlane - fromPlane).Length();
|
||||||
var direction = (toPlane - fromPlane) / distance;
|
Vector2 direction = (toPlane - fromPlane) / distance;
|
||||||
|
|
||||||
var currentPointPlane = fromPlane;
|
Vector2 currentPointPlane = fromPlane;
|
||||||
var currentCell = GetHexAt(currentPointPlane);
|
HexCell currentCell = GetHexAt(currentPointPlane);
|
||||||
float currentDistance = 0;
|
float currentDistance = 0;
|
||||||
|
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
result.Add(currentCell);
|
result.Add(currentCell);
|
||||||
GetHexCenter(currentCell);
|
GetHexCenter(currentCell);
|
||||||
var currentPointLocal = currentPointPlane - GetHexCenter(currentCell);
|
Vector2 currentPointLocal = currentPointPlane - GetHexCenter(currentCell);
|
||||||
|
|
||||||
int neighbourIndex;
|
int neighbourIndex;
|
||||||
float boundaryPlaneDistance;
|
float boundaryPlaneDistance;
|
||||||
|
|
|
@ -21,7 +21,7 @@ compress/lossy_quality=0.7
|
||||||
compress/hdr_mode=0
|
compress/hdr_mode=0
|
||||||
compress/bptc_ldr=0
|
compress/bptc_ldr=0
|
||||||
compress/normal_map=0
|
compress/normal_map=0
|
||||||
flags/repeat=true
|
flags/repeat=1
|
||||||
flags/filter=false
|
flags/filter=false
|
||||||
flags/mipmaps=true
|
flags/mipmaps=true
|
||||||
flags/anisotropic=false
|
flags/anisotropic=false
|
||||||
|
|
|
@ -19,7 +19,7 @@ compress/lossy_quality=0.7
|
||||||
compress/hdr_mode=0
|
compress/hdr_mode=0
|
||||||
compress/bptc_ldr=0
|
compress/bptc_ldr=0
|
||||||
compress/normal_map=2
|
compress/normal_map=2
|
||||||
flags/repeat=true
|
flags/repeat=0
|
||||||
flags/filter=false
|
flags/filter=false
|
||||||
flags/mipmaps=true
|
flags/mipmaps=true
|
||||||
flags/anisotropic=false
|
flags/anisotropic=false
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,50 @@
|
||||||
|
[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.
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
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,28 +2,30 @@
|
||||||
|
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="StreamTexture"
|
type="StreamTexture"
|
||||||
path="res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.stex"
|
path.s3tc="res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.s3tc.stex"
|
||||||
|
path.etc2="res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.etc2.stex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"imported_formats": [ "s3tc", "etc2" ],
|
||||||
|
"vram_texture": true
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://assets/IslandMasks/IslandMask2.png"
|
source_file="res://assets/IslandMasks/IslandMask2.png"
|
||||||
dest_files=[ "res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.stex" ]
|
dest_files=[ "res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.s3tc.stex", "res://.import/IslandMask2.png-b09deb1a0f8633d5ff352ae53948f6ed.etc2.stex" ]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
compress/mode=0
|
compress/mode=2
|
||||||
compress/lossy_quality=0.7
|
compress/lossy_quality=0.7
|
||||||
compress/hdr_mode=0
|
compress/hdr_mode=0
|
||||||
compress/bptc_ldr=0
|
compress/bptc_ldr=0
|
||||||
compress/normal_map=0
|
compress/normal_map=0
|
||||||
flags/repeat=0
|
flags/repeat=true
|
||||||
flags/filter=true
|
flags/filter=true
|
||||||
flags/mipmaps=false
|
flags/mipmaps=true
|
||||||
flags/anisotropic=false
|
flags/anisotropic=false
|
||||||
flags/srgb=2
|
flags/srgb=1
|
||||||
process/fix_alpha_border=true
|
process/fix_alpha_border=true
|
||||||
process/premult_alpha=false
|
process/premult_alpha=false
|
||||||
process/HDR_as_SRGB=false
|
process/HDR_as_SRGB=false
|
||||||
|
@ -31,5 +33,5 @@ process/invert_color=false
|
||||||
process/normal_map_invert_y=false
|
process/normal_map_invert_y=false
|
||||||
stream=false
|
stream=false
|
||||||
size_limit=0
|
size_limit=0
|
||||||
detect_3d=true
|
detect_3d=false
|
||||||
svg/scale=1.0
|
svg/scale=1.0
|
||||||
|
|
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -2,8 +2,7 @@ using System;
|
||||||
using Godot;
|
using Godot;
|
||||||
using GoDotLog;
|
using GoDotLog;
|
||||||
|
|
||||||
public class ClickableComponent : Spatial
|
public class ClickableComponent : Spatial {
|
||||||
{
|
|
||||||
[Export] public string ClickName = "ClickName";
|
[Export] public string ClickName = "ClickName";
|
||||||
|
|
||||||
[Signal]
|
[Signal]
|
||||||
|
@ -15,11 +14,9 @@ public class ClickableComponent : Spatial
|
||||||
private CollisionObject _collisionObject;
|
private CollisionObject _collisionObject;
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
_collisionObject = (CollisionObject)FindNode("Area", false);
|
_collisionObject = (CollisionObject)FindNode("Area", false);
|
||||||
if (_collisionObject == null)
|
if (_collisionObject == null) {
|
||||||
{
|
|
||||||
GD.PrintErr("Error: could not find Area for Clickable Component!");
|
GD.PrintErr("Error: could not find Area for Clickable Component!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -30,26 +27,21 @@ public class ClickableComponent : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||||
int shapeIndex)
|
int shapeIndex) {
|
||||||
{
|
if (IsMouseOver && inputEvent is InputEventMouseButton) {
|
||||||
if (IsMouseOver && inputEvent is InputEventMouseButton)
|
|
||||||
{
|
|
||||||
InputEventMouseButton mouseButtonEvent = (InputEventMouseButton)inputEvent;
|
InputEventMouseButton mouseButtonEvent = (InputEventMouseButton)inputEvent;
|
||||||
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed)
|
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed) {
|
||||||
{
|
|
||||||
GD.Print("Clicked on Clickable Component!");
|
GD.Print("Clicked on Clickable Component!");
|
||||||
EmitSignal("Clicked", this);
|
EmitSignal("Clicked", this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnAreaMouseEntered()
|
public void OnAreaMouseEntered() {
|
||||||
{
|
|
||||||
IsMouseOver = true;
|
IsMouseOver = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnAreaMouseExited()
|
public void OnAreaMouseExited() {
|
||||||
{
|
|
||||||
IsMouseOver = false;
|
IsMouseOver = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
[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,6 +1,3 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public class Component : Node
|
public class Component : Node { }
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -2,8 +2,7 @@ using Godot;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GroundMotionComponent : Component
|
public class GroundMotionComponent : Component {
|
||||||
{
|
|
||||||
public float Accel = 50;
|
public float Accel = 50;
|
||||||
public float Damping = 0.2f;
|
public float Damping = 0.2f;
|
||||||
public Vector3 DirectionToTarget = Vector3.Zero;
|
public Vector3 DirectionToTarget = Vector3.Zero;
|
||||||
|
@ -14,29 +13,21 @@ public class GroundMotionComponent : Component
|
||||||
public float TargetAngle;
|
public float TargetAngle;
|
||||||
public float TargetDeltaAngle;
|
public float TargetDeltaAngle;
|
||||||
|
|
||||||
private void CalcAndApplyOrientation(float delta, Entity entity, Vector3 targetPosition, float targetAngle)
|
private void CalcAndApplyOrientation(float delta, Entity entity, Vector3 targetPosition, float targetAngle) {
|
||||||
{
|
|
||||||
float deltaAngleAbsolute = Mathf.Abs(TargetDeltaAngle);
|
float deltaAngleAbsolute = Mathf.Abs(TargetDeltaAngle);
|
||||||
if (deltaAngleAbsolute > 0.001)
|
if (deltaAngleAbsolute > 0.001) {
|
||||||
{
|
if (RotationSpeedRadPerSecond * delta >= deltaAngleAbsolute) {
|
||||||
if (RotationSpeedRadPerSecond * delta >= deltaAngleAbsolute)
|
|
||||||
{
|
|
||||||
entity.PlaneAngle = TargetAngle;
|
entity.PlaneAngle = TargetAngle;
|
||||||
TargetDeltaAngle = 0;
|
TargetDeltaAngle = 0;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
entity.PlaneAngle += Mathf.Sign(TargetDeltaAngle) * RotationSpeedRadPerSecond * delta;
|
entity.PlaneAngle += Mathf.Sign(TargetDeltaAngle) * RotationSpeedRadPerSecond * delta;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
TargetDeltaAngle = 0;
|
TargetDeltaAngle = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CalcPlaneVelocity(float delta, Entity entity, Vector3 targetPosition)
|
private void CalcPlaneVelocity(float delta, Entity entity, Vector3 targetPosition) {
|
||||||
{
|
|
||||||
Vector2 planeTargetDirection = new(DirectionToTarget.x, DirectionToTarget.z);
|
Vector2 planeTargetDirection = new(DirectionToTarget.x, DirectionToTarget.z);
|
||||||
|
|
||||||
Vector2 planeVelocity = new(entity.Velocity.x, entity.Velocity.z);
|
Vector2 planeVelocity = new(entity.Velocity.x, entity.Velocity.z);
|
||||||
|
@ -44,29 +35,25 @@ public class GroundMotionComponent : Component
|
||||||
planeVelocity -= planeVelocity * Damping;
|
planeVelocity -= planeVelocity * Damping;
|
||||||
// GD.Print(" damp : speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
// GD.Print(" damp : speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
||||||
|
|
||||||
if (DistanceToTarget < 0.01)
|
if (DistanceToTarget < 0.01) {
|
||||||
{
|
|
||||||
planeVelocity = Vector2.Zero;
|
planeVelocity = Vector2.Zero;
|
||||||
}
|
} else if (TargetDeltaAngle == 0.0) {
|
||||||
else if (TargetDeltaAngle == 0.0)
|
|
||||||
{
|
|
||||||
planeVelocity = planeVelocity.Length() * planeTargetDirection + planeTargetDirection * Accel * delta;
|
planeVelocity = planeVelocity.Length() * planeTargetDirection + planeTargetDirection * Accel * delta;
|
||||||
// GD.Print(" accel: speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
// GD.Print(" accel: speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
||||||
|
|
||||||
float projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
|
float projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
|
||||||
// GD.Print(" Projected step: " + projectedStep + " Speed: " + planeVelocity.Length() + " delta: " + delta);
|
// GD.Print(" Projected step: " + projectedStep + " Speed: " + planeVelocity.Length() + " delta: " + delta);
|
||||||
if (projectedStep > DistanceToTarget)
|
if (projectedStep > DistanceToTarget) {
|
||||||
{
|
|
||||||
planeVelocity *= DistanceToTarget / projectedStep;
|
planeVelocity *= DistanceToTarget / projectedStep;
|
||||||
projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
|
projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
|
||||||
// GD.Print(" corr speed: " + planeVelocity.Length() + " step: " + projectedStep);
|
// GD.Print(" corr speed: " + planeVelocity.Length() + " step: " + projectedStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
float planeSpeed = planeVelocity.Length();
|
float planeSpeed = planeVelocity.Length();
|
||||||
if (planeSpeed > MaxSpeed) planeVelocity *= MaxSpeed / planeSpeed;
|
if (planeSpeed > MaxSpeed) {
|
||||||
|
planeVelocity *= MaxSpeed / planeSpeed;
|
||||||
}
|
}
|
||||||
else
|
} else {
|
||||||
{
|
|
||||||
planeVelocity = Vector2.Zero;
|
planeVelocity = Vector2.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,22 +61,19 @@ public class GroundMotionComponent : Component
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void CalcVerticalVelocity(float delta, Entity entity, TileWorld tileWorld)
|
private void CalcVerticalVelocity(float delta, Entity entity, TileWorld tileWorld) {
|
||||||
{
|
|
||||||
Vector3 entityVelocity = entity.Velocity;
|
Vector3 entityVelocity = entity.Velocity;
|
||||||
|
|
||||||
Vector2 currentTile = tileWorld.WorldToOffsetCoords(entity.GlobalTransform.origin);
|
Vector2 currentTile = tileWorld.WorldToOffsetCoords(entity.GlobalTransform.origin);
|
||||||
Vector2 nextTile = tileWorld.WorldToOffsetCoords(entity.GlobalTransform.origin + entityVelocity * delta);
|
Vector2 nextTile = tileWorld.WorldToOffsetCoords(entity.GlobalTransform.origin + entityVelocity * delta);
|
||||||
|
|
||||||
if (nextTile != currentTile)
|
if (nextTile != currentTile) {
|
||||||
{
|
|
||||||
float currentHeight = tileWorld.GetHeightAtOffset(currentTile);
|
float currentHeight = tileWorld.GetHeightAtOffset(currentTile);
|
||||||
float nextHeight = tileWorld.GetHeightAtOffset(nextTile);
|
float nextHeight = tileWorld.GetHeightAtOffset(nextTile);
|
||||||
|
|
||||||
bool isOnFloor = entity.IsOnFloor();
|
bool isOnFloor = entity.IsOnFloor();
|
||||||
|
|
||||||
if (nextHeight - entity.GlobalTransform.origin.y > 0.1)
|
if (nextHeight - entity.GlobalTransform.origin.y > 0.1) {
|
||||||
{
|
|
||||||
GD.Print("Jump!");
|
GD.Print("Jump!");
|
||||||
entityVelocity.y = 10;
|
entityVelocity.y = 10;
|
||||||
|
|
||||||
|
@ -105,32 +89,26 @@ public class GroundMotionComponent : Component
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PhysicsProcess(float delta, Entity entity, Vector3 targetPosition, float targetAngle,
|
public void PhysicsProcess(float delta, Entity entity, Vector3 targetPosition, float targetAngle,
|
||||||
World world)
|
World world) {
|
||||||
{
|
|
||||||
DirectionToTarget = targetPosition - entity.GlobalTranslation;
|
DirectionToTarget = targetPosition - entity.GlobalTranslation;
|
||||||
DirectionToTarget.y = 0;
|
DirectionToTarget.y = 0;
|
||||||
DistanceToTarget = DirectionToTarget.Length();
|
DistanceToTarget = DirectionToTarget.Length();
|
||||||
|
|
||||||
if (DistanceToTarget >= Globals.EpsPosition)
|
if (DistanceToTarget >= Globals.EpsPosition) {
|
||||||
{
|
|
||||||
DirectionToTarget = DirectionToTarget.Normalized();
|
DirectionToTarget = DirectionToTarget.Normalized();
|
||||||
TargetAngle = Vector3.Right.SignedAngleTo(DirectionToTarget, Vector3.Up);
|
TargetAngle = Vector3.Right.SignedAngleTo(DirectionToTarget, Vector3.Up);
|
||||||
TargetDeltaAngle = entity.CalcShortestPlaneRotationToTargetDirection(DirectionToTarget);
|
TargetDeltaAngle = entity.CalcShortestPlaneRotationToTargetDirection(DirectionToTarget);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
DirectionToTarget = Vector3.Right;
|
DirectionToTarget = Vector3.Right;
|
||||||
entity.GlobalTranslation = targetPosition;
|
entity.GlobalTranslation = targetPosition;
|
||||||
entity.Velocity = new Vector3(0, entity.Velocity.y, 0);
|
entity.Velocity = new Vector3(0, entity.Velocity.y, 0);
|
||||||
|
|
||||||
if (entity.PlaneAngle != targetAngle)
|
if (entity.PlaneAngle != targetAngle) {
|
||||||
{
|
|
||||||
Vector3 directionToTarget = Vector3.Right.Rotated(Vector3.Up, targetAngle);
|
Vector3 directionToTarget = Vector3.Right.Rotated(Vector3.Up, targetAngle);
|
||||||
TargetAngle = targetAngle;
|
TargetAngle = targetAngle;
|
||||||
TargetDeltaAngle = entity.CalcShortestPlaneRotationToTargetDirection(directionToTarget);
|
TargetDeltaAngle = entity.CalcShortestPlaneRotationToTargetDirection(directionToTarget);
|
||||||
|
|
||||||
if (Mathf.Abs(TargetDeltaAngle) < Globals.EpsRadians)
|
if (Mathf.Abs(TargetDeltaAngle) < Globals.EpsRadians) {
|
||||||
{
|
|
||||||
TargetAngle = entity.PlaneAngle;
|
TargetAngle = entity.PlaneAngle;
|
||||||
TargetDeltaAngle = 0;
|
TargetDeltaAngle = 0;
|
||||||
|
|
||||||
|
|
|
@ -2,20 +2,18 @@ using Godot;
|
||||||
|
|
||||||
namespace GodotComponentTest.components;
|
namespace GodotComponentTest.components;
|
||||||
|
|
||||||
public class InteractionComponent: Component
|
public class InteractionComponent : Component {
|
||||||
{
|
|
||||||
[Signal]
|
[Signal]
|
||||||
delegate void InteractionStart(Spatial owningEntity, Spatial targetEntity);
|
private delegate void InteractionStart(Spatial owningEntity, Spatial targetEntity);
|
||||||
|
|
||||||
[Signal]
|
[Signal]
|
||||||
delegate void InteractionEnd(Spatial owningEntity, Spatial targetEntity);
|
private delegate void InteractionEnd(Spatial owningEntity, Spatial targetEntity);
|
||||||
|
|
||||||
public void EndInteraction()
|
public void EndInteraction() {
|
||||||
{
|
|
||||||
hasStopped = true;
|
hasStopped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool hasStopped = false;
|
public bool hasStopped;
|
||||||
public Spatial OwningEntity;
|
public Spatial OwningEntity;
|
||||||
public Spatial TargetEntity;
|
public Spatial TargetEntity;
|
||||||
}
|
}
|
|
@ -1,15 +1,13 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
using System;
|
|
||||||
|
|
||||||
public class MovableComponent : Component
|
public class MovableComponent : Component {
|
||||||
{
|
|
||||||
public Vector3 targetPosition = Vector3.Zero;
|
public Vector3 targetPosition = Vector3.Zero;
|
||||||
public Vector3 currentPosition = Vector3.Zero;
|
public Vector3 currentPosition = Vector3.Zero;
|
||||||
public Vector3 currentVelocity = Vector3.Zero;
|
public Vector3 currentVelocity = Vector3.Zero;
|
||||||
|
|
||||||
public float targetAngle = 0;
|
public float targetAngle;
|
||||||
public float currentAngle = 0;
|
public float currentAngle;
|
||||||
public float currentAngularVelocity = 0;
|
public float currentAngularVelocity;
|
||||||
|
|
||||||
[Export] public float maxSpeed = 3;
|
[Export] public float maxSpeed = 3;
|
||||||
|
|
||||||
|
@ -17,59 +15,52 @@ public class MovableComponent : Component
|
||||||
private SpringDamper _angleSpringDamper;
|
private SpringDamper _angleSpringDamper;
|
||||||
|
|
||||||
[Signal]
|
[Signal]
|
||||||
delegate void PositionUpdated(Vector3 newPosition);
|
private delegate void PositionUpdated(Vector3 newPosition);
|
||||||
|
|
||||||
[Signal]
|
[Signal]
|
||||||
delegate void OrientationUpdated(float newAngle);
|
private delegate void OrientationUpdated(float newAngle);
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
_positionSpringDamper = new SpringDamper(4, 0.99f, 0.5f);
|
_positionSpringDamper = new SpringDamper(4, 0.99f, 0.5f);
|
||||||
_angleSpringDamper = new SpringDamper(4, 0.99f, 0.5f);
|
_angleSpringDamper = new SpringDamper(4, 0.99f, 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called every frame. 'delta' is the elapsed time since the previous frame.
|
// Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
public override void _Process(float delta)
|
public override void _Process(float delta) {
|
||||||
{
|
|
||||||
Vector3 targetError = targetPosition - currentPosition;
|
Vector3 targetError = targetPosition - currentPosition;
|
||||||
|
|
||||||
if (targetError.LengthSquared() > 0.01)
|
if (targetError.LengthSquared() > 0.01) {
|
||||||
{
|
|
||||||
Vector3 targetDir = targetError.Normalized();
|
Vector3 targetDir = targetError.Normalized();
|
||||||
targetAngle = new Vector3(0, 0, 1).SignedAngleTo(targetDir, Vector3.Up);
|
targetAngle = new Vector3(0, 0, 1).SignedAngleTo(targetDir, Vector3.Up);
|
||||||
|
|
||||||
if (targetAngle - currentAngle > Mathf.Pi)
|
if (targetAngle - currentAngle > Mathf.Pi) {
|
||||||
{
|
|
||||||
currentAngle += 2 * Mathf.Pi;
|
currentAngle += 2 * Mathf.Pi;
|
||||||
}
|
} else if (targetAngle - currentAngle < -Mathf.Pi) {
|
||||||
else if (targetAngle - currentAngle < -Mathf.Pi)
|
|
||||||
{
|
|
||||||
currentAngle -= 2 * Mathf.Pi;
|
currentAngle -= 2 * Mathf.Pi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Mathf.Abs(currentAngularVelocity) > 0.1 || Mathf.Abs(targetAngle - currentAngle) > 0.01)
|
if (Mathf.Abs(currentAngularVelocity) > 0.1 || Mathf.Abs(targetAngle - currentAngle) > 0.01) {
|
||||||
{
|
(float, float) springDamperResult =
|
||||||
var springDamperResult =
|
|
||||||
_angleSpringDamper.Calc(currentAngle, currentAngularVelocity, targetAngle, delta);
|
_angleSpringDamper.Calc(currentAngle, currentAngularVelocity, targetAngle, delta);
|
||||||
|
|
||||||
currentAngle = springDamperResult.Item1;
|
currentAngle = springDamperResult.Item1;
|
||||||
currentAngularVelocity = springDamperResult.Item2;
|
currentAngularVelocity = springDamperResult.Item2;
|
||||||
|
|
||||||
EmitSignal("OrientationUpdated", this.currentAngle);
|
EmitSignal("OrientationUpdated", currentAngle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((Mathf.Abs(currentAngularVelocity) < 5 && Mathf.Abs(targetAngle - currentAngle) < 0.3)
|
if (Mathf.Abs(currentAngularVelocity) < 5 && Mathf.Abs(targetAngle - currentAngle) < 0.3
|
||||||
&& (targetPosition - currentPosition).LengthSquared() > 0.01)
|
&& (targetPosition - currentPosition).LengthSquared() > 0.01) {
|
||||||
{
|
(Vector3, Vector3) springDamperResult =
|
||||||
var springDamperResult =
|
|
||||||
_positionSpringDamper.CalcClampedSpeedXZ(currentPosition, currentVelocity, targetPosition, delta,
|
_positionSpringDamper.CalcClampedSpeedXZ(currentPosition, currentVelocity, targetPosition, delta,
|
||||||
maxSpeed);
|
maxSpeed);
|
||||||
|
|
||||||
currentPosition = springDamperResult.Item1;
|
currentPosition = springDamperResult.Item1;
|
||||||
currentVelocity = springDamperResult.Item2;
|
currentVelocity = springDamperResult.Item2;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentVelocity.y = currentVelocity.y - 9.81f * delta;
|
currentVelocity.y = currentVelocity.y - 9.81f * delta;
|
||||||
currentPosition.y = currentPosition.y + currentVelocity.y * delta;
|
currentPosition.y = currentPosition.y + currentVelocity.y * delta;
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,9 @@ using GodotComponentTest.utils;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class NavigationComponent : Spatial
|
public class NavigationComponent : Spatial {
|
||||||
{
|
[Export] public bool PathSmoothing = false;
|
||||||
|
|
||||||
public World World { set; get; }
|
public World World { set; get; }
|
||||||
public Vector3 CurrentGoalPositionWorld { get; private set; } = Vector3.Zero;
|
public Vector3 CurrentGoalPositionWorld { get; private set; } = Vector3.Zero;
|
||||||
public float CurrentGoalAngleWorld { get; private set; }
|
public float CurrentGoalAngleWorld { get; private set; }
|
||||||
|
@ -16,69 +17,57 @@ public class NavigationComponent : Spatial
|
||||||
private NavigationPoint _currentGoal;
|
private NavigationPoint _currentGoal;
|
||||||
private HexCell[] _path;
|
private HexCell[] _path;
|
||||||
private List<NavigationPoint> _pathWorldNavigationPoints = new();
|
private List<NavigationPoint> _pathWorldNavigationPoints = new();
|
||||||
private List<NavigationPoint> _planningPathSmoothedWorldNavigationPoints = new();
|
private List<NavigationPoint> _activePathWorldNavigationPoints = new();
|
||||||
|
|
||||||
private List<NavigationPoint> _planningPathWorldNavigationPoints = new();
|
private List<NavigationPoint> _planningPathWorldNavigationPoints = new();
|
||||||
private List<NavigationPoint> _smoothedPathWorldNavigationPoints = new();
|
private List<NavigationPoint> _smoothedPathWorldNavigationPoints = new();
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
base._Ready();
|
base._Ready();
|
||||||
_pathWorldNavigationPoints = new List<NavigationPoint>();
|
_pathWorldNavigationPoints = new List<NavigationPoint>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process(float delta)
|
public override void _Process(float delta) {
|
||||||
{
|
|
||||||
Debug.Assert(World != null);
|
Debug.Assert(World != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PlanSmoothedPath(KinematicBody body, Transform fromTransformWorld, NavigationPoint navigationPoint)
|
public void PlanSmoothedPath(Entity body, Transform fromTransformWorld, NavigationPoint navigationPoint) {
|
||||||
{
|
|
||||||
if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)
|
if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)
|
||||||
&& navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation))
|
&& navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation)) {
|
||||||
{
|
|
||||||
FindPath(body, fromTransformWorld.origin, navigationPoint);
|
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);
|
FindPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FindPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld)
|
public void FindPath(Entity entity, Vector3 fromPositionWorld, Vector3 toPositionWorld) {
|
||||||
{
|
HexCell fromCell = World.HexGrid.GetHexAt(new Vector2(fromPositionWorld.x, fromPositionWorld.z));
|
||||||
var fromCell = World.HexGrid.GetHexAt(new Vector2(fromPositionWorld.x, fromPositionWorld.z));
|
if (World.HexGrid.GetHexCost(fromCell) == 0) {
|
||||||
if (World.HexGrid.GetHexCost(fromCell) == 0)
|
|
||||||
{
|
|
||||||
GD.Print("Invalid starting point for FindPath(): returning empty path.");
|
GD.Print("Invalid starting point for FindPath(): returning empty path.");
|
||||||
_planningPathWorldNavigationPoints = new List<NavigationPoint>();
|
_planningPathWorldNavigationPoints = new List<NavigationPoint>();
|
||||||
_planningPathWorldNavigationPoints.Add(new NavigationPoint(fromPositionWorld));
|
_planningPathWorldNavigationPoints.Add(new NavigationPoint(fromPositionWorld));
|
||||||
_planningPathSmoothedWorldNavigationPoints = _planningPathWorldNavigationPoints;
|
_activePathWorldNavigationPoints = _planningPathWorldNavigationPoints;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var toCell = World.HexGrid.GetHexAt(new Vector2(toPositionWorld.x, toPositionWorld.z));
|
HexCell toCell = World.HexGrid.GetHexAt(new Vector2(toPositionWorld.x, toPositionWorld.z));
|
||||||
toCell = World.HexGrid.GetClosestWalkableCell(fromCell, toCell);
|
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.");
|
GD.Print("Invalid target point for FindPath(): returning empty path.");
|
||||||
_planningPathWorldNavigationPoints = new List<NavigationPoint>();
|
_planningPathWorldNavigationPoints = new List<NavigationPoint>();
|
||||||
_planningPathWorldNavigationPoints.Add(new NavigationPoint(fromPositionWorld));
|
_planningPathWorldNavigationPoints.Add(new NavigationPoint(fromPositionWorld));
|
||||||
_planningPathSmoothedWorldNavigationPoints = _planningPathWorldNavigationPoints;
|
_activePathWorldNavigationPoints = _planningPathWorldNavigationPoints;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var path = World.HexGrid.FindPath(fromCell, toCell);
|
List<HexCell> path = World.FindPath(entity, fromCell, toCell);
|
||||||
|
|
||||||
// Generate grid navigation points
|
// Generate grid navigation points
|
||||||
_planningPathWorldNavigationPoints = new List<NavigationPoint>();
|
_planningPathWorldNavigationPoints = new List<NavigationPoint>();
|
||||||
foreach (var index in Enumerable.Range(0, path.Count))
|
foreach (int index in Enumerable.Range(0, path.Count)) {
|
||||||
{
|
|
||||||
_planningPathWorldNavigationPoints.Add(
|
_planningPathWorldNavigationPoints.Add(
|
||||||
new NavigationPoint(World.HexGrid.GetHexCenterVec3FromOffset(path[index].OffsetCoords)));
|
new NavigationPoint(World.HexGrid.GetHexCenterVec3FromOffset(path[index].OffsetCoords)));
|
||||||
}
|
}
|
||||||
|
@ -86,40 +75,44 @@ public class NavigationComponent : Spatial
|
||||||
// Ensure the last point coincides with the target position
|
// Ensure the last point coincides with the target position
|
||||||
if (_planningPathWorldNavigationPoints.Count > 0 &&
|
if (_planningPathWorldNavigationPoints.Count > 0 &&
|
||||||
(_planningPathWorldNavigationPoints.Last().WorldPosition - toPositionWorld).LengthSquared() <
|
(_planningPathWorldNavigationPoints.Last().WorldPosition - toPositionWorld).LengthSquared() <
|
||||||
0.5f * 0.5f)
|
0.5f * 0.5f) {
|
||||||
{
|
|
||||||
_planningPathWorldNavigationPoints[_planningPathWorldNavigationPoints.Count - 1].WorldPosition =
|
_planningPathWorldNavigationPoints[_planningPathWorldNavigationPoints.Count - 1].WorldPosition =
|
||||||
toPositionWorld;
|
toPositionWorld;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform smoothing
|
// Perform smoothing
|
||||||
_planningPathSmoothedWorldNavigationPoints = SmoothPath(body, _planningPathWorldNavigationPoints);
|
if (PathSmoothing)
|
||||||
|
{
|
||||||
|
_activePathWorldNavigationPoints = World.SmoothPath(entity, _planningPathWorldNavigationPoints);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_activePathWorldNavigationPoints = _planningPathWorldNavigationPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Ensure starting point is the current position
|
// Ensure starting point is the current position
|
||||||
if (_planningPathSmoothedWorldNavigationPoints.Count > 0)
|
if (_activePathWorldNavigationPoints.Count > 0) {
|
||||||
{
|
_activePathWorldNavigationPoints[0] = new NavigationPoint(fromPositionWorld);
|
||||||
_planningPathSmoothedWorldNavigationPoints[0] = new NavigationPoint(fromPositionWorld);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FindPath(KinematicBody body, Vector3 fromPositionWorld, NavigationPoint navigationPoint)
|
public void FindPath(Entity entity, Vector3 fromPositionWorld, NavigationPoint navigationPoint) {
|
||||||
{
|
FindPath(entity, fromPositionWorld, navigationPoint.WorldPosition);
|
||||||
FindPath(body, fromPositionWorld, navigationPoint.WorldPosition);
|
|
||||||
|
|
||||||
_planningPathWorldNavigationPoints[_planningPathWorldNavigationPoints.Count - 1] = navigationPoint;
|
_planningPathWorldNavigationPoints[_planningPathWorldNavigationPoints.Count - 1] = navigationPoint;
|
||||||
_planningPathSmoothedWorldNavigationPoints[_planningPathSmoothedWorldNavigationPoints.Count - 1] =
|
_activePathWorldNavigationPoints[_activePathWorldNavigationPoints.Count - 1] =
|
||||||
navigationPoint;
|
navigationPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PlanGridPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld)
|
public void PlanGridPath(Entity entity, Vector3 fromPositionWorld, Vector3 toPositionWorld) {
|
||||||
{
|
Vector2 fromPositionOffset = World.WorldToOffsetCoords(fromPositionWorld);
|
||||||
var fromPositionOffset = World.WorldToOffsetCoords(fromPositionWorld);
|
Vector2 toPositionOffset = World.WorldToOffsetCoords(toPositionWorld);
|
||||||
var toPositionOffset = World.WorldToOffsetCoords(toPositionWorld);
|
|
||||||
|
|
||||||
var fromCell = new HexCell();
|
HexCell fromCell = new();
|
||||||
fromCell.OffsetCoords = fromPositionOffset;
|
fromCell.OffsetCoords = fromPositionOffset;
|
||||||
|
|
||||||
var toCell = new HexCell();
|
HexCell toCell = new();
|
||||||
toCell.OffsetCoords = toPositionOffset;
|
toCell.OffsetCoords = toPositionOffset;
|
||||||
|
|
||||||
_path = fromCell.LineTo(toCell);
|
_path = fromCell.LineTo(toCell);
|
||||||
|
@ -129,26 +122,23 @@ public class NavigationComponent : Spatial
|
||||||
_pathWorldNavigationPoints.Add(
|
_pathWorldNavigationPoints.Add(
|
||||||
new NavigationPoint(World.HexGrid.GetHexCenterVec3FromOffset(fromPositionOffset)));
|
new NavigationPoint(World.HexGrid.GetHexCenterVec3FromOffset(fromPositionOffset)));
|
||||||
|
|
||||||
foreach (var index in Enumerable.Range(1, _path.Length - 1))
|
foreach (int index in Enumerable.Range(1, _path.Length - 1)) {
|
||||||
{
|
|
||||||
_pathWorldNavigationPoints.Add(
|
_pathWorldNavigationPoints.Add(
|
||||||
new NavigationPoint(World.GetHexCenterFromOffset(_path[index].OffsetCoords)));
|
new NavigationPoint(World.GetHexCenterFromOffset(_path[index].OffsetCoords)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fromPositionWorld - World.GetHexCenterFromOffset(toCell.OffsetCoords)).LengthSquared() >
|
if ((fromPositionWorld - World.GetHexCenterFromOffset(toCell.OffsetCoords)).LengthSquared() >
|
||||||
Globals.EpsPositionSquared)
|
Globals.EpsPositionSquared)
|
||||||
{
|
|
||||||
// Remove the last one, because it is only the position rounded to HexGrid coordinates.
|
// Remove the last one, because it is only the position rounded to HexGrid coordinates.
|
||||||
if (_pathWorldNavigationPoints.Count > 0)
|
|
||||||
{
|
{
|
||||||
|
if (_pathWorldNavigationPoints.Count > 0) {
|
||||||
_pathWorldNavigationPoints.RemoveAt(_pathWorldNavigationPoints.Count - 1);
|
_pathWorldNavigationPoints.RemoveAt(_pathWorldNavigationPoints.Count - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_pathWorldNavigationPoints.Add(new NavigationPoint(toPositionWorld));
|
_pathWorldNavigationPoints.Add(new NavigationPoint(toPositionWorld));
|
||||||
if (_pathWorldNavigationPoints.Count > 2)
|
if (_pathWorldNavigationPoints.Count > 2) {
|
||||||
{
|
_smoothedPathWorldNavigationPoints = SmoothPath(entity, _pathWorldNavigationPoints);
|
||||||
_smoothedPathWorldNavigationPoints = SmoothPath(body, _pathWorldNavigationPoints);
|
|
||||||
_pathWorldNavigationPoints = _smoothedPathWorldNavigationPoints;
|
_pathWorldNavigationPoints = _smoothedPathWorldNavigationPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,36 +146,28 @@ public class NavigationComponent : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void PlanGridPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld,
|
public void PlanGridPath(Entity entity, Vector3 fromPositionWorld, Vector3 toPositionWorld,
|
||||||
Quat toWorldOrientation)
|
Quat toWorldOrientation) {
|
||||||
{
|
PlanGridPath(entity, fromPositionWorld, toPositionWorld);
|
||||||
PlanGridPath(body, fromPositionWorld, toPositionWorld);
|
|
||||||
|
|
||||||
_pathWorldNavigationPoints.Add(new NavigationPoint(toWorldOrientation));
|
_pathWorldNavigationPoints.Add(new NavigationPoint(toWorldOrientation));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void PlanGridPath(KinematicBody body, Transform fromTransformWorld, NavigationPoint navigationPoint)
|
public void PlanGridPath(Entity entity, Transform fromTransformWorld, NavigationPoint navigationPoint) {
|
||||||
{
|
|
||||||
if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)
|
if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)
|
||||||
&& navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation))
|
&& navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation)) {
|
||||||
{
|
PlanGridPath(entity, fromTransformWorld.origin, navigationPoint.WorldPosition,
|
||||||
PlanGridPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition,
|
|
||||||
navigationPoint.WorldOrientation);
|
navigationPoint.WorldOrientation);
|
||||||
}
|
} else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)) {
|
||||||
else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position))
|
PlanGridPath(entity, fromTransformWorld.origin, navigationPoint.WorldPosition);
|
||||||
{
|
} else {
|
||||||
PlanGridPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void PlanDirectPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld)
|
public void PlanDirectPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld) {
|
||||||
{
|
|
||||||
_pathWorldNavigationPoints.Clear();
|
_pathWorldNavigationPoints.Clear();
|
||||||
_pathWorldNavigationPoints.Add(new NavigationPoint(toPositionWorld));
|
_pathWorldNavigationPoints.Add(new NavigationPoint(toPositionWorld));
|
||||||
|
|
||||||
|
@ -194,23 +176,20 @@ public class NavigationComponent : Spatial
|
||||||
|
|
||||||
|
|
||||||
public void PlanDirectPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld,
|
public void PlanDirectPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld,
|
||||||
Quat toWorldOrientation)
|
Quat toWorldOrientation) {
|
||||||
{
|
|
||||||
PlanDirectPath(body, fromPositionWorld, toPositionWorld);
|
PlanDirectPath(body, fromPositionWorld, toPositionWorld);
|
||||||
|
|
||||||
_pathWorldNavigationPoints.Add(new NavigationPoint(toWorldOrientation));
|
_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 fromPositionLocal = GlobalTransform.XformInv(fromPositionWorld);
|
||||||
Vector3 toPositionLocal = GlobalTransform.XformInv(toPositionWorld);
|
Vector3 toPositionLocal = GlobalTransform.XformInv(toPositionWorld);
|
||||||
Vector3 relativeVelocity = GlobalTransform.basis.Xform(toPositionLocal - fromPositionLocal);
|
Vector3 relativeVelocity = GlobalTransform.basis.Xform(toPositionLocal - fromPositionLocal);
|
||||||
|
|
||||||
KinematicCollision moveCollision = body.MoveAndCollide(relativeVelocity, true, true, true);
|
KinematicCollision moveCollision = body.MoveAndCollide(relativeVelocity, true, true, true);
|
||||||
if (moveCollision != null)
|
if (moveCollision != null) {
|
||||||
{
|
|
||||||
Spatial colliderSpatial = moveCollision.Collider as Spatial;
|
Spatial colliderSpatial = moveCollision.Collider as Spatial;
|
||||||
// GD.Print("Found collision: " + moveCollision.Collider + " (" + colliderSpatial.Name + ")");
|
// GD.Print("Found collision: " + moveCollision.Collider + " (" + colliderSpatial.Name + ")");
|
||||||
return true;
|
return true;
|
||||||
|
@ -220,37 +199,30 @@ public class NavigationComponent : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public bool CheckSweptTriangleCellCollision(Vector3 startWorld, Vector3 endWorld, float radius)
|
public bool CheckSweptTriangleCellCollision(Vector3 startWorld, Vector3 endWorld, float radius) {
|
||||||
{
|
Vector2 startPlane = new(startWorld.x, startWorld.z);
|
||||||
Vector2 startPlane = new Vector2(startWorld.x, startWorld.z);
|
Vector2 endPlane = new(endWorld.x, endWorld.z);
|
||||||
Vector2 endPlane = new Vector2(endWorld.x, endWorld.z);
|
|
||||||
Vector2 directionPlane = (endPlane - startPlane).Normalized();
|
Vector2 directionPlane = (endPlane - startPlane).Normalized();
|
||||||
Vector2 sidePlane = directionPlane.Rotated(Mathf.Pi * 0.5f);
|
Vector2 sidePlane = directionPlane.Rotated(Mathf.Pi * 0.5f);
|
||||||
|
|
||||||
List<HexCell> cells =
|
List<HexCell> cells =
|
||||||
World.HexGrid.GetCellsForLine(startPlane + directionPlane * radius, endPlane + directionPlane * radius);
|
World.HexGrid.GetCellsForLine(startPlane + directionPlane * radius, endPlane + directionPlane * radius);
|
||||||
foreach (HexCell cell in cells)
|
foreach (HexCell cell in cells) {
|
||||||
{
|
if (World.HexGrid.GetHexCost(cell) == 0) {
|
||||||
if (World.HexGrid.GetHexCost(cell) == 0)
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cells = World.HexGrid.GetCellsForLine(startPlane + sidePlane * radius, endPlane + sidePlane * radius);
|
cells = World.HexGrid.GetCellsForLine(startPlane + sidePlane * radius, endPlane + sidePlane * radius);
|
||||||
foreach (HexCell cell in cells)
|
foreach (HexCell cell in cells) {
|
||||||
{
|
if (World.HexGrid.GetHexCost(cell) == 0) {
|
||||||
if (World.HexGrid.GetHexCost(cell) == 0)
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cells = World.HexGrid.GetCellsForLine(startPlane - sidePlane * radius, endPlane - sidePlane * radius);
|
cells = World.HexGrid.GetCellsForLine(startPlane - sidePlane * radius, endPlane - sidePlane * radius);
|
||||||
foreach (HexCell cell in cells)
|
foreach (HexCell cell in cells) {
|
||||||
{
|
if (World.HexGrid.GetHexCost(cell) == 0) {
|
||||||
if (World.HexGrid.GetHexCost(cell) == 0)
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,29 +230,24 @@ public class NavigationComponent : Spatial
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<NavigationPoint> SmoothPath(KinematicBody body, List<NavigationPoint> navigationPoints)
|
public List<NavigationPoint> SmoothPath(KinematicBody body, List<NavigationPoint> navigationPoints) {
|
||||||
{
|
if (navigationPoints.Count <= 2) {
|
||||||
if (navigationPoints.Count <= 2)
|
|
||||||
{
|
|
||||||
return navigationPoints;
|
return navigationPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 bodyGlobalTranslation = body.GlobalTranslation;
|
Vector3 bodyGlobalTranslation = body.GlobalTranslation;
|
||||||
List<NavigationPoint> smoothedPath = new List<NavigationPoint>();
|
List<NavigationPoint> smoothedPath = new();
|
||||||
|
|
||||||
int startIndex = 0;
|
int startIndex = 0;
|
||||||
int endIndex = navigationPoints.Count > 1 ? 1 : 0;
|
int endIndex = navigationPoints.Count > 1 ? 1 : 0;
|
||||||
smoothedPath.Add(navigationPoints[startIndex]);
|
smoothedPath.Add(navigationPoints[startIndex]);
|
||||||
Vector3 startPoint = navigationPoints[startIndex].WorldPosition;
|
Vector3 startPoint = navigationPoints[startIndex].WorldPosition;
|
||||||
|
|
||||||
while (endIndex != navigationPoints.Count)
|
while (endIndex != navigationPoints.Count) {
|
||||||
{
|
|
||||||
Vector3 endPoint = navigationPoints[endIndex].WorldPosition;
|
Vector3 endPoint = navigationPoints[endIndex].WorldPosition;
|
||||||
|
|
||||||
if (CheckSweptTriangleCellCollision(startPoint, endPoint, 0.27f))
|
if (CheckSweptTriangleCellCollision(startPoint, endPoint, 0.27f)) {
|
||||||
{
|
if (endIndex - startIndex == 1) {
|
||||||
if (endIndex - startIndex == 1)
|
|
||||||
{
|
|
||||||
GD.Print("Aborting SmoothPath: input path passes through collision geometry.");
|
GD.Print("Aborting SmoothPath: input path passes through collision geometry.");
|
||||||
body.GlobalTranslation = bodyGlobalTranslation;
|
body.GlobalTranslation = bodyGlobalTranslation;
|
||||||
return smoothedPath;
|
return smoothedPath;
|
||||||
|
@ -294,8 +261,7 @@ public class NavigationComponent : Spatial
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endIndex == navigationPoints.Count - 1)
|
if (endIndex == navigationPoints.Count - 1) {
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,34 +274,25 @@ public class NavigationComponent : Spatial
|
||||||
return smoothedPath;
|
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)
|
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,
|
PlanDirectPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition,
|
||||||
navigationPoint.WorldOrientation);
|
navigationPoint.WorldOrientation);
|
||||||
}
|
} else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)) {
|
||||||
else if (navigationPoint.Flags.HasFlag(NavigationPoint.NavigationFlags.Position))
|
|
||||||
{
|
|
||||||
PlanDirectPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition);
|
PlanDirectPath(body, fromTransformWorld.origin, navigationPoint.WorldPosition);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ActivatePlannedPath()
|
public void ActivatePlannedPath() {
|
||||||
{
|
_pathWorldNavigationPoints = _activePathWorldNavigationPoints;
|
||||||
_pathWorldNavigationPoints = _planningPathSmoothedWorldNavigationPoints;
|
|
||||||
UpdateCurrentGoal();
|
UpdateCurrentGoal();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateCurrentGoal()
|
private void UpdateCurrentGoal() {
|
||||||
{
|
if (_pathWorldNavigationPoints.Count == 0) {
|
||||||
if (_pathWorldNavigationPoints.Count == 0)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,73 +301,56 @@ public class NavigationComponent : Spatial
|
||||||
CurrentGoalAngleWorld = _pathWorldNavigationPoints[0].WorldAngle;
|
CurrentGoalAngleWorld = _pathWorldNavigationPoints[0].WorldAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyExistingTransform(Transform worldTransform)
|
private void ApplyExistingTransform(Transform worldTransform) {
|
||||||
{
|
if (_currentGoal.Flags == NavigationPoint.NavigationFlags.Orientation) {
|
||||||
if (_currentGoal.Flags == NavigationPoint.NavigationFlags.Orientation)
|
|
||||||
{
|
|
||||||
CurrentGoalPositionWorld = worldTransform.origin;
|
CurrentGoalPositionWorld = worldTransform.origin;
|
||||||
}
|
} else if (_currentGoal.Flags == NavigationPoint.NavigationFlags.Position) {
|
||||||
else if (_currentGoal.Flags == NavigationPoint.NavigationFlags.Position)
|
|
||||||
{
|
|
||||||
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(worldTransform);
|
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(worldTransform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void UpdateCurrentGoal(Transform currentTransformWorld)
|
public void UpdateCurrentGoal(Transform currentTransformWorld) {
|
||||||
{
|
if (_currentGoal == null) {
|
||||||
if (_currentGoal == null)
|
|
||||||
{
|
|
||||||
_currentGoal = new NavigationPoint(currentTransformWorld);
|
_currentGoal = new NavigationPoint(currentTransformWorld);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pathWorldNavigationPoints.Count == 0)
|
if (_pathWorldNavigationPoints.Count == 0) {
|
||||||
{
|
|
||||||
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
|
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
|
||||||
CurrentGoalPositionWorld = currentTransformWorld.origin;
|
CurrentGoalPositionWorld = currentTransformWorld.origin;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Position))
|
if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)) {
|
||||||
{
|
|
||||||
CurrentGoalPositionWorld = _pathWorldNavigationPoints[0].WorldPosition;
|
CurrentGoalPositionWorld = _pathWorldNavigationPoints[0].WorldPosition;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
|
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation))
|
if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation)) {
|
||||||
{
|
|
||||||
CurrentGoalAngleWorld = _currentGoal.WorldAngle;
|
CurrentGoalAngleWorld = _currentGoal.WorldAngle;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
|
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentGoal.IsReached(currentTransformWorld))
|
if (_currentGoal.IsReached(currentTransformWorld)) {
|
||||||
{
|
|
||||||
_pathWorldNavigationPoints.RemoveAt(0);
|
_pathWorldNavigationPoints.RemoveAt(0);
|
||||||
|
|
||||||
UpdateCurrentGoal();
|
UpdateCurrentGoal();
|
||||||
ApplyExistingTransform(currentTransformWorld);
|
ApplyExistingTransform(currentTransformWorld);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pathWorldNavigationPoints.Count == 0)
|
if (_pathWorldNavigationPoints.Count == 0) {
|
||||||
{
|
|
||||||
CurrentGoalPositionWorld = currentTransformWorld.origin;
|
CurrentGoalPositionWorld = currentTransformWorld.origin;
|
||||||
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
|
CurrentGoalAngleWorld = Globals.CalcPlaneAngle(currentTransformWorld);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsGoalReached()
|
public bool IsGoalReached() {
|
||||||
{
|
|
||||||
return _pathWorldNavigationPoints.Count == 0;
|
return _pathWorldNavigationPoints.Count == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DebugDraw(Spatial parentNode, DebugGeometry debugGeometry)
|
public void DebugDraw(Spatial parentNode, DebugGeometry debugGeometry) {
|
||||||
{
|
|
||||||
Vector3 yOffset = Vector3.Up * 0.1f;
|
Vector3 yOffset = Vector3.Up * 0.1f;
|
||||||
|
|
||||||
debugGeometry.GlobalTransform = Transform.Identity;
|
debugGeometry.GlobalTransform = Transform.Identity;
|
||||||
|
@ -428,8 +368,7 @@ public class NavigationComponent : Spatial
|
||||||
debugGeometry.PopTransform();
|
debugGeometry.PopTransform();
|
||||||
|
|
||||||
Vector3 previousPoint = parentNode.GlobalTranslation;
|
Vector3 previousPoint = parentNode.GlobalTranslation;
|
||||||
foreach (NavigationPoint point in _pathWorldNavigationPoints)
|
foreach (NavigationPoint point in _pathWorldNavigationPoints) {
|
||||||
{
|
|
||||||
debugGeometry.AddVertex(previousPoint + yOffset);
|
debugGeometry.AddVertex(previousPoint + yOffset);
|
||||||
debugGeometry.AddVertex(point.WorldPosition + yOffset);
|
debugGeometry.AddVertex(point.WorldPosition + yOffset);
|
||||||
|
|
||||||
|
@ -437,8 +376,7 @@ public class NavigationComponent : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
previousPoint = parentNode.GlobalTranslation;
|
previousPoint = parentNode.GlobalTranslation;
|
||||||
foreach (NavigationPoint point in _smoothedPathWorldNavigationPoints)
|
foreach (NavigationPoint point in _smoothedPathWorldNavigationPoints) {
|
||||||
{
|
|
||||||
debugGeometry.SetColor(new Color(0, 0, 1));
|
debugGeometry.SetColor(new Color(0, 0, 1));
|
||||||
debugGeometry.AddVertex(previousPoint + yOffset);
|
debugGeometry.AddVertex(previousPoint + yOffset);
|
||||||
debugGeometry.AddVertex(point.WorldPosition + yOffset);
|
debugGeometry.AddVertex(point.WorldPosition + yOffset);
|
||||||
|
@ -447,8 +385,7 @@ public class NavigationComponent : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
previousPoint = parentNode.GlobalTranslation;
|
previousPoint = parentNode.GlobalTranslation;
|
||||||
foreach (NavigationPoint point in _planningPathWorldNavigationPoints)
|
foreach (NavigationPoint point in _planningPathWorldNavigationPoints) {
|
||||||
{
|
|
||||||
debugGeometry.SetColor(new Color(1, 0, 1));
|
debugGeometry.SetColor(new Color(1, 0, 1));
|
||||||
debugGeometry.AddVertex(previousPoint + yOffset);
|
debugGeometry.AddVertex(previousPoint + yOffset);
|
||||||
debugGeometry.AddVertex(point.WorldPosition + yOffset);
|
debugGeometry.AddVertex(point.WorldPosition + yOffset);
|
||||||
|
@ -457,8 +394,7 @@ public class NavigationComponent : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
previousPoint = parentNode.GlobalTranslation;
|
previousPoint = parentNode.GlobalTranslation;
|
||||||
foreach (NavigationPoint point in _planningPathSmoothedWorldNavigationPoints)
|
foreach (NavigationPoint point in _activePathWorldNavigationPoints) {
|
||||||
{
|
|
||||||
debugGeometry.SetColor(new Color(1, 1, 0));
|
debugGeometry.SetColor(new Color(1, 1, 0));
|
||||||
debugGeometry.AddVertex(previousPoint + yOffset);
|
debugGeometry.AddVertex(previousPoint + yOffset);
|
||||||
debugGeometry.AddVertex(point.WorldPosition + yOffset);
|
debugGeometry.AddVertex(point.WorldPosition + yOffset);
|
||||||
|
|
|
@ -1,42 +1,39 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public class TaskQueueComponent : Component
|
public class TaskQueueComponent : Component {
|
||||||
{
|
|
||||||
[Signal]
|
[Signal]
|
||||||
private delegate void StartInteraction(Entity entity, Entity targetEntity);
|
private delegate void StartInteraction(Entity entity, Entity targetEntity);
|
||||||
|
|
||||||
public Queue<Task> Queue;
|
public Queue<Task> Queue;
|
||||||
|
|
||||||
public TaskQueueComponent()
|
public TaskQueueComponent() {
|
||||||
{
|
|
||||||
Queue = new Queue<Task>();
|
Queue = new Queue<Task>();
|
||||||
|
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset() {
|
||||||
{
|
|
||||||
Queue.Clear();
|
Queue.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Process(Entity entity, float delta)
|
public void Process(Entity entity, float delta) {
|
||||||
{
|
if (Queue.Count == 0) {
|
||||||
if (Queue.Count == 0) return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
do
|
do {
|
||||||
{
|
Task currentTask = Queue.Peek();
|
||||||
var currentTask = Queue.Peek();
|
|
||||||
|
|
||||||
if (currentTask.PerformTask(entity, this, delta))
|
if (currentTask.PerformTask(entity, this, delta)) {
|
||||||
Queue.Dequeue();
|
Queue.Dequeue();
|
||||||
else
|
} else {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
} while (Queue.Count > 0);
|
} while (Queue.Count > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class Task : Object
|
public abstract class Task : Object {
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Executes a Task on the specified entity.
|
/// Executes a Task on the specified entity.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -47,33 +44,27 @@ public class TaskQueueComponent : Component
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Makes an entity move towards a target (translation and or orientation).
|
/// Makes an entity move towards a target (translation and or orientation).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class NavigationTask : Task
|
public class NavigationTask : Task {
|
||||||
{
|
|
||||||
public NavigationPoint NavigationPoint;
|
public NavigationPoint NavigationPoint;
|
||||||
public bool PlanningComplete = false;
|
public bool PlanningComplete = false;
|
||||||
|
|
||||||
public NavigationTask(NavigationPoint navigationPoint)
|
public NavigationTask(NavigationPoint navigationPoint) {
|
||||||
{
|
|
||||||
NavigationPoint = navigationPoint;
|
NavigationPoint = navigationPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta)
|
public override bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta) {
|
||||||
{
|
|
||||||
return NavigationPoint.IsReached(entity.GlobalTransform);
|
return NavigationPoint.IsReached(entity.GlobalTransform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class InteractionTask : Task
|
public class InteractionTask : Task {
|
||||||
{
|
|
||||||
public Entity TargetEntity;
|
public Entity TargetEntity;
|
||||||
|
|
||||||
public InteractionTask(Entity entity)
|
public InteractionTask(Entity entity) {
|
||||||
{
|
|
||||||
TargetEntity = entity;
|
TargetEntity = entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta)
|
public override bool PerformTask(Entity entity, TaskQueueComponent taskQueueComponent, float delta) {
|
||||||
{
|
|
||||||
taskQueueComponent.EmitSignal("StartInteraction", entity, TargetEntity);
|
taskQueueComponent.EmitSignal("StartInteraction", entity, TargetEntity);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,18 +1,15 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public class WorldInfoComponent : Component
|
public class WorldInfoComponent : Component {
|
||||||
{
|
|
||||||
[Export] public NodePath WorldPath;
|
[Export] public NodePath WorldPath;
|
||||||
public World World;
|
public World World;
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
World = GetNode<World>(WorldPath);
|
World = GetNode<World>(WorldPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetWorld(World world)
|
public void SetWorld(World world) {
|
||||||
{
|
|
||||||
World = world;
|
World = world;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,11 +1 @@
|
||||||
using Godot;
|
public class Axe : Entity { }
|
||||||
using System;
|
|
||||||
|
|
||||||
public class Axe : StaticBody
|
|
||||||
{
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
|
||||||
public override void _Ready()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,14 @@
|
||||||
[gd_scene load_steps=4 format=2]
|
[gd_scene load_steps=5 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://assets/Objects/toolAxe.tscn" type="PackedScene" id=1]
|
[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://entities/Axe.cs" type="Script" id=2]
|
||||||
|
[ext_resource path="res://components/CollectibleComponent.tscn" type="PackedScene" id=3]
|
||||||
|
|
||||||
[sub_resource type="CylinderShape" id=1]
|
[sub_resource type="CylinderShape" id=1]
|
||||||
height = 0.846435
|
height = 0.846435
|
||||||
radius = 0.687167
|
radius = 0.687167
|
||||||
|
|
||||||
[node name="Axe" type="StaticBody"]
|
[node name="Axe" type="KinematicBody"]
|
||||||
collision_layer = 9
|
collision_layer = 9
|
||||||
collision_mask = 0
|
collision_mask = 0
|
||||||
script = ExtResource( 2 )
|
script = ExtResource( 2 )
|
||||||
|
@ -18,3 +19,5 @@ shape = SubResource( 1 )
|
||||||
|
|
||||||
[node name="toolAxe" parent="." instance=ExtResource( 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 )
|
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,13 +3,11 @@ using Godot;
|
||||||
using GodotComponentTest.components;
|
using GodotComponentTest.components;
|
||||||
using GodotComponentTest.entities;
|
using GodotComponentTest.entities;
|
||||||
|
|
||||||
public class Chest : Entity, IInteractionInterface
|
public class Chest : Entity, IInteractionInterface {
|
||||||
{
|
|
||||||
// resources
|
// resources
|
||||||
private readonly PackedScene _goldBarScene = GD.Load<PackedScene>("res://entities/GoldBar.tscn");
|
private readonly PackedScene _goldBarScene = GD.Load<PackedScene>("res://entities/GoldBar.tscn");
|
||||||
|
|
||||||
public enum LidState
|
public enum LidState {
|
||||||
{
|
|
||||||
Closed,
|
Closed,
|
||||||
Open
|
Open
|
||||||
}
|
}
|
||||||
|
@ -29,8 +27,7 @@ public class Chest : Entity, IInteractionInterface
|
||||||
private delegate void ChestOpened(Entity entity);
|
private delegate void ChestOpened(Entity entity);
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
_mesh = GetNode<MeshInstance>("Geometry/Skeleton/Chest");
|
_mesh = GetNode<MeshInstance>("Geometry/Skeleton/Chest");
|
||||||
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
|
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
|
||||||
|
|
||||||
|
@ -42,65 +39,52 @@ public class Chest : Entity, IInteractionInterface
|
||||||
|
|
||||||
|
|
||||||
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||||
int shapeIndex)
|
int shapeIndex) {
|
||||||
{
|
if (IsMouseOver && inputEvent is InputEventMouseButton) {
|
||||||
if (IsMouseOver && inputEvent is InputEventMouseButton)
|
|
||||||
{
|
|
||||||
InputEventMouseButton mouseButtonEvent = (InputEventMouseButton)inputEvent;
|
InputEventMouseButton mouseButtonEvent = (InputEventMouseButton)inputEvent;
|
||||||
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed)
|
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed) {
|
||||||
{
|
|
||||||
EmitSignal("EntityClicked", this);
|
EmitSignal("EntityClicked", this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void OnAreaMouseEntered()
|
public void OnAreaMouseEntered() {
|
||||||
{
|
|
||||||
IsMouseOver = true;
|
IsMouseOver = true;
|
||||||
SpatialMaterial overrideMaterial = new SpatialMaterial();
|
SpatialMaterial overrideMaterial = new();
|
||||||
overrideMaterial.AlbedoColor = new Color(1, 0, 0);
|
overrideMaterial.AlbedoColor = new Color(1, 0, 0);
|
||||||
_mesh.MaterialOverride = overrideMaterial;
|
_mesh.MaterialOverride = overrideMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void OnAreaMouseExited()
|
public void OnAreaMouseExited() {
|
||||||
{
|
|
||||||
IsMouseOver = false;
|
IsMouseOver = false;
|
||||||
_mesh.MaterialOverride = null;
|
_mesh.MaterialOverride = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void OnInteractionStart()
|
public void OnInteractionStart() {
|
||||||
{
|
|
||||||
_animationPlayer.Stop();
|
_animationPlayer.Stop();
|
||||||
|
|
||||||
if (State == LidState.Closed)
|
if (State == LidState.Closed) {
|
||||||
{
|
|
||||||
State = LidState.Open;
|
State = LidState.Open;
|
||||||
_animationPlayer.Play("ChestOpen");
|
_animationPlayer.Play("ChestOpen");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
_animationPlayer.PlayBackwards("ChestOpen");
|
_animationPlayer.PlayBackwards("ChestOpen");
|
||||||
State = LidState.Closed;
|
State = LidState.Closed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void OnInteractionEnd()
|
public void OnInteractionEnd() { }
|
||||||
{
|
|
||||||
|
|
||||||
}
|
public void OnChestOpened() {
|
||||||
|
|
||||||
public void OnChestOpened()
|
|
||||||
{
|
|
||||||
GD.Print("Chest now opened!");
|
GD.Print("Chest now opened!");
|
||||||
foreach (int i in Enumerable.Range(0, 10))
|
foreach (int i in Enumerable.Range(0, 10)) {
|
||||||
{
|
|
||||||
GoldBar bar = (GoldBar)_goldBarScene.Instance();
|
GoldBar bar = (GoldBar)_goldBarScene.Instance();
|
||||||
bar.Transform = new Transform(Transform.basis.Rotated(Vector3.Up, GD.Randf() * 2 * Mathf.Pi), Transform.origin + Vector3.Up * 0.8f);
|
bar.Transform = new Transform(Transform.basis.Rotated(Vector3.Up, GD.Randf() * 2 * Mathf.Pi),
|
||||||
bar.velocity = new Vector3(
|
Transform.origin + Vector3.Up * 0.8f);
|
||||||
|
bar.Velocity = new Vector3(
|
||||||
(GD.Randf() * 2f - 1f) * 2,
|
(GD.Randf() * 2f - 1f) * 2,
|
||||||
5 + GD.Randf() * 0.3f,
|
5 + GD.Randf() * 0.3f,
|
||||||
(GD.Randf() * 2f - 1f) * 2
|
(GD.Randf() * 2f - 1f) * 2
|
||||||
|
@ -108,8 +92,7 @@ public class Chest : Entity, IInteractionInterface
|
||||||
GetParent().AddChild(bar);
|
GetParent().AddChild(bar);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (InteractionComponent != null)
|
if (InteractionComponent != null) {
|
||||||
{
|
|
||||||
InteractionComponent.EndInteraction();
|
InteractionComponent.EndInteraction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,8 +79,8 @@ tracks/2/keys = {
|
||||||
|
|
||||||
[sub_resource type="PrismMesh" id=15]
|
[sub_resource type="PrismMesh" id=15]
|
||||||
|
|
||||||
[sub_resource type="BoxShape" id=16]
|
[sub_resource type="SphereShape" id=19]
|
||||||
extents = Vector3( 0.19, 0.19, 0.33 )
|
radius = 0.359562
|
||||||
|
|
||||||
[sub_resource type="CubeMesh" id=17]
|
[sub_resource type="CubeMesh" id=17]
|
||||||
size = Vector3( 0.38, 0.38, 0.66 )
|
size = Vector3( 0.38, 0.38, 0.66 )
|
||||||
|
@ -133,8 +133,8 @@ skeleton = NodePath("../..")
|
||||||
[node name="ResourceContainer" type="Node" parent="."]
|
[node name="ResourceContainer" type="Node" parent="."]
|
||||||
|
|
||||||
[node name="CollisionShape" type="CollisionShape" parent="."]
|
[node name="CollisionShape" type="CollisionShape" parent="."]
|
||||||
transform = Transform( -0.866026, 0, 0.5, 0, 1, 0, -0.5, 0, -0.866026, 0, 0.240716, 0 )
|
transform = Transform( -0.866026, 0, 0.5, 0, 1, 0, -0.5, 0, -0.866026, 0, 0.110576, 0 )
|
||||||
shape = SubResource( 16 )
|
shape = SubResource( 19 )
|
||||||
|
|
||||||
[node name="MeshInstance" type="MeshInstance" parent="CollisionShape" groups=["PhysicsGeometry"]]
|
[node name="MeshInstance" type="MeshInstance" parent="CollisionShape" groups=["PhysicsGeometry"]]
|
||||||
mesh = SubResource( 17 )
|
mesh = SubResource( 17 )
|
||||||
|
|
|
@ -1,30 +1,61 @@
|
||||||
using Godot;
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
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 Vector3 Velocity { get; set; } = Vector3.Zero;
|
||||||
public float RotationalVelocity { get; set; } = 0;
|
public float RotationalVelocity { get; set; } = 0;
|
||||||
|
|
||||||
/** Defines the angle in plane coordinates, 0 => pointing to the right/east, pi/2 pointing up/north, range [-pi,pi]. */
|
private CollectibleComponent _collectibleComponent;
|
||||||
public float PlaneAngle
|
|
||||||
{
|
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 {
|
||||||
get => Globals.CalcPlaneAngle(GlobalTransform);
|
get => Globals.CalcPlaneAngle(GlobalTransform);
|
||||||
set => GlobalTransform = new Transform(new Basis(Vector3.Up, value + Mathf.Pi * 0.5f), GlobalTranslation);
|
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 angleToTarget = Vector3.Right.SignedAngleTo(globalTargetDirection, Vector3.Up);
|
||||||
float currentAngle = PlaneAngle;
|
float currentAngle = PlaneAngle;
|
||||||
|
|
||||||
float delta = angleToTarget - currentAngle;
|
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;
|
return delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Ready()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,61 +1 @@
|
||||||
using Godot;
|
public class GoldBar : Entity { }
|
||||||
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,7 +1,8 @@
|
||||||
[gd_scene load_steps=4 format=2]
|
[gd_scene load_steps=5 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://entities/GoldBar.cs" type="Script" id=1]
|
[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://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]
|
[sub_resource type="BoxShape" id=21]
|
||||||
extents = Vector3( 0.354271, 0.0817164, 0.173406 )
|
extents = Vector3( 0.354271, 0.0817164, 0.173406 )
|
||||||
|
@ -16,8 +17,10 @@ script = ExtResource( 1 )
|
||||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.084728, 0 )
|
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.084728, 0 )
|
||||||
shape = SubResource( 21 )
|
shape = SubResource( 21 )
|
||||||
|
|
||||||
[node name="Spatial" type="Spatial" parent="."]
|
[node name="Geometry" type="Spatial" parent="."]
|
||||||
transform = Transform( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0 )
|
transform = Transform( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0 )
|
||||||
|
|
||||||
[node name="Gold_Bar" parent="Spatial" instance=ExtResource( 2 )]
|
[node name="Gold_Bar" parent="Geometry" instance=ExtResource( 2 )]
|
||||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 21.335, -0.022, -6.533 )
|
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,14 +2,9 @@ using GodotComponentTest.components;
|
||||||
|
|
||||||
namespace GodotComponentTest.entities;
|
namespace GodotComponentTest.entities;
|
||||||
|
|
||||||
public interface IInteractionInterface
|
public interface IInteractionInterface {
|
||||||
{
|
|
||||||
void OnInteractionStart();
|
void OnInteractionStart();
|
||||||
void OnInteractionEnd();
|
void OnInteractionEnd();
|
||||||
|
|
||||||
InteractionComponent InteractionComponent
|
InteractionComponent InteractionComponent { get; set; }
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -5,16 +5,21 @@ using GodotComponentTest.components;
|
||||||
using GodotComponentTest.entities;
|
using GodotComponentTest.entities;
|
||||||
using GodotComponentTest.utils;
|
using GodotComponentTest.utils;
|
||||||
|
|
||||||
public class Player : Entity, IInteractionInterface
|
public class Player : Entity, IInteractionInterface {
|
||||||
{
|
|
||||||
// public members
|
// public members
|
||||||
[Export] public NodePath WorldNode;
|
[Export] public NodePath WorldNode;
|
||||||
|
|
||||||
|
public int WoodCount;
|
||||||
public int GoldCount;
|
public int GoldCount;
|
||||||
|
public bool HasAxe;
|
||||||
|
|
||||||
public TaskQueueComponent TaskQueueComponent;
|
public TaskQueueComponent TaskQueueComponent;
|
||||||
public NavigationComponent NavigationComponent { get; private set; }
|
public NavigationComponent NavigationComponent { get; private set; }
|
||||||
public InteractionComponent InteractionComponent { get; set; }
|
public InteractionComponent InteractionComponent { get; set; }
|
||||||
|
|
||||||
|
[Signal]
|
||||||
|
private delegate void WoodCountChanged(int woodCount);
|
||||||
|
|
||||||
[Signal]
|
[Signal]
|
||||||
private delegate void GoldCountChanged(int goldCount);
|
private delegate void GoldCountChanged(int goldCount);
|
||||||
|
|
||||||
|
@ -30,8 +35,7 @@ public class Player : Entity, IInteractionInterface
|
||||||
private BoneAttachment _toolAttachement;
|
private BoneAttachment _toolAttachement;
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
_groundMotion = new GroundMotionComponent();
|
_groundMotion = new GroundMotionComponent();
|
||||||
_worldInfo = (WorldInfoComponent)FindNode("WorldInfo", false);
|
_worldInfo = (WorldInfoComponent)FindNode("WorldInfo", false);
|
||||||
NavigationComponent = (NavigationComponent)FindNode("Navigation", false);
|
NavigationComponent = (NavigationComponent)FindNode("Navigation", false);
|
||||||
|
@ -39,33 +43,28 @@ public class Player : Entity, IInteractionInterface
|
||||||
TaskQueueComponent = new TaskQueueComponent();
|
TaskQueueComponent = new TaskQueueComponent();
|
||||||
|
|
||||||
_itemAttractorArea = (Area)FindNode("ItemAttractorArea", false);
|
_itemAttractorArea = (Area)FindNode("ItemAttractorArea", false);
|
||||||
if (_itemAttractorArea == null)
|
if (_itemAttractorArea == null) {
|
||||||
{
|
|
||||||
GD.PushWarning("No ItemAttractorArea node found for " + GetClass());
|
GD.PushWarning("No ItemAttractorArea node found for " + GetClass());
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
_itemAttractorArea.Connect("body_entered", this, nameof(OnItemAttractorBodyEntered));
|
_itemAttractorArea.Connect("body_entered", this, nameof(OnItemAttractorBodyEntered));
|
||||||
_itemAttractorArea.Connect("body_exited", this, nameof(OnItemAttractorBodyExited));
|
_itemAttractorArea.Connect("body_exited", this, nameof(OnItemAttractorBodyExited));
|
||||||
}
|
}
|
||||||
|
|
||||||
_itemPickupArea = (Area)FindNode("ItemPickupArea", false);
|
_itemPickupArea = (Area)FindNode("ItemPickupArea", false);
|
||||||
if (_itemPickupArea == null)
|
if (_itemPickupArea == null) {
|
||||||
GD.PushWarning("No ItemPickupArea node found for " + GetClass());
|
GD.PushWarning("No ItemPickupArea node found for " + GetClass());
|
||||||
else
|
} else {
|
||||||
_itemPickupArea.Connect("body_entered", this, nameof(OnItemPickupAreaBodyEntered));
|
_itemPickupArea.Connect("body_entered", this, nameof(OnItemPickupAreaBodyEntered));
|
||||||
|
}
|
||||||
|
|
||||||
_playerAnimationPlayer = GetNode<AnimationPlayer>("Geometry/AnimationPlayer");
|
|
||||||
Debug.Assert(_playerAnimationPlayer != null);
|
|
||||||
_animationTree = GetNode<AnimationTree>("Geometry/AnimationTree");
|
_animationTree = GetNode<AnimationTree>("Geometry/AnimationTree");
|
||||||
Debug.Assert(_animationTree != null);
|
Debug.Assert(_animationTree != null);
|
||||||
var stateMachine =
|
AnimationNodeStateMachinePlayback stateMachine =
|
||||||
(AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
|
(AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
|
||||||
stateMachine.Start("Idle");
|
stateMachine.Start("Idle");
|
||||||
|
|
||||||
_toolAttachement = (BoneAttachment)FindNode("ToolAttachement");
|
_toolAttachement = (BoneAttachment)FindNode("ToolAttachement");
|
||||||
if (_toolAttachement == null)
|
if (_toolAttachement == null) {
|
||||||
{
|
|
||||||
GD.PushWarning("No ToolAttachement found!");
|
GD.PushWarning("No ToolAttachement found!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,25 +72,20 @@ public class Player : Entity, IInteractionInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void _PhysicsProcess(float delta)
|
public override void _PhysicsProcess(float delta) {
|
||||||
{
|
|
||||||
base._PhysicsProcess(delta);
|
base._PhysicsProcess(delta);
|
||||||
|
|
||||||
if (NavigationComponent == null)
|
if (NavigationComponent == null) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TaskQueueComponent != null && TaskQueueComponent.Queue.Count > 0)
|
if (TaskQueueComponent != null && TaskQueueComponent.Queue.Count > 0) {
|
||||||
{
|
|
||||||
TaskQueueComponent.Process(this, delta);
|
TaskQueueComponent.Process(this, delta);
|
||||||
|
|
||||||
if (TaskQueueComponent.Queue.Count > 0)
|
if (TaskQueueComponent.Queue.Count > 0) {
|
||||||
{
|
TaskQueueComponent.Task currentTask = TaskQueueComponent.Queue.Peek();
|
||||||
var currentTask = TaskQueueComponent.Queue.Peek();
|
|
||||||
TaskQueueComponent.NavigationTask navigationTask = currentTask as TaskQueueComponent.NavigationTask;
|
TaskQueueComponent.NavigationTask navigationTask = currentTask as TaskQueueComponent.NavigationTask;
|
||||||
if (navigationTask != null && navigationTask.PlanningComplete == false)
|
if (navigationTask != null && navigationTask.PlanningComplete == false) {
|
||||||
{
|
|
||||||
// _navigationComponent.PlanGridPath(this, GlobalTransform, navigationTask.NavigationPoint);
|
// _navigationComponent.PlanGridPath(this, GlobalTransform, navigationTask.NavigationPoint);
|
||||||
NavigationComponent.PlanSmoothedPath(this, GlobalTransform, navigationTask.NavigationPoint);
|
NavigationComponent.PlanSmoothedPath(this, GlobalTransform, navigationTask.NavigationPoint);
|
||||||
|
|
||||||
|
@ -103,115 +97,112 @@ public class Player : Entity, IInteractionInterface
|
||||||
_groundMotion.PhysicsProcess(delta, this, NavigationComponent.CurrentGoalPositionWorld,
|
_groundMotion.PhysicsProcess(delta, this, NavigationComponent.CurrentGoalPositionWorld,
|
||||||
NavigationComponent.CurrentGoalAngleWorld, _worldInfo.World);
|
NavigationComponent.CurrentGoalAngleWorld, _worldInfo.World);
|
||||||
|
|
||||||
if (NavigationComponent.IsGoalReached())
|
if (NavigationComponent.IsGoalReached()) {
|
||||||
navigationTask.NavigationPoint = new NavigationPoint(GlobalTransform);
|
navigationTask.NavigationPoint = new NavigationPoint(GlobalTransform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void _Process(float delta)
|
public override void _Process(float delta) {
|
||||||
{
|
if (NavigationComponent != null) {
|
||||||
if (NavigationComponent != null)
|
|
||||||
{
|
|
||||||
NavigationComponent.UpdateCurrentGoal(GlobalTransform);
|
NavigationComponent.UpdateCurrentGoal(GlobalTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Node node in _attractedItemList)
|
foreach (Node node in _attractedItemList) {
|
||||||
{
|
Entity entity = node as Entity;
|
||||||
if (node is GoldBar)
|
if (entity != null) {
|
||||||
{
|
CollectibleComponent collectibleComponent = entity.GetCollectibleComponent();
|
||||||
GoldBar bar = (GoldBar)node;
|
if (collectibleComponent != null) {
|
||||||
bar.SetTarget(GlobalTransform.origin);
|
collectibleComponent.SetTarget(GlobalTransform.origin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateDebugGeometry();
|
UpdateDebugGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateDebugGeometry()
|
public void UpdateDebugGeometry() {
|
||||||
{
|
if (_debugGeometry == null || _debugGeometry.Visible == false) {
|
||||||
if (_debugGeometry == null || _debugGeometry.Visible == false)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_debugGeometry.Clear();
|
_debugGeometry.Clear();
|
||||||
_debugGeometry.GlobalTransform = Transform.Identity;
|
_debugGeometry.GlobalTransform = Transform.Identity;
|
||||||
|
|
||||||
if (NavigationComponent != null)
|
if (NavigationComponent != null) {
|
||||||
{
|
|
||||||
NavigationComponent.DebugDraw(this, _debugGeometry);
|
NavigationComponent.DebugDraw(this, _debugGeometry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnItemAttractorBodyEntered(Node node)
|
public void OnItemAttractorBodyEntered(Node node) {
|
||||||
{
|
|
||||||
_attractedItemList.Add(node);
|
_attractedItemList.Add(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnItemAttractorBodyExited(Node node)
|
public void OnItemAttractorBodyExited(Node node) {
|
||||||
{
|
Entity entity = node as Entity;
|
||||||
if (node is GoldBar)
|
if (entity != null) {
|
||||||
{
|
CollectibleComponent collectibleComponent = entity.GetCollectibleComponent();
|
||||||
GoldBar bar = (GoldBar)node;
|
if (collectibleComponent != null) {
|
||||||
bar.UnsetTarget();
|
collectibleComponent.UnsetTarget();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_attractedItemList.Remove(node);
|
_attractedItemList.Remove(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnItemPickupAreaBodyEntered(Node body)
|
public void OnItemPickupAreaBodyEntered(Node body) {
|
||||||
{
|
|
||||||
GD.Print("Picking up item: " + body.Name);
|
GD.Print("Picking up item: " + body.Name);
|
||||||
|
|
||||||
if (body is Axe)
|
if (body is Axe) {
|
||||||
{
|
|
||||||
SetActiveTool("Axe");
|
SetActiveTool("Axe");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (body is GoldBar)
|
if (body is GoldBar) {
|
||||||
{
|
|
||||||
GoldCount++;
|
GoldCount++;
|
||||||
EmitSignal("GoldCountChanged", GoldCount);
|
EmitSignal("GoldCountChanged", GoldCount);
|
||||||
|
} else if (body is Wood) {
|
||||||
|
WoodCount++;
|
||||||
|
EmitSignal("WoodCountChanged", WoodCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.QueueFree();
|
body.QueueFree();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetActiveTool(string toolName)
|
public void SetActiveTool(string toolName) {
|
||||||
{
|
|
||||||
Debug.Assert(_toolAttachement != null);
|
Debug.Assert(_toolAttachement != null);
|
||||||
if (toolName == "Axe")
|
if (toolName == "Axe") {
|
||||||
{
|
|
||||||
_toolAttachement.Visible = true;
|
_toolAttachement.Visible = true;
|
||||||
}
|
HasAxe = true;
|
||||||
else if (toolName == "")
|
} else if (toolName == "") {
|
||||||
{
|
|
||||||
_toolAttachement.Visible = false;
|
_toolAttachement.Visible = false;
|
||||||
|
HasAxe = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnInteractionStart()
|
public void OnInteractionStart() {
|
||||||
{
|
|
||||||
AnimationNodeStateMachinePlayback stateMachine =
|
AnimationNodeStateMachinePlayback stateMachine =
|
||||||
(AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
|
(AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
|
||||||
Debug.Assert(stateMachine != null);
|
Debug.Assert(stateMachine != null);
|
||||||
|
|
||||||
if (InteractionComponent.TargetEntity is Chest)
|
if (InteractionComponent.TargetEntity is Chest) {
|
||||||
{
|
|
||||||
GD.Print("Player Opening Box");
|
GD.Print("Player Opening Box");
|
||||||
stateMachine.Travel("Interaction");
|
stateMachine.Travel("Interaction");
|
||||||
|
} else if (InteractionComponent.TargetEntity is Tree) {
|
||||||
|
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");
|
GD.Print("Player Chopping Tree");
|
||||||
stateMachine.Travel("Hit");
|
stateMachine.Travel("Hit");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnInteractionEnd()
|
public void OnInteractionEnd() {
|
||||||
{
|
|
||||||
GD.Print("Player Stopping Interaction");
|
GD.Print("Player Stopping Interaction");
|
||||||
AnimationNodeStateMachinePlayback stateMachine =
|
AnimationNodeStateMachinePlayback stateMachine =
|
||||||
(AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
|
(AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=27 format=2]
|
[gd_scene load_steps=26 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://entities/Player.cs" type="Script" id=1]
|
[ext_resource path="res://entities/Player.cs" type="Script" id=1]
|
||||||
[ext_resource path="res://components/NavigationComponent.cs" type="Script" id=2]
|
[ext_resource path="res://components/NavigationComponent.cs" type="Script" id=2]
|
||||||
|
@ -28,277 +28,6 @@ radius = 0.1
|
||||||
flags_unshaded = true
|
flags_unshaded = true
|
||||||
vertex_color_use_as_albedo = 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]
|
[sub_resource type="AnimationNodeAnimation" id=1]
|
||||||
animation = "Hit-loop"
|
animation = "Hit-loop"
|
||||||
|
|
||||||
|
@ -308,6 +37,9 @@ animation = "Idle-loop"
|
||||||
[sub_resource type="AnimationNodeAnimation" id=3]
|
[sub_resource type="AnimationNodeAnimation" id=3]
|
||||||
animation = "Interaction-loop"
|
animation = "Interaction-loop"
|
||||||
|
|
||||||
|
[sub_resource type="AnimationNodeAnimation" id=35]
|
||||||
|
animation = "Shrug-loop"
|
||||||
|
|
||||||
[sub_resource type="AnimationNodeStateMachineTransition" id=4]
|
[sub_resource type="AnimationNodeStateMachineTransition" id=4]
|
||||||
|
|
||||||
[sub_resource type="AnimationNodeStateMachineTransition" id=5]
|
[sub_resource type="AnimationNodeStateMachineTransition" id=5]
|
||||||
|
@ -321,15 +53,26 @@ xfade_time = 0.1
|
||||||
switch_mode = 2
|
switch_mode = 2
|
||||||
xfade_time = 0.3
|
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]
|
[sub_resource type="AnimationNodeStateMachine" id=8]
|
||||||
states/Hit/node = SubResource( 1 )
|
states/Hit/node = SubResource( 1 )
|
||||||
states/Hit/position = Vector2( 415, 45 )
|
states/Hit/position = Vector2( 413, 37 )
|
||||||
states/Idle/node = SubResource( 2 )
|
states/Idle/node = SubResource( 2 )
|
||||||
states/Idle/position = Vector2( 149, 39 )
|
states/Idle/position = Vector2( 157, 37 )
|
||||||
states/Interaction/node = SubResource( 3 )
|
states/Interaction/node = SubResource( 3 )
|
||||||
states/Interaction/position = Vector2( 176, 157 )
|
states/Interaction/position = Vector2( 157, 162 )
|
||||||
transitions = [ "Idle", "Hit", SubResource( 4 ), "Hit", "Idle", SubResource( 5 ), "Idle", "Interaction", SubResource( 6 ), "Interaction", "Idle", SubResource( 33 ) ]
|
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 ) ]
|
||||||
start_node = "Idle"
|
start_node = "Idle"
|
||||||
|
graph_offset = Vector2( -175, -42 )
|
||||||
|
|
||||||
[sub_resource type="AnimationNodeStateMachinePlayback" id=34]
|
[sub_resource type="AnimationNodeStateMachinePlayback" id=34]
|
||||||
|
|
||||||
|
@ -397,27 +140,17 @@ generate_lightmap = false
|
||||||
[node name="PirateAsset" parent="Geometry" instance=ExtResource( 8 )]
|
[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 )
|
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"]
|
[node name="ToolAttachement" type="BoneAttachment" parent="Geometry/PirateAsset/Armature/Skeleton" index="5"]
|
||||||
transform = Transform( 1, 7.13626e-08, -4.47035e-08, 1.64262e-07, -1, -1.00583e-07, 1.19209e-07, 1.18278e-07, -1, -0.72, 0.45, 1.78362e-08 )
|
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 )
|
||||||
visible = false
|
visible = false
|
||||||
bone_name = "HandTip.R"
|
bone_name = "HandTip.R"
|
||||||
|
|
||||||
[node name="toolAxe" parent="Geometry/PirateAsset/Armature/Skeleton/ToolAttachement" instance=ExtResource( 4 )]
|
[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 )
|
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"]
|
[node name="AnimationTree" type="AnimationTree" parent="Geometry"]
|
||||||
tree_root = SubResource( 8 )
|
tree_root = SubResource( 8 )
|
||||||
anim_player = NodePath("../AnimationPlayer")
|
anim_player = NodePath("../PirateAsset/AnimationPlayer")
|
||||||
active = true
|
active = true
|
||||||
parameters/playback = SubResource( 34 )
|
parameters/playback = SubResource( 34 )
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using Godot;
|
using Godot;
|
||||||
using GodotComponentTest.components;
|
using GodotComponentTest.components;
|
||||||
using GodotComponentTest.entities;
|
using GodotComponentTest.entities;
|
||||||
|
|
||||||
public class Tree : StaticBody, IInteractionInterface
|
public class Tree : StaticBody, IInteractionInterface {
|
||||||
{
|
private readonly PackedScene _woodScene = GD.Load<PackedScene>("res://entities/Wood.tscn");
|
||||||
|
|
||||||
[Export] public float ChopDuration = 2;
|
[Export] public float ChopDuration = 2;
|
||||||
public bool IsMouseOver;
|
public bool IsMouseOver;
|
||||||
public InteractionComponent InteractionComponent { get; set; }
|
public InteractionComponent InteractionComponent { get; set; }
|
||||||
|
@ -14,13 +16,16 @@ public class Tree : StaticBody, IInteractionInterface
|
||||||
private AnimationPlayer _animationPlayer;
|
private AnimationPlayer _animationPlayer;
|
||||||
private float _health = 100;
|
private float _health = 100;
|
||||||
private bool _isBeingChopped;
|
private bool _isBeingChopped;
|
||||||
|
private bool _isDead;
|
||||||
|
|
||||||
[Signal]
|
[Signal]
|
||||||
public delegate void EntityClicked(Entity entity);
|
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.
|
// 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");
|
_geometry = GetNode<MeshInstance>("Geometry/tree");
|
||||||
Debug.Assert(_geometry != null);
|
Debug.Assert(_geometry != null);
|
||||||
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
|
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
|
||||||
|
@ -33,56 +38,61 @@ public class Tree : StaticBody, IInteractionInterface
|
||||||
Connect("mouse_exited", this, nameof(OnAreaMouseExited));
|
Connect("mouse_exited", this, nameof(OnAreaMouseExited));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void _Process(float delta) {
|
||||||
public override void _Process(float delta)
|
|
||||||
{
|
|
||||||
base._Process(delta);
|
base._Process(delta);
|
||||||
|
|
||||||
if (_isBeingChopped)
|
if (_isBeingChopped) {
|
||||||
{
|
|
||||||
_health = Math.Max(0, _health - delta * 100 / ChopDuration);
|
_health = Math.Max(0, _health - delta * 100 / ChopDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_health == 0)
|
if (!_isDead && _health == 0) {
|
||||||
{
|
|
||||||
InteractionComponent.EndInteraction();
|
InteractionComponent.EndInteraction();
|
||||||
InteractionComponent.TargetEntity = null;
|
InteractionComponent.TargetEntity = null;
|
||||||
QueueFree();
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||||
int shapeIndex)
|
int shapeIndex) {
|
||||||
{
|
if (IsMouseOver && inputEvent is InputEventMouseButton) {
|
||||||
if (IsMouseOver && inputEvent is InputEventMouseButton)
|
|
||||||
{
|
|
||||||
InputEventMouseButton mouseButtonEvent = (InputEventMouseButton)inputEvent;
|
InputEventMouseButton mouseButtonEvent = (InputEventMouseButton)inputEvent;
|
||||||
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed)
|
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed) {
|
||||||
{
|
|
||||||
EmitSignal("EntityClicked", this);
|
EmitSignal("EntityClicked", this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnAreaMouseEntered() {
|
||||||
public void OnAreaMouseEntered()
|
|
||||||
{
|
|
||||||
IsMouseOver = true;
|
IsMouseOver = true;
|
||||||
SpatialMaterial overrideMaterial = new SpatialMaterial();
|
SpatialMaterial overrideMaterial = new();
|
||||||
overrideMaterial.AlbedoColor = new Color(1, 0, 0);
|
overrideMaterial.AlbedoColor = new Color(1, 0, 0);
|
||||||
_geometry.MaterialOverride = overrideMaterial;
|
_geometry.MaterialOverride = overrideMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnAreaMouseExited() {
|
||||||
public void OnAreaMouseExited()
|
|
||||||
{
|
|
||||||
IsMouseOver = false;
|
IsMouseOver = false;
|
||||||
_geometry.MaterialOverride = null;
|
_geometry.MaterialOverride = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnInteractionStart() {
|
||||||
public void OnInteractionStart()
|
|
||||||
{
|
|
||||||
GD.Print("Starting tree animationplayer");
|
GD.Print("Starting tree animationplayer");
|
||||||
_animationPlayer.CurrentAnimation = "TreeShake";
|
_animationPlayer.CurrentAnimation = "TreeShake";
|
||||||
_animationPlayer.Seek(0);
|
_animationPlayer.Seek(0);
|
||||||
|
@ -90,8 +100,7 @@ public class Tree : StaticBody, IInteractionInterface
|
||||||
_isBeingChopped = true;
|
_isBeingChopped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnInteractionEnd()
|
public void OnInteractionEnd() {
|
||||||
{
|
|
||||||
_animationPlayer.CurrentAnimation = "Idle";
|
_animationPlayer.CurrentAnimation = "Idle";
|
||||||
_animationPlayer.Seek(0);
|
_animationPlayer.Seek(0);
|
||||||
_animationPlayer.Stop();
|
_animationPlayer.Stop();
|
||||||
|
|
|
@ -88,7 +88,6 @@ script = ExtResource( 3 )
|
||||||
|
|
||||||
[node name="MountPoint" type="Spatial" parent="."]
|
[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 )
|
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"]
|
[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 )
|
transform = Transform( -1, 0, -8.74227e-08, 0, 1, 0, 8.74227e-08, 0, -1, 2.38419e-07, 0, 0 )
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
public class Wood : Entity { }
|
|
@ -0,0 +1,25 @@
|
||||||
|
[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 )]
|
|
@ -0,0 +1,49 @@
|
||||||
|
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)
|
||||||
|
// {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
[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_user="androiddebugkey"
|
||||||
keystore/release_password="android"
|
keystore/release_password="android"
|
||||||
one_click_deploy/clear_previous_install=true
|
one_click_deploy/clear_previous_install=true
|
||||||
version/code=1
|
version/code=5
|
||||||
version/name="1.0"
|
version/name="1.0"
|
||||||
package/unique_name="org.godotengine.$genname"
|
package/unique_name="org.godotengine.$genname"
|
||||||
package/name=""
|
package/name=""
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
[gd_resource type="ShaderMaterial" load_steps=2 format=2]
|
[gd_resource type="ShaderMaterial" load_steps=2 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://materials/shader/IslandColorRampShader.gdshader" type="Shader" id=1]
|
[ext_resource path="res://materials/shader/WorldTileTypeShader.gdshader" type="Shader" id=1]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
shader = ExtResource( 1 )
|
shader = ExtResource( 1 )
|
||||||
shader_param/DeepWaterColor = Color( 0, 0, 0.6, 1 )
|
shader_param/DeepWaterColor = Color( 0, 0, 0.6, 1 )
|
||||||
shader_param/WaterColor = Color( 0, 0, 0.7, 1 )
|
shader_param/WaterColor = Color( 0, 0, 0.698039, 1 )
|
||||||
shader_param/LightWaterColor = Color( 0, 0, 1, 1 )
|
shader_param/LightWaterColor = Color( 0, 0, 1, 1 )
|
||||||
shader_param/SandColor = Color( 0.8, 0.8, 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/GrassColor = Color( 0, 0.6, 0, 1 )
|
|
@ -0,0 +1,166 @@
|
||||||
|
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);
|
||||||
|
}
|
|
@ -56,7 +56,7 @@ void fragment() {
|
||||||
|
|
||||||
// COLOR.rgb = color_ramp(texture_color.r * borderFalloffCircle(UV) * 1.8);
|
// COLOR.rgb = color_ramp(texture_color.r * borderFalloffCircle(UV) * 1.8);
|
||||||
COLOR.rgb = color_ramp(texture_color.r * texture(TextureMask, UV).r);
|
COLOR.rgb = color_ramp(texture_color.r * texture(TextureMask, UV).r);
|
||||||
COLOR.a = 0.8;
|
COLOR.a = 1.0;
|
||||||
// COLOR.rgb = vec3(1, 0, 0);
|
// COLOR.rgb = vec3(1, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,17 +9,17 @@
|
||||||
config_version=4
|
config_version=4
|
||||||
|
|
||||||
_global_script_classes=[ {
|
_global_script_classes=[ {
|
||||||
"base": "Reference",
|
"base": "Node",
|
||||||
"class": "ClickableComponent",
|
"class": "ClickableComponent",
|
||||||
"language": "GDScript",
|
"language": "GDScript",
|
||||||
"path": "res://components/ClickableComponent.gd"
|
"path": "res://components/ClickableComponent.gd"
|
||||||
}, {
|
}, {
|
||||||
"base": "Reference",
|
"base": "KinematicBody2D",
|
||||||
"class": "CollisionLine",
|
"class": "CollisionLine",
|
||||||
"language": "GDScript",
|
"language": "GDScript",
|
||||||
"path": "res://utils/CollisionLine.gd"
|
"path": "res://utils/CollisionLine.gd"
|
||||||
}, {
|
}, {
|
||||||
"base": "Reference",
|
"base": "Node",
|
||||||
"class": "ColorComponent",
|
"class": "ColorComponent",
|
||||||
"language": "GDScript",
|
"language": "GDScript",
|
||||||
"path": "res://components/ColorComponent.gd"
|
"path": "res://components/ColorComponent.gd"
|
||||||
|
@ -54,7 +54,7 @@ _global_script_classes=[ {
|
||||||
"language": "GDScript",
|
"language": "GDScript",
|
||||||
"path": "res://utils/SpringDamper.gd"
|
"path": "res://utils/SpringDamper.gd"
|
||||||
}, {
|
}, {
|
||||||
"base": "Reference",
|
"base": "Sprite",
|
||||||
"class": "TintedSpriteComponent",
|
"class": "TintedSpriteComponent",
|
||||||
"language": "GDScript",
|
"language": "GDScript",
|
||||||
"path": "res://components/TintedSpriteComponent.gd"
|
"path": "res://components/TintedSpriteComponent.gd"
|
||||||
|
@ -114,6 +114,11 @@ 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)
|
"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]
|
[layer_names]
|
||||||
|
|
||||||
|
@ -134,5 +139,9 @@ common/enable_pause_aware_picking=true
|
||||||
|
|
||||||
quality/directional_shadow/size.mobile=512
|
quality/directional_shadow/size.mobile=512
|
||||||
quality/shadow_atlas/size.mobile=1024
|
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
|
quality/subsurface_scattering/quality=0
|
||||||
environment/default_environment="res://default_env.tres"
|
environment/default_environment="res://default_env.tres"
|
||||||
|
|
189
scenes/Game.cs
189
scenes/Game.cs
|
@ -1,8 +1,14 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public class Game : Spatial
|
public class Game : Spatial {
|
||||||
{
|
private enum ActionMode {
|
||||||
|
Default,
|
||||||
|
Building
|
||||||
|
}
|
||||||
|
|
||||||
|
private ActionMode _actionMode = ActionMode.Default;
|
||||||
|
|
||||||
private ImageTexture _blackWhitePatternTexture;
|
private ImageTexture _blackWhitePatternTexture;
|
||||||
private Camera _camera;
|
private Camera _camera;
|
||||||
private Vector3 _cameraOffset;
|
private Vector3 _cameraOffset;
|
||||||
|
@ -13,59 +19,58 @@ public class Game : Spatial
|
||||||
// ui elements
|
// ui elements
|
||||||
private Label _framesPerSecondLabel;
|
private Label _framesPerSecondLabel;
|
||||||
private Control _gameUi;
|
private Control _gameUi;
|
||||||
private Button _generateWorldButton;
|
private Label _woodCountLabel;
|
||||||
private Label _goldCountLabel;
|
private Label _goldCountLabel;
|
||||||
private TextureRect _heightTextureRect;
|
private TextureRect _heightTextureRect;
|
||||||
|
private Button _walkActionButton;
|
||||||
|
private Button _buildActionButton;
|
||||||
|
|
||||||
// other members
|
// other members
|
||||||
private HexGrid _hexGrid;
|
private HexGrid _hexGrid;
|
||||||
private InteractionSystem _interactionSystem;
|
private InteractionSystem _interactionSystem;
|
||||||
private HexCell _lastTile;
|
|
||||||
private Label _mouseTileCubeLabel;
|
private Label _mouseTileCubeLabel;
|
||||||
private Label _mouseTileAxialLabel;
|
private Label _mouseTileAxialLabel;
|
||||||
private Spatial _mouseTileHighlight;
|
private Spatial _mouseTileHighlight;
|
||||||
private Label _mouseTileOffsetLabel;
|
private Label _mouseTileOffsetLabel;
|
||||||
private Label _mouseWorldLabel;
|
private Label _mouseWorldLabel;
|
||||||
private Label _numCoordsAddedLabel;
|
|
||||||
private Label _numCoordsRemovedLabel;
|
|
||||||
private Label _numTilesLabel;
|
|
||||||
private Player _player;
|
private Player _player;
|
||||||
|
|
||||||
// scene nodes
|
// scene nodes
|
||||||
private Spatial _tileHighlight;
|
private Spatial _tileHighlight;
|
||||||
|
|
||||||
// Resources
|
// Resources
|
||||||
private PackedScene _tileHighlightScene;
|
|
||||||
private ShaderMaterial _tileMaterial;
|
private ShaderMaterial _tileMaterial;
|
||||||
private Label _tileOffsetLabel;
|
private Label _tileOffsetLabel;
|
||||||
private World _world;
|
private World _world;
|
||||||
private TextureRect _worldTextureRect;
|
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.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
// debugStatsContainer
|
// debugStatsContainer
|
||||||
Container debugStatsContainer = (Container)FindNode("DebugStatsContainer");
|
Container debugStatsContainer = (Container)FindNode("DebugStatsContainer");
|
||||||
|
|
||||||
_framesPerSecondLabel = debugStatsContainer.GetNode<Label>("fps_label");
|
_framesPerSecondLabel = debugStatsContainer.GetNode<Label>("fps_label");
|
||||||
_centerLabel = debugStatsContainer.GetNode<Label>("center_label");
|
_centerLabel = debugStatsContainer.GetNode<Label>("center_label");
|
||||||
_tileOffsetLabel = debugStatsContainer.GetNode<Label>("tile_offset_label");
|
_tileOffsetLabel = debugStatsContainer.GetNode<Label>("tile_offset_label");
|
||||||
_numTilesLabel = debugStatsContainer.GetNode<Label>("num_tiles_label");
|
|
||||||
_mouseWorldLabel = debugStatsContainer.GetNode<Label>("mouse_world_label");
|
_mouseWorldLabel = debugStatsContainer.GetNode<Label>("mouse_world_label");
|
||||||
_mouseTileOffsetLabel = debugStatsContainer.GetNode<Label>("mouse_tile_offset_label");
|
_mouseTileOffsetLabel = debugStatsContainer.GetNode<Label>("mouse_tile_offset_label");
|
||||||
_mouseTileCubeLabel = debugStatsContainer.GetNode<Label>("mouse_tile_cube_label");
|
_mouseTileCubeLabel = debugStatsContainer.GetNode<Label>("mouse_tile_cube_label");
|
||||||
_mouseTileAxialLabel = debugStatsContainer.GetNode<Label>("mouse_tile_axial_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
|
// UI elements
|
||||||
Container worldGeneratorContainer = (Container)FindNode("WorldGeneratorContainer");
|
Container worldGeneratorWidget = (Container)FindNode("WorldGeneratorWidget");
|
||||||
_worldTextureRect = worldGeneratorContainer.GetNode<TextureRect>("WorldTextureRect");
|
_worldTextureRect = worldGeneratorWidget.GetNode<TextureRect>("WorldTextureRect");
|
||||||
_heightTextureRect = worldGeneratorContainer.GetNode<TextureRect>("HeightTextureRect");
|
_heightTextureRect = worldGeneratorWidget.GetNode<TextureRect>("HeightTextureRect");
|
||||||
_generateWorldButton = worldGeneratorContainer.GetNode<Button>("WorldGenerateButton");
|
|
||||||
_gameUi = (Control)FindNode("GameUI");
|
_gameUi = (Control)FindNode("GameUI");
|
||||||
_goldCountLabel = _gameUi.GetNode<Label>("GoldCount");
|
_woodCountLabel = _gameUi.GetNode<Label>("TopRight/WoodCount");
|
||||||
|
Debug.Assert(_woodCountLabel != null);
|
||||||
|
_goldCountLabel = _gameUi.GetNode<Label>("TopRight/GoldCount");
|
||||||
Debug.Assert(_goldCountLabel != null);
|
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
|
// scene nodes
|
||||||
_tileHighlight = GetNode<Spatial>("TileHighlight");
|
_tileHighlight = GetNode<Spatial>("TileHighlight");
|
||||||
|
@ -77,40 +82,39 @@ public class Game : Spatial
|
||||||
|
|
||||||
_world = (World)FindNode("World");
|
_world = (World)FindNode("World");
|
||||||
|
|
||||||
// populate UI values
|
|
||||||
Slider generatorWorldSizeSlider = worldGeneratorContainer.GetNode<Slider>("HBoxContainer/WorldSizeSlider");
|
|
||||||
|
|
||||||
// resources
|
// resources
|
||||||
_tileHighlightScene = GD.Load<PackedScene>("utils/TileHighlight.tscn");
|
|
||||||
_tileMaterial = GD.Load<ShaderMaterial>("materials/HexTileTextureLookup.tres");
|
_tileMaterial = GD.Load<ShaderMaterial>("materials/HexTileTextureLookup.tres");
|
||||||
Debug.Assert(_tileMaterial != null);
|
Debug.Assert(_tileMaterial != null);
|
||||||
|
|
||||||
_blackWhitePatternTexture = new ImageTexture();
|
_blackWhitePatternTexture = new ImageTexture();
|
||||||
Image image = new Image();
|
Image image = new();
|
||||||
image.Load("assets/4x4checker.png");
|
image.Load("assets/4x4checker.png");
|
||||||
_blackWhitePatternTexture.CreateFromImage(image, (uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
_blackWhitePatternTexture.CreateFromImage(image, (uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||||
|
|
||||||
// other members
|
// other members
|
||||||
_lastTile = new HexCell();
|
|
||||||
_currentTile = new HexCell();
|
_currentTile = new HexCell();
|
||||||
_hexGrid = new HexGrid();
|
_hexGrid = new HexGrid();
|
||||||
_interactionSystem = GetNode<InteractionSystem>("InteractionSystem");
|
_interactionSystem = GetNode<InteractionSystem>("InteractionSystem");
|
||||||
Debug.Assert(_interactionSystem != null);
|
Debug.Assert(_interactionSystem != null);
|
||||||
|
|
||||||
// connect signals
|
// connect signals
|
||||||
_generateWorldButton.Connect("pressed", this, nameof(OnGenerateButton));
|
|
||||||
_player.TaskQueueComponent.Connect("StartInteraction", _interactionSystem,
|
_player.TaskQueueComponent.Connect("StartInteraction", _interactionSystem,
|
||||||
nameof(_interactionSystem.OnStartInteraction));
|
nameof(_interactionSystem.OnStartInteraction));
|
||||||
|
_player.Connect("WoodCountChanged", this, nameof(OnWoodCountChanged));
|
||||||
_player.Connect("GoldCountChanged", this, nameof(OnGoldCountChanged));
|
_player.Connect("GoldCountChanged", this, nameof(OnGoldCountChanged));
|
||||||
_world.Connect("TileClicked", this, nameof(OnTileClicked));
|
_world.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||||
_world.Connect("TileHovered", this, nameof(OnTileHovered));
|
_world.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||||
_world.Connect("OnWorldViewTileTypeImageChanged", this, nameof(OnWorldViewTileTypeImageChanged));
|
_world.Connect("OnWorldViewTileTypeImageChanged", this, nameof(OnWorldViewTileTypeImageChanged));
|
||||||
_world.Connect("OnHeightmapImageChanged", this, nameof(OnHeightmapImageChanged));
|
_world.Connect("OnHeightmapImageChanged", this, nameof(OnHeightmapImageChanged));
|
||||||
|
_walkActionButton.Connect("pressed", this, nameof(OnWalkActionPressed));
|
||||||
|
_buildActionButton.Connect("pressed", this, nameof(OnBuildActionPressed));
|
||||||
|
|
||||||
// register entity events
|
// register entity events
|
||||||
foreach (Node node in GetNode("Entities").GetChildren())
|
foreach (Node node in GetNode("Entities").GetChildren()) {
|
||||||
if (node.HasSignal("EntityClicked"))
|
if (node.HasSignal("EntityClicked")) {
|
||||||
node.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
node.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_world.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
_world.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
||||||
|
|
||||||
|
@ -119,18 +123,39 @@ public class Game : Spatial
|
||||||
WorldInfoComponent worldInfoComponent = _player.GetNode<WorldInfoComponent>("WorldInfo");
|
WorldInfoComponent worldInfoComponent = _player.GetNode<WorldInfoComponent>("WorldInfo");
|
||||||
|
|
||||||
UpdateCurrentTile();
|
UpdateCurrentTile();
|
||||||
|
|
||||||
|
StartNewGame(2, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void _Input(InputEvent inputEvent)
|
public override void _Input(InputEvent inputEvent) {
|
||||||
{
|
if (inputEvent.IsAction("Forward")) {
|
||||||
if (inputEvent.IsAction("Forward")) GD.Print("Forward");
|
GD.Print("Forward");
|
||||||
|
|
||||||
if (inputEvent.IsAction("Back")) GD.Print("Back");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateCurrentTile()
|
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() {
|
||||||
// cast a ray from the camera to center
|
// cast a ray from the camera to center
|
||||||
Vector3 cameraNormal = _camera.ProjectRayNormal(_camera.GetViewport().Size * 0.5f);
|
Vector3 cameraNormal = _camera.ProjectRayNormal(_camera.GetViewport().Size * 0.5f);
|
||||||
Vector3 cameraPosition = _camera.ProjectRayOrigin(_camera.GetViewport().Size * 0.5f);
|
Vector3 cameraPosition = _camera.ProjectRayOrigin(_camera.GetViewport().Size * 0.5f);
|
||||||
|
@ -138,12 +163,9 @@ public class Game : Spatial
|
||||||
|
|
||||||
Vector3 centerCoord;
|
Vector3 centerCoord;
|
||||||
|
|
||||||
if (Mathf.Abs(cameraDir.y) > Globals.EpsPosition)
|
if (Mathf.Abs(cameraDir.y) > Globals.EpsPosition) {
|
||||||
{
|
|
||||||
centerCoord = cameraPosition + cameraNormal * (-cameraPosition.y / cameraNormal.y);
|
centerCoord = cameraPosition + cameraNormal * (-cameraPosition.y / cameraNormal.y);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
centerCoord = _camera.GlobalTranslation;
|
centerCoord = _camera.GlobalTranslation;
|
||||||
centerCoord.y = 0;
|
centerCoord.y = 0;
|
||||||
}
|
}
|
||||||
|
@ -157,10 +179,8 @@ public class Game : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void _Process(float delta)
|
public override void _Process(float delta) {
|
||||||
{
|
|
||||||
_framesPerSecondLabel.Text = Engine.GetFramesPerSecond().ToString();
|
_framesPerSecondLabel.Text = Engine.GetFramesPerSecond().ToString();
|
||||||
_lastTile = _currentTile;
|
|
||||||
|
|
||||||
UpdateCurrentTile();
|
UpdateCurrentTile();
|
||||||
|
|
||||||
|
@ -175,18 +195,8 @@ public class Game : Spatial
|
||||||
_camera.Transform = cameraTransform;
|
_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,
|
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||||
int shapeIndex)
|
int shapeIndex) {
|
||||||
{
|
|
||||||
HexCell cellAtCursor = _hexGrid.GetHexAt(new Vector2(position.x, position.z));
|
HexCell cellAtCursor = _hexGrid.GetHexAt(new Vector2(position.x, position.z));
|
||||||
Transform highlightTransform = Transform.Identity;
|
Transform highlightTransform = Transform.Identity;
|
||||||
|
|
||||||
|
@ -198,19 +208,33 @@ public class Game : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void OnTileClicked(HexTile3D tile)
|
public void OnTileClicked(HexTile3D tile) {
|
||||||
{
|
if (_player == null) {
|
||||||
if (_player == null) return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_player.InteractionComponent != null) _player.InteractionComponent.EmitSignal("InteractionEnd");
|
if (_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");
|
||||||
|
}
|
||||||
|
|
||||||
_player.TaskQueueComponent.Reset();
|
_player.TaskQueueComponent.Reset();
|
||||||
_player.TaskQueueComponent.Queue.Enqueue(new TaskQueueComponent.NavigationTask(
|
_player.TaskQueueComponent.Queue.Enqueue(new TaskQueueComponent.NavigationTask(
|
||||||
new NavigationPoint(tile.GlobalTranslation)));
|
new NavigationPoint(tile.GlobalTranslation)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTileHovered(HexTile3D tile)
|
public void OnTileHovered(HexTile3D tile) {
|
||||||
{
|
|
||||||
Transform highlightTransform = tile.GlobalTransform;
|
Transform highlightTransform = tile.GlobalTransform;
|
||||||
_mouseTileHighlight.Transform = highlightTransform;
|
_mouseTileHighlight.Transform = highlightTransform;
|
||||||
_mouseWorldLabel.Text = highlightTransform.origin.ToString("F3");
|
_mouseWorldLabel.Text = highlightTransform.origin.ToString("F3");
|
||||||
|
@ -220,13 +244,11 @@ public class Game : Spatial
|
||||||
_player.NavigationComponent.FindPath(_player, _player.GlobalTranslation, tile.GlobalTranslation);
|
_player.NavigationComponent.FindPath(_player, _player.GlobalTranslation, tile.GlobalTranslation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnEntityClicked(Entity entity)
|
public void OnEntityClicked(Entity entity) {
|
||||||
{
|
|
||||||
GD.Print("Clicked on entity at " + entity.GlobalTranslation);
|
GD.Print("Clicked on entity at " + entity.GlobalTranslation);
|
||||||
|
|
||||||
Spatial mountPoint = (Spatial)entity.FindNode("MountPoint");
|
Spatial mountPoint = (Spatial)entity.FindNode("MountPoint");
|
||||||
if (mountPoint != null)
|
if (mountPoint != null) {
|
||||||
{
|
|
||||||
_player.TaskQueueComponent.Reset();
|
_player.TaskQueueComponent.Reset();
|
||||||
_player.TaskQueueComponent.Queue.Enqueue(new TaskQueueComponent.NavigationTask(
|
_player.TaskQueueComponent.Queue.Enqueue(new TaskQueueComponent.NavigationTask(
|
||||||
new NavigationPoint(mountPoint.GlobalTransform)));
|
new NavigationPoint(mountPoint.GlobalTransform)));
|
||||||
|
@ -235,8 +257,7 @@ public class Game : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void ResetGameState()
|
public void ResetGameState() {
|
||||||
{
|
|
||||||
Transform playerStartTransform = Transform.Identity;
|
Transform playerStartTransform = Transform.Identity;
|
||||||
playerStartTransform.origin.y = 0;
|
playerStartTransform.origin.y = 0;
|
||||||
_player.Transform = playerStartTransform;
|
_player.Transform = playerStartTransform;
|
||||||
|
@ -244,30 +265,29 @@ public class Game : Spatial
|
||||||
_player.NavigationComponent.PlanDirectPath(_player, playerStartTransform.origin, playerStartTransform.origin,
|
_player.NavigationComponent.PlanDirectPath(_player, playerStartTransform.origin, playerStartTransform.origin,
|
||||||
playerStartTransform.basis.Quat());
|
playerStartTransform.basis.Quat());
|
||||||
|
|
||||||
|
_woodCountLabel.Text = "0";
|
||||||
_goldCountLabel.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;
|
Transform entityTransform = entity.Transform;
|
||||||
Vector2 entityPlanePos = new Vector2(entityTransform.origin.x, entityTransform.origin.z);
|
Vector2 entityPlanePos = new(entityTransform.origin.x, entityTransform.origin.z);
|
||||||
Vector2 entityOffsetCoordinates = _hexGrid.GetHexAt(entityPlanePos).OffsetCoords;
|
Vector2 entityOffsetCoordinates = _hexGrid.GetHexAt(entityPlanePos).OffsetCoords;
|
||||||
entityTransform.origin.y = 0;
|
entityTransform.origin.y = 0;
|
||||||
entity.Transform = entityTransform;
|
entity.Transform = entityTransform;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnHeightmapImageChanged(Image heightmapImage)
|
private void OnHeightmapImageChanged(Image heightmapImage) {
|
||||||
{
|
ImageTexture newHeightmapTexture = new();
|
||||||
ImageTexture newHeightmapTexture = new ImageTexture();
|
|
||||||
newHeightmapTexture.CreateFromImage(heightmapImage,
|
newHeightmapTexture.CreateFromImage(heightmapImage,
|
||||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||||
|
|
||||||
_heightTextureRect.Texture = newHeightmapTexture;
|
_heightTextureRect.Texture = newHeightmapTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnWorldViewTileTypeImageChanged(Image viewTileTypeImage)
|
private void OnWorldViewTileTypeImageChanged(Image viewTileTypeImage) {
|
||||||
{
|
ImageTexture newWorldTexture = new();
|
||||||
ImageTexture newWorldTexture = new ImageTexture();
|
|
||||||
newWorldTexture.CreateFromImage(viewTileTypeImage,
|
newWorldTexture.CreateFromImage(viewTileTypeImage,
|
||||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||||
|
|
||||||
|
@ -279,12 +299,27 @@ public class Game : Spatial
|
||||||
_tileMaterial.SetShaderParam("CoordinateOffsetV", (int)_world.WorldTextureCoordinateOffset.y);
|
_tileMaterial.SetShaderParam("CoordinateOffsetV", (int)_world.WorldTextureCoordinateOffset.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnGoldCountChanged(int goldCount)
|
public void OnWoodCountChanged(int woodCount) {
|
||||||
{
|
AnimationPlayer animationPlayer = _woodCountLabel.GetNode<AnimationPlayer>("AnimationPlayer");
|
||||||
AnimationPlayer animationPlayer = _gameUi.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");
|
||||||
_goldCountLabel.Text = goldCount.ToString();
|
_goldCountLabel.Text = goldCount.ToString();
|
||||||
animationPlayer.CurrentAnimation = "FlashLabel";
|
animationPlayer.CurrentAnimation = "FlashLabel";
|
||||||
animationPlayer.Seek(0);
|
animationPlayer.Seek(0);
|
||||||
animationPlayer.Play();
|
animationPlayer.Play();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnWalkActionPressed() {
|
||||||
|
_actionMode = ActionMode.Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnBuildActionPressed() {
|
||||||
|
_actionMode = ActionMode.Building;
|
||||||
|
}
|
||||||
}
|
}
|
352
scenes/Game.tscn
352
scenes/Game.tscn
|
@ -1,22 +1,51 @@
|
||||||
[gd_scene load_steps=21 format=2]
|
[gd_scene load_steps=20 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://entities/Player.tscn" type="PackedScene" id=2]
|
||||||
[ext_resource path="res://scenes/Camera.tscn" type="PackedScene" id=3]
|
[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://ui/EditorUI.tscn" type="PackedScene" id=4]
|
||||||
[ext_resource path="res://utils/TileHighlight.tscn" type="PackedScene" id=5]
|
[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://ui/DebugStatsContainer.gd" type="Script" id=6]
|
||||||
[ext_resource path="res://scenes/World.cs" type="Script" id=7]
|
[ext_resource path="res://scenes/World.tscn" type="PackedScene" id=7]
|
||||||
|
[ext_resource path="res://ui/WorldGeneratorUI.tscn" type="PackedScene" id=8]
|
||||||
[ext_resource path="res://scenes/Game.cs" type="Script" id=9]
|
[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://entities/Chest.tscn" type="PackedScene" id=11]
|
||||||
[ext_resource path="res://ui/WorldGeneratorUI.gd" type="Script" id=12]
|
[ext_resource path="res://ui/game_theme.tres" type="Theme" id=12]
|
||||||
[ext_resource path="res://assets/Environment/HexTileMesh.tres" type="CylinderMesh" id=13]
|
[ext_resource path="res://ui/action_buttongroup.tres" type="ButtonGroup" id=13]
|
||||||
[ext_resource path="res://entities/Axe.tscn" type="PackedScene" id=14]
|
[ext_resource path="res://entities/Axe.tscn" type="PackedScene" id=14]
|
||||||
[ext_resource path="res://systems/InteractionSystem.cs" type="Script" id=15]
|
[ext_resource path="res://systems/InteractionSystem.cs" type="Script" id=15]
|
||||||
[ext_resource path="res://entities/rockA.tscn" type="PackedScene" id=16]
|
|
||||||
[ext_resource path="res://entities/rockC.tscn" type="PackedScene" id=17]
|
[sub_resource type="Animation" id=27]
|
||||||
[ext_resource path="res://entities/rockB.tscn" type="PackedScene" id=18]
|
resource_name = "FlashLabel"
|
||||||
[ext_resource path="res://entities/Tree.tscn" type="PackedScene" id=19]
|
length = 0.3
|
||||||
[ext_resource path="res://assets/Environment/grassLarge.tscn" type="PackedScene" id=20]
|
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 ) ]
|
||||||
|
}
|
||||||
|
|
||||||
[sub_resource type="Animation" id=25]
|
[sub_resource type="Animation" id=25]
|
||||||
resource_name = "FlashLabel"
|
resource_name = "FlashLabel"
|
||||||
|
@ -36,15 +65,11 @@ tracks/0/keys = {
|
||||||
|
|
||||||
[sub_resource type="AnimationNodeStateMachinePlayback" id=26]
|
[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"]
|
[node name="Game" type="Spatial"]
|
||||||
script = ExtResource( 9 )
|
script = ExtResource( 9 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_horizontal_guides_": [ -333.0 ]
|
||||||
|
}
|
||||||
|
|
||||||
[node name="TileHighlight" parent="." instance=ExtResource( 5 )]
|
[node name="TileHighlight" parent="." instance=ExtResource( 5 )]
|
||||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0 )
|
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0 )
|
||||||
|
@ -52,42 +77,94 @@ visible = false
|
||||||
|
|
||||||
[node name="MouseTileHighlight" parent="." instance=ExtResource( 5 )]
|
[node name="MouseTileHighlight" parent="." instance=ExtResource( 5 )]
|
||||||
|
|
||||||
[node name="GameUI" type="HBoxContainer" parent="."]
|
[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"]
|
||||||
anchor_left = 1.0
|
anchor_left = 1.0
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
margin_left = -40.0
|
margin_left = -206.0
|
||||||
margin_right = -10.0
|
|
||||||
margin_bottom = 40.0
|
margin_bottom = 40.0
|
||||||
grow_horizontal = 0
|
grow_horizontal = 0
|
||||||
|
mouse_filter = 2
|
||||||
alignment = 2
|
alignment = 2
|
||||||
|
|
||||||
[node name="GoldLabel" type="Label" parent="GameUI"]
|
[node name="WoodLabel" type="Label" parent="GameUI/TopRight"]
|
||||||
margin_top = 13.0
|
margin_left = 4.0
|
||||||
margin_right = 30.0
|
margin_top = 10.0
|
||||||
margin_bottom = 27.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
|
||||||
text = "Gold"
|
text = "Gold"
|
||||||
|
|
||||||
[node name="GoldCount" type="Label" parent="GameUI"]
|
[node name="GoldCount" type="Label" parent="GameUI/TopRight"]
|
||||||
margin_left = 34.0
|
margin_left = 156.0
|
||||||
margin_top = 13.0
|
margin_top = 10.0
|
||||||
margin_right = 84.0
|
margin_right = 206.0
|
||||||
margin_bottom = 27.0
|
margin_bottom = 29.0
|
||||||
rect_min_size = Vector2( 50, 0 )
|
rect_min_size = Vector2( 50, 0 )
|
||||||
rect_pivot_offset = Vector2( 45, 8 )
|
rect_pivot_offset = Vector2( 25, 8 )
|
||||||
text = "0"
|
text = "0"
|
||||||
align = 2
|
align = 1
|
||||||
|
|
||||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="GameUI"]
|
[node name="AnimationPlayer" type="AnimationPlayer" parent="GameUI/TopRight/GoldCount"]
|
||||||
|
root_node = NodePath("../..")
|
||||||
anims/FlashLabel = SubResource( 25 )
|
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="."]
|
[node name="DebugContainer" type="PanelContainer" parent="."]
|
||||||
self_modulate = Color( 1, 1, 1, 0.443137 )
|
self_modulate = Color( 1, 1, 1, 0.443137 )
|
||||||
anchor_left = 1.0
|
anchor_left = 1.0
|
||||||
anchor_top = 1.0
|
anchor_top = 1.0
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
margin_left = -141.0
|
margin_left = -67.0
|
||||||
margin_top = -172.0
|
margin_top = -34.0
|
||||||
grow_horizontal = 0
|
grow_horizontal = 0
|
||||||
grow_vertical = 0
|
grow_vertical = 0
|
||||||
mouse_filter = 2
|
mouse_filter = 2
|
||||||
|
@ -97,8 +174,8 @@ size_flags_vertical = 3
|
||||||
[node name="DebugStatsContainer" type="GridContainer" parent="DebugContainer"]
|
[node name="DebugStatsContainer" type="GridContainer" parent="DebugContainer"]
|
||||||
margin_left = 7.0
|
margin_left = 7.0
|
||||||
margin_top = 7.0
|
margin_top = 7.0
|
||||||
margin_right = 134.0
|
margin_right = 60.0
|
||||||
margin_bottom = 165.0
|
margin_bottom = 27.0
|
||||||
grow_horizontal = 0
|
grow_horizontal = 0
|
||||||
grow_vertical = 0
|
grow_vertical = 0
|
||||||
mouse_filter = 2
|
mouse_filter = 2
|
||||||
|
@ -291,22 +368,24 @@ margin_bottom = 200.0
|
||||||
text = "0"
|
text = "0"
|
||||||
|
|
||||||
[node name="Generator Container" type="Control" parent="."]
|
[node name="Generator Container" type="Control" parent="."]
|
||||||
|
visible = false
|
||||||
margin_right = 40.0
|
margin_right = 40.0
|
||||||
margin_bottom = 40.0
|
margin_bottom = 40.0
|
||||||
mouse_filter = 2
|
mouse_filter = 2
|
||||||
|
|
||||||
[node name="WorldGeneratorContainer" type="VBoxContainer" parent="Generator Container"]
|
[node name="WorldGeneratorWidget" type="VBoxContainer" parent="Generator Container"]
|
||||||
margin_left = 10.0
|
margin_left = 10.0
|
||||||
margin_top = 10.0
|
margin_top = 10.0
|
||||||
margin_right = 145.0
|
margin_right = 145.0
|
||||||
margin_bottom = 94.0
|
margin_bottom = 94.0
|
||||||
script = ExtResource( 12 )
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
[node name="HBoxContainer" type="HBoxContainer" parent="Generator Container/WorldGeneratorContainer"]
|
[node name="HBoxContainer" type="HBoxContainer" parent="Generator Container/WorldGeneratorWidget"]
|
||||||
|
visible = false
|
||||||
margin_right = 135.0
|
margin_right = 135.0
|
||||||
margin_bottom = 16.0
|
margin_bottom = 16.0
|
||||||
|
|
||||||
[node name="WorldSizeSlider" type="HSlider" parent="Generator Container/WorldGeneratorContainer/HBoxContainer"]
|
[node name="WorldSizeSlider" type="HSlider" parent="Generator Container/WorldGeneratorWidget/HBoxContainer"]
|
||||||
margin_right = 123.0
|
margin_right = 123.0
|
||||||
margin_bottom = 16.0
|
margin_bottom = 16.0
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
|
@ -314,26 +393,26 @@ min_value = 1.0
|
||||||
max_value = 256.0
|
max_value = 256.0
|
||||||
value = 1.0
|
value = 1.0
|
||||||
|
|
||||||
[node name="WorldSizeLabel" type="Label" parent="Generator Container/WorldGeneratorContainer/HBoxContainer"]
|
[node name="WorldSizeLabel" type="Label" parent="Generator Container/WorldGeneratorWidget/HBoxContainer"]
|
||||||
margin_left = 127.0
|
margin_left = 127.0
|
||||||
margin_top = 1.0
|
margin_top = 1.0
|
||||||
margin_right = 135.0
|
margin_right = 135.0
|
||||||
margin_bottom = 15.0
|
margin_bottom = 15.0
|
||||||
text = "4"
|
text = "4"
|
||||||
|
|
||||||
[node name="WorldGenerateButton" type="Button" parent="Generator Container/WorldGeneratorContainer"]
|
[node name="WorldGenerateButton" type="Button" parent="Generator Container/WorldGeneratorWidget"]
|
||||||
|
visible = false
|
||||||
margin_top = 20.0
|
margin_top = 20.0
|
||||||
margin_right = 135.0
|
margin_right = 135.0
|
||||||
margin_bottom = 40.0
|
margin_bottom = 40.0
|
||||||
text = "Generate"
|
text = "Generate"
|
||||||
|
|
||||||
[node name="ShowTexturesCheckButton" type="CheckButton" parent="Generator Container/WorldGeneratorContainer"]
|
[node name="ShowTexturesCheckButton" type="CheckButton" parent="Generator Container/WorldGeneratorWidget"]
|
||||||
margin_top = 44.0
|
|
||||||
margin_right = 135.0
|
margin_right = 135.0
|
||||||
margin_bottom = 84.0
|
margin_bottom = 40.0
|
||||||
text = "Textures"
|
text = "Textures"
|
||||||
|
|
||||||
[node name="WorldTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorContainer"]
|
[node name="WorldTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorWidget"]
|
||||||
visible = false
|
visible = false
|
||||||
margin_top = 88.0
|
margin_top = 88.0
|
||||||
margin_right = 135.0
|
margin_right = 135.0
|
||||||
|
@ -343,11 +422,11 @@ expand = true
|
||||||
stretch_mode = 5
|
stretch_mode = 5
|
||||||
flip_v = true
|
flip_v = true
|
||||||
|
|
||||||
[node name="HeightTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorContainer"]
|
[node name="HeightTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorWidget"]
|
||||||
visible = false
|
visible = false
|
||||||
margin_top = 88.0
|
margin_top = 192.0
|
||||||
margin_right = 135.0
|
margin_right = 135.0
|
||||||
margin_bottom = 188.0
|
margin_bottom = 292.0
|
||||||
rect_min_size = Vector2( 100, 100 )
|
rect_min_size = Vector2( 100, 100 )
|
||||||
expand = true
|
expand = true
|
||||||
stretch_mode = 5
|
stretch_mode = 5
|
||||||
|
@ -365,63 +444,182 @@ script = ExtResource( 15 )
|
||||||
[node name="NavigationSystem" type="Node" parent="."]
|
[node name="NavigationSystem" type="Node" parent="."]
|
||||||
|
|
||||||
[node name="Player" parent="." instance=ExtResource( 2 )]
|
[node name="Player" parent="." instance=ExtResource( 2 )]
|
||||||
|
EntityMask = 2
|
||||||
WorldNode = NodePath("../World")
|
WorldNode = NodePath("../World")
|
||||||
|
|
||||||
[node name="WorldInfo" parent="Player" index="2"]
|
[node name="WorldInfo" parent="Player" index="2"]
|
||||||
WorldPath = NodePath("../../World")
|
WorldPath = NodePath("../../World")
|
||||||
|
|
||||||
[node name="ToolAttachement" parent="Player/Geometry/PirateAsset/Armature/Skeleton" index="5"]
|
[node name="Skeleton" parent="Player/Geometry/PirateAsset/Armature" index="0"]
|
||||||
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 )
|
bones/4/bound_children = [ NodePath("ToolAttachement") ]
|
||||||
|
|
||||||
[node name="AnimationTree" parent="Player/Geometry" index="2"]
|
[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 )
|
||||||
|
|
||||||
|
[node name="AnimationTree" parent="Player/Geometry" index="1"]
|
||||||
parameters/playback = SubResource( 26 )
|
parameters/playback = SubResource( 26 )
|
||||||
|
|
||||||
[node name="Entities" type="Spatial" parent="."]
|
[node name="Entities" type="Spatial" parent="."]
|
||||||
|
|
||||||
[node name="Axe" parent="Entities" instance=ExtResource( 14 )]
|
[node name="Axe" parent="Entities" instance=ExtResource( 14 )]
|
||||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.79762, 0, 0 )
|
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1.03292, -2.38419e-07, -4.33215 )
|
||||||
input_ray_pickable = false
|
input_ray_pickable = false
|
||||||
|
|
||||||
[node name="Chest" parent="Entities" instance=ExtResource( 11 )]
|
[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 )
|
transform = Transform( -0.825665, 0, 0.56416, 0, 1, 0, -0.56416, 0, -0.825665, -3.27709, 0, 1.02593 )
|
||||||
|
|
||||||
[node name="World" type="Spatial" parent="."]
|
[node name="Wood" parent="Entities" instance=ExtResource( 10 )]
|
||||||
script = ExtResource( 7 )
|
transform = Transform( 0.791533, 0, 0.611126, 0, 1, 0, -0.611126, 0, 0.791533, -2.46279, 0, -0.631194 )
|
||||||
|
|
||||||
[node name="Chunks" type="Spatial" parent="World"]
|
[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="TileMultiMeshInstance" type="MultiMeshInstance" parent="World"]
|
[node name="Wood3" parent="Entities" instance=ExtResource( 10 )]
|
||||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -2.5, 0 )
|
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1.89011, 0, 1.70148 )
|
||||||
multimesh = SubResource( 27 )
|
|
||||||
|
|
||||||
[node name="Assets" type="Spatial" parent="World"]
|
[node name="Wood4" parent="Entities" instance=ExtResource( 10 )]
|
||||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -5, 0 )
|
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.85616, 0, -2.01499 )
|
||||||
visible = false
|
|
||||||
|
|
||||||
[node name="Rocks" type="Spatial" parent="World/Assets"]
|
[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="rockA" parent="World/Assets/Rocks" instance=ExtResource( 16 )]
|
[node name="World" parent="." instance=ExtResource( 7 )]
|
||||||
|
|
||||||
[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="."]
|
[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 )
|
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
|
shadow_enabled = true
|
||||||
directional_shadow_mode = 0
|
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="toggled" from="DebugContainer/DebugStatsContainer/DebugMenuButton" to="DebugContainer/DebugStatsContainer" method="_on_DebugMenuButton_toggled"]
|
||||||
[connection signal="value_changed" from="Generator Container/WorldGeneratorContainer/HBoxContainer/WorldSizeSlider" to="Generator Container/WorldGeneratorContainer" method="_on_HSlider_value_changed"]
|
[connection signal="value_changed" from="Generator Container/WorldGeneratorWidget/HBoxContainer/WorldSizeSlider" to="Generator Container/WorldGeneratorWidget" method="_on_HSlider_value_changed"]
|
||||||
[connection signal="toggled" from="Generator Container/WorldGeneratorContainer/ShowTexturesCheckButton" to="Generator Container/WorldGeneratorContainer" method="_on_ShowTexturesCheckButton_toggled"]
|
[connection signal="toggled" from="Generator Container/WorldGeneratorWidget/ShowTexturesCheckButton" to="Generator Container/WorldGeneratorWidget" method="_on_ShowTexturesCheckButton_toggled"]
|
||||||
|
|
||||||
[editable path="Player"]
|
[editable path="Player"]
|
||||||
[editable path="Player/Geometry/PirateAsset"]
|
[editable path="Player/Geometry/PirateAsset"]
|
||||||
|
[editable path="World"]
|
||||||
|
[editable path="GameMenu/NewGameMenu/WorldGeneratorUI"]
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public class HexTile3D : Spatial
|
public class HexTile3D : Spatial {
|
||||||
{
|
public class TileTypeInfo {
|
||||||
public enum TileType
|
public readonly string Name;
|
||||||
{
|
public readonly Color Color;
|
||||||
Undefined,
|
public readonly ushort TileTypeMask;
|
||||||
Sand,
|
|
||||||
Grass,
|
|
||||||
DeepGrass
|
|
||||||
}
|
|
||||||
|
|
||||||
static public TileType[] ValidTileTypes = { TileType.Sand, TileType.Grass, TileType.DeepGrass };
|
public TileTypeInfo(string name, Color color, ushort tileTypeMask) {
|
||||||
|
Name = name;
|
||||||
|
Color = color;
|
||||||
|
TileTypeMask = tileTypeMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// scene nodes
|
// scene nodes
|
||||||
private MeshInstance _mesh;
|
private MeshInstance _mesh;
|
||||||
|
@ -19,26 +20,24 @@ public class HexTile3D : Spatial
|
||||||
|
|
||||||
// signals
|
// signals
|
||||||
[Signal]
|
[Signal]
|
||||||
delegate void TileClicked(HexTile3D tile3d);
|
private delegate void TileClicked(HexTile3D tile3d);
|
||||||
|
|
||||||
[Signal]
|
[Signal]
|
||||||
delegate void TileHovered(HexTile3D tile3d);
|
private delegate void TileHovered(HexTile3D tile3d);
|
||||||
|
|
||||||
// other member variables
|
// other member variables
|
||||||
private SpatialMaterial _previousMaterial;
|
private SpatialMaterial _previousMaterial;
|
||||||
|
|
||||||
private HexGrid _hexGrid;
|
private readonly HexGrid _hexGrid;
|
||||||
|
|
||||||
public HexCell Cell = new HexCell();
|
public HexCell Cell = new();
|
||||||
public bool IsMouseOver = false;
|
public bool IsMouseOver;
|
||||||
public MeshInstance Mesh;
|
public MeshInstance Mesh;
|
||||||
|
|
||||||
public Vector2 OffsetCoords
|
public Vector2 OffsetCoords {
|
||||||
{
|
get => Cell.OffsetCoords;
|
||||||
get { return Cell.OffsetCoords; }
|
|
||||||
|
|
||||||
set
|
set {
|
||||||
{
|
|
||||||
Cell.OffsetCoords = value;
|
Cell.OffsetCoords = value;
|
||||||
Transform tile3dTransform = Transform;
|
Transform tile3dTransform = Transform;
|
||||||
Vector2 cellPlaneCoords = _hexGrid.GetHexCenter(Cell);
|
Vector2 cellPlaneCoords = _hexGrid.GetHexCenter(Cell);
|
||||||
|
@ -48,16 +47,12 @@ public class HexTile3D : Spatial
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TileType Type { get; set; }
|
private HexTile3D() {
|
||||||
|
|
||||||
HexTile3D()
|
|
||||||
{
|
|
||||||
_hexGrid = new HexGrid();
|
_hexGrid = new HexGrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
_mesh = GetNode<MeshInstance>("Mesh");
|
_mesh = GetNode<MeshInstance>("Mesh");
|
||||||
_staticBody = GetNode<StaticBody>("StaticBody");
|
_staticBody = GetNode<StaticBody>("StaticBody");
|
||||||
|
|
||||||
|
@ -67,26 +62,20 @@ public class HexTile3D : Spatial
|
||||||
|
|
||||||
Mesh = GetNode<MeshInstance>("Mesh");
|
Mesh = GetNode<MeshInstance>("Mesh");
|
||||||
Debug.Assert(Mesh != null);
|
Debug.Assert(Mesh != null);
|
||||||
|
|
||||||
this.Type = TileType.Undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||||
int shapeIndex)
|
int shapeIndex) {
|
||||||
{
|
if (IsMouseOver && inputEvent is InputEventMouseButton) {
|
||||||
if (IsMouseOver && inputEvent is InputEventMouseButton)
|
|
||||||
{
|
|
||||||
InputEventMouseButton mouseButtonEvent = (InputEventMouseButton)inputEvent;
|
InputEventMouseButton mouseButtonEvent = (InputEventMouseButton)inputEvent;
|
||||||
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed)
|
if (mouseButtonEvent.ButtonIndex == 1 && mouseButtonEvent.Pressed) {
|
||||||
{
|
|
||||||
EmitSignal("TileClicked", this);
|
EmitSignal("TileClicked", this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnAreaMouseEntered()
|
public void OnAreaMouseEntered() {
|
||||||
{
|
|
||||||
IsMouseOver = true;
|
IsMouseOver = true;
|
||||||
_previousMaterial = (SpatialMaterial)_mesh.MaterialOverride;
|
_previousMaterial = (SpatialMaterial)_mesh.MaterialOverride;
|
||||||
|
|
||||||
|
@ -96,8 +85,7 @@ public class HexTile3D : Spatial
|
||||||
// _mesh.MaterialOverride = clonedMaterial;
|
// _mesh.MaterialOverride = clonedMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnAreaMouseExited()
|
public void OnAreaMouseExited() {
|
||||||
{
|
|
||||||
IsMouseOver = false;
|
IsMouseOver = false;
|
||||||
_mesh.MaterialOverride = _previousMaterial;
|
_mesh.MaterialOverride = _previousMaterial;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[gd_scene load_steps=4 format=2]
|
[gd_scene load_steps=4 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://materials/IslandColorRampShader.tres" type="Material" id=1]
|
[ext_resource path="res://materials/WorldTileTypeMaterial.tres" type="Material" id=1]
|
||||||
|
|
||||||
[sub_resource type="OpenSimplexNoise" id=3]
|
[sub_resource type="OpenSimplexNoise" id=3]
|
||||||
seed = 57
|
seed = 57
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
using System;
|
|
||||||
using Godot;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using GoDotLog;
|
using Godot;
|
||||||
|
|
||||||
public class StreamContainer : Spatial
|
public class StreamContainer : Spatial {
|
||||||
{
|
|
||||||
// readonly variables
|
// readonly variables
|
||||||
private readonly Transform _deactivatedTileTransform = new Transform(Basis.Identity, Vector3.Up * 1000);
|
private readonly Transform _deactivatedTileTransform = new(Basis.Identity, Vector3.Up * 1000);
|
||||||
|
|
||||||
// scene nodes
|
// scene nodes
|
||||||
private MeshInstance _bounds;
|
private MeshInstance _bounds;
|
||||||
|
@ -18,41 +14,37 @@ public class StreamContainer : Spatial
|
||||||
private MultiMeshInstance _tileMultiMesh;
|
private MultiMeshInstance _tileMultiMesh;
|
||||||
|
|
||||||
// resources
|
// resources
|
||||||
private PackedScene _hexTileScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
private readonly PackedScene _hexTileScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
||||||
|
|
||||||
// exports
|
// exports
|
||||||
[Export] public Vector2 Dimensions = new Vector2(8, 4);
|
[Export] public Vector2 Dimensions = new(8, 4);
|
||||||
[Export] public NodePath World;
|
[Export] public NodePath World;
|
||||||
[Export] private bool ShowHexTiles = false;
|
[Export] private bool ShowHexTiles;
|
||||||
|
|
||||||
[Signal]
|
[Signal]
|
||||||
delegate void TileClicked(HexTile3D tile3d);
|
private delegate void TileClicked(HexTile3D tile3d);
|
||||||
|
|
||||||
[Signal]
|
[Signal]
|
||||||
delegate void TileHovered(HexTile3D tile3d);
|
private delegate void TileHovered(HexTile3D tile3d);
|
||||||
|
|
||||||
// other members
|
// other members
|
||||||
private Rect2 _currentOffsetCoordRect;
|
private Rect2 _currentOffsetCoordRect;
|
||||||
private Rect2 _oldOffsetCoordRect;
|
private Rect2 _oldOffsetCoordRect;
|
||||||
private HexGrid _hexGrid;
|
private HexGrid _hexGrid;
|
||||||
|
|
||||||
private Dictionary<Vector2, HexTile3D> _coordToTile = new();
|
private readonly Dictionary<Vector2, HexTile3D> _coordToTile = new();
|
||||||
private Dictionary<HexTile3D, int> _tileToInstanceIndex = new();
|
private readonly Dictionary<HexTile3D, int> _tileToInstanceIndex = new();
|
||||||
public List<Vector2> RemovedCoords = new List<Vector2>();
|
public List<Vector2> RemovedCoords = new();
|
||||||
public List<Vector2> AddedCoords = new List<Vector2>();
|
public List<Vector2> AddedCoords = new();
|
||||||
|
|
||||||
public Rect2 CurrentOffsetCoordRect
|
public Rect2 CurrentOffsetCoordRect => _currentOffsetCoordRect;
|
||||||
{
|
|
||||||
get { return _currentOffsetCoordRect; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetWorld(TileWorld tileWorld)
|
public void SetWorld(TileWorld tileWorld) {
|
||||||
{
|
|
||||||
TileWorld = tileWorld;
|
TileWorld = tileWorld;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
_unusedTiles = new Queue<HexTile3D>();
|
_unusedTiles = new Queue<HexTile3D>();
|
||||||
_bounds = GetNode<MeshInstance>("Bounds");
|
_bounds = GetNode<MeshInstance>("Bounds");
|
||||||
_activeTiles = GetNode<Spatial>("ActiveTiles");
|
_activeTiles = GetNode<Spatial>("ActiveTiles");
|
||||||
|
@ -60,8 +52,7 @@ public class StreamContainer : Spatial
|
||||||
_tileMultiMesh = GetNode<MultiMeshInstance>("TileMultiMesh");
|
_tileMultiMesh = GetNode<MultiMeshInstance>("TileMultiMesh");
|
||||||
_tileMultiMesh.Multimesh.InstanceCount = (int)((Dimensions.x + 5) * (Dimensions.y + 5));
|
_tileMultiMesh.Multimesh.InstanceCount = (int)((Dimensions.x + 5) * (Dimensions.y + 5));
|
||||||
_tileMultiMesh.Multimesh.InstanceCount = 1810;
|
_tileMultiMesh.Multimesh.InstanceCount = 1810;
|
||||||
foreach (int i in Enumerable.Range(0, _tileMultiMesh.Multimesh.InstanceCount))
|
foreach (int i in Enumerable.Range(0, _tileMultiMesh.Multimesh.InstanceCount)) {
|
||||||
{
|
|
||||||
_tileMultiMesh.Multimesh.SetInstanceTransform(i, _deactivatedTileTransform);
|
_tileMultiMesh.Multimesh.SetInstanceTransform(i, _deactivatedTileTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,8 +66,7 @@ public class StreamContainer : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void UpdateRects(Vector2 centerPlane)
|
public void UpdateRects(Vector2 centerPlane) {
|
||||||
{
|
|
||||||
_oldOffsetCoordRect = _currentOffsetCoordRect;
|
_oldOffsetCoordRect = _currentOffsetCoordRect;
|
||||||
|
|
||||||
Vector2 bottomLeftCoord = centerPlane - new Vector2(Dimensions.x / 2, Dimensions.y / 2);
|
Vector2 bottomLeftCoord = centerPlane - new Vector2(Dimensions.x / 2, Dimensions.y / 2);
|
||||||
|
@ -104,15 +94,13 @@ public class StreamContainer : Spatial
|
||||||
// GD.Print("Bounds Transform: " + boundsTransform.ToString());
|
// GD.Print("Bounds Transform: " + boundsTransform.ToString());
|
||||||
// GD.Print("Bounds Global : " + _bounds.GlobalTransform.ToString());
|
// GD.Print("Bounds Global : " + _bounds.GlobalTransform.ToString());
|
||||||
|
|
||||||
if (!_currentOffsetCoordRect.Equals(_oldOffsetCoordRect))
|
if (!_currentOffsetCoordRect.Equals(_oldOffsetCoordRect)) {
|
||||||
{
|
|
||||||
UpdateTileCache();
|
UpdateTileCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void UpdateTileCache()
|
public void UpdateTileCache() {
|
||||||
{
|
|
||||||
RemovedCoords.Clear();
|
RemovedCoords.Clear();
|
||||||
AddedCoords.Clear();
|
AddedCoords.Clear();
|
||||||
_unusedTiles.Clear();
|
_unusedTiles.Clear();
|
||||||
|
@ -123,8 +111,7 @@ public class StreamContainer : Spatial
|
||||||
MarkUnusedTiles(expandedRect, clippedRect);
|
MarkUnusedTiles(expandedRect, clippedRect);
|
||||||
AddNewTiles(expandedRect, clippedRect);
|
AddNewTiles(expandedRect, clippedRect);
|
||||||
|
|
||||||
foreach (HexTile3D tile3D in _unusedTiles.ToArray())
|
foreach (HexTile3D tile3D in _unusedTiles.ToArray()) {
|
||||||
{
|
|
||||||
RemovedCoords.Add(tile3D.OffsetCoords);
|
RemovedCoords.Add(tile3D.OffsetCoords);
|
||||||
_activeTiles.RemoveChild(tile3D);
|
_activeTiles.RemoveChild(tile3D);
|
||||||
tile3D.Disconnect("TileClicked", this, nameof(OnTileClicked));
|
tile3D.Disconnect("TileClicked", this, nameof(OnTileClicked));
|
||||||
|
@ -134,26 +121,21 @@ public class StreamContainer : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void MarkUnusedTiles(Rect2 expandedRect, Rect2 clippedRect)
|
public void MarkUnusedTiles(Rect2 expandedRect, Rect2 clippedRect) {
|
||||||
{
|
|
||||||
foreach (int coord_x in Enumerable.Range(Mathf.FloorToInt(expandedRect.Position.x) - 5,
|
foreach (int coord_x in Enumerable.Range(Mathf.FloorToInt(expandedRect.Position.x) - 5,
|
||||||
Mathf.CeilToInt(expandedRect.Size.x) + 20))
|
Mathf.CeilToInt(expandedRect.Size.x) + 20)) {
|
||||||
{
|
|
||||||
foreach (int coord_y in Enumerable.Range(Mathf.FloorToInt(expandedRect.Position.y) - 5,
|
foreach (int coord_y in Enumerable.Range(Mathf.FloorToInt(expandedRect.Position.y) - 5,
|
||||||
Mathf.CeilToInt(expandedRect.Size.y) + 20))
|
Mathf.CeilToInt(expandedRect.Size.y) + 20)) {
|
||||||
{
|
Vector2 coord = new(coord_x, coord_y);
|
||||||
Vector2 coord = new Vector2(coord_x, coord_y);
|
|
||||||
|
|
||||||
if (clippedRect.HasPoint(coord))
|
if (clippedRect.HasPoint(coord)) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isInCurrent = _currentOffsetCoordRect.HasPoint(coord);
|
bool isInCurrent = _currentOffsetCoordRect.HasPoint(coord);
|
||||||
bool isInOld = _oldOffsetCoordRect.HasPoint(coord);
|
bool isInOld = _oldOffsetCoordRect.HasPoint(coord);
|
||||||
|
|
||||||
if (isInOld && !isInCurrent && _coordToTile.Keys.Contains(coord))
|
if (isInOld && !isInCurrent && _coordToTile.Keys.Contains(coord)) {
|
||||||
{
|
|
||||||
HexTile3D tile3D = _coordToTile[coord];
|
HexTile3D tile3D = _coordToTile[coord];
|
||||||
|
|
||||||
OnTileDeactivate(tile3D, coord);
|
OnTileDeactivate(tile3D, coord);
|
||||||
|
@ -162,31 +144,23 @@ public class StreamContainer : Spatial
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddNewTiles(Rect2 expandedRect, Rect2 clippedRect)
|
public void AddNewTiles(Rect2 expandedRect, Rect2 clippedRect) {
|
||||||
{
|
|
||||||
foreach (int coord_x in Enumerable.Range(Mathf.FloorToInt(_currentOffsetCoordRect.Position.x),
|
foreach (int coord_x in Enumerable.Range(Mathf.FloorToInt(_currentOffsetCoordRect.Position.x),
|
||||||
Mathf.CeilToInt(_currentOffsetCoordRect.Size.x)))
|
Mathf.CeilToInt(_currentOffsetCoordRect.Size.x))) {
|
||||||
{
|
|
||||||
foreach (int coord_y in Enumerable.Range(Mathf.FloorToInt(_currentOffsetCoordRect.Position.y),
|
foreach (int coord_y in Enumerable.Range(Mathf.FloorToInt(_currentOffsetCoordRect.Position.y),
|
||||||
Mathf.CeilToInt(_currentOffsetCoordRect.Size.y)))
|
Mathf.CeilToInt(_currentOffsetCoordRect.Size.y))) {
|
||||||
{
|
Vector2 coord = new(coord_x, coord_y);
|
||||||
Vector2 coord = new Vector2(coord_x, coord_y);
|
|
||||||
|
|
||||||
if (clippedRect.HasPoint(coord))
|
if (clippedRect.HasPoint(coord)) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_unusedTiles.Count == 0)
|
if (_unusedTiles.Count == 0) {
|
||||||
{
|
|
||||||
AddedCoords.Add(coord);
|
AddedCoords.Add(coord);
|
||||||
HexTile3D tile3D = GetTile3dAt(coord);
|
HexTile3D tile3D = GetTile3dAt(coord);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
HexTile3D tile3D = _unusedTiles.Dequeue();
|
HexTile3D tile3D = _unusedTiles.Dequeue();
|
||||||
tile3D.OffsetCoords = coord;
|
tile3D.OffsetCoords = coord;
|
||||||
tile3D.Type = TileWorld.GetTileTypeAtOffset(coord);
|
|
||||||
Transform tileTransform = tile3D.Transform;
|
Transform tileTransform = tile3D.Transform;
|
||||||
tileTransform.origin.y = TileWorld.GetHeightAtOffset(coord);
|
tileTransform.origin.y = TileWorld.GetHeightAtOffset(coord);
|
||||||
tile3D.Transform = tileTransform;
|
tile3D.Transform = tileTransform;
|
||||||
|
@ -200,18 +174,15 @@ public class StreamContainer : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public HexTile3D GetTile3dAt(Vector2 offsetCoords)
|
public HexTile3D GetTile3dAt(Vector2 offsetCoords) {
|
||||||
{
|
if (!_coordToTile.Keys.Contains(offsetCoords)) {
|
||||||
if (!_coordToTile.Keys.Contains(offsetCoords))
|
|
||||||
{
|
|
||||||
HexTile3D tile3D = (HexTile3D)_hexTileScene.Instance();
|
HexTile3D tile3D = (HexTile3D)_hexTileScene.Instance();
|
||||||
tile3D.OffsetCoords = offsetCoords;
|
tile3D.OffsetCoords = offsetCoords;
|
||||||
_activeTiles.AddChild(tile3D);
|
_activeTiles.AddChild(tile3D);
|
||||||
tile3D.Connect("TileClicked", this, nameof(OnTileClicked));
|
tile3D.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||||
tile3D.Connect("TileHovered", this, nameof(OnTileHovered));
|
tile3D.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||||
|
|
||||||
if (ShowHexTiles)
|
if (ShowHexTiles) {
|
||||||
{
|
|
||||||
MeshInstance HexTileMesh = tile3D.GetNode<MeshInstance>("Mesh");
|
MeshInstance HexTileMesh = tile3D.GetNode<MeshInstance>("Mesh");
|
||||||
HexTileMesh.Transform = HexTileMesh.Transform.Scaled(new Vector3(0.95f, 1, 0.95f));
|
HexTileMesh.Transform = HexTileMesh.Transform.Scaled(new Vector3(0.95f, 1, 0.95f));
|
||||||
}
|
}
|
||||||
|
@ -219,7 +190,6 @@ public class StreamContainer : Spatial
|
||||||
Transform tileTransform = tile3D.Transform;
|
Transform tileTransform = tile3D.Transform;
|
||||||
tileTransform.origin.y = TileWorld.GetHeightAtOffset(offsetCoords);
|
tileTransform.origin.y = TileWorld.GetHeightAtOffset(offsetCoords);
|
||||||
tile3D.Transform = tileTransform;
|
tile3D.Transform = tileTransform;
|
||||||
tile3D.Type = TileWorld.GetTileTypeAtOffset(offsetCoords);
|
|
||||||
|
|
||||||
_tileToInstanceIndex[tile3D] = _tileToInstanceIndex.Count;
|
_tileToInstanceIndex[tile3D] = _tileToInstanceIndex.Count;
|
||||||
|
|
||||||
|
@ -231,18 +201,14 @@ public class StreamContainer : Spatial
|
||||||
return _coordToTile[offsetCoords];
|
return _coordToTile[offsetCoords];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCenterTile(HexCell cell)
|
public void SetCenterTile(HexCell cell) {
|
||||||
{
|
|
||||||
UpdateRects(_hexGrid.GetHexCenter(cell));
|
UpdateRects(_hexGrid.GetHexCenter(cell));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTileMaterial(ShaderMaterial material)
|
public void SetTileMaterial(ShaderMaterial material) {
|
||||||
{
|
foreach (Spatial node in _activeTiles.GetChildren()) {
|
||||||
foreach (Spatial node in _activeTiles.GetChildren())
|
|
||||||
{
|
|
||||||
HexTile3D tile = (HexTile3D)node;
|
HexTile3D tile = (HexTile3D)node;
|
||||||
if (tile == null)
|
if (tile == null) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,50 +216,43 @@ public class StreamContainer : Spatial
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTileActivate(HexTile3D tile3D)
|
public void OnTileActivate(HexTile3D tile3D) {
|
||||||
{
|
|
||||||
int instanceIndex = _tileToInstanceIndex[tile3D];
|
int instanceIndex = _tileToInstanceIndex[tile3D];
|
||||||
|
|
||||||
Vector3 scale = Vector3.One;
|
Vector3 scale = Vector3.One;
|
||||||
if (ShowHexTiles)
|
if (ShowHexTiles) {
|
||||||
{
|
|
||||||
scale.x *= 0.96f;
|
scale.x *= 0.96f;
|
||||||
scale.z *= 0.96f;
|
scale.z *= 0.96f;
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform instanceTransform = new Transform(tile3D.GlobalTransform.basis.Rotated(Vector3.Up, Mathf.Deg2Rad(30)).Scaled(scale), tile3D.GlobalTransform.origin + Vector3.Up * -2.5f);
|
Transform instanceTransform =
|
||||||
|
new(tile3D.GlobalTransform.basis.Rotated(Vector3.Up, Mathf.Deg2Rad(30)).Scaled(scale),
|
||||||
|
tile3D.GlobalTransform.origin + Vector3.Up * -2.5f);
|
||||||
|
|
||||||
_tileMultiMesh.Multimesh.SetInstanceTransform(instanceIndex, instanceTransform);
|
_tileMultiMesh.Multimesh.SetInstanceTransform(instanceIndex, instanceTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTileDeactivate(HexTile3D tile3D, Vector2 coord)
|
public void OnTileDeactivate(HexTile3D tile3D, Vector2 coord) {
|
||||||
{
|
|
||||||
int instanceIndex = _tileToInstanceIndex[tile3D];
|
int instanceIndex = _tileToInstanceIndex[tile3D];
|
||||||
_tileMultiMesh.Multimesh.SetInstanceTransform(instanceIndex, _deactivatedTileTransform);
|
_tileMultiMesh.Multimesh.SetInstanceTransform(instanceIndex, _deactivatedTileTransform);
|
||||||
|
|
||||||
tile3D.Type = HexTile3D.TileType.Undefined;
|
|
||||||
_unusedTiles.Enqueue(tile3D);
|
_unusedTiles.Enqueue(tile3D);
|
||||||
_coordToTile.Remove(coord);
|
_coordToTile.Remove(coord);
|
||||||
RemovedCoords.Add(coord);
|
RemovedCoords.Add(coord);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTileClicked(HexTile3D tile)
|
public void OnTileClicked(HexTile3D tile) {
|
||||||
{
|
|
||||||
EmitSignal("TileClicked", tile);
|
EmitSignal("TileClicked", tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTileHovered(HexTile3D tile)
|
public void OnTileHovered(HexTile3D tile) {
|
||||||
{
|
|
||||||
EmitSignal("TileHovered", tile);
|
EmitSignal("TileHovered", tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnWorldGenerated()
|
public void OnWorldGenerated() {
|
||||||
{
|
foreach (Spatial node in _activeTiles.GetChildren()) {
|
||||||
foreach (Spatial node in _activeTiles.GetChildren())
|
|
||||||
{
|
|
||||||
HexTile3D tile = (HexTile3D)node;
|
HexTile3D tile = (HexTile3D)node;
|
||||||
if (tile == null)
|
if (tile == null) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,7 @@ using Godot;
|
||||||
using Godot.Collections;
|
using Godot.Collections;
|
||||||
using Namespace;
|
using Namespace;
|
||||||
|
|
||||||
public class TileWorld : Spatial
|
public class TileWorld : Spatial {
|
||||||
{
|
|
||||||
// exports
|
// exports
|
||||||
[Export] public bool DebugMap;
|
[Export] public bool DebugMap;
|
||||||
[ExportFlagsEnum(typeof(MapType))] public MapType GenerationMapType = MapType.Debug;
|
[ExportFlagsEnum(typeof(MapType))] public MapType GenerationMapType = MapType.Debug;
|
||||||
|
@ -21,8 +20,7 @@ public class TileWorld : Spatial
|
||||||
private Spatial _environmentNode;
|
private Spatial _environmentNode;
|
||||||
private readonly Array<Spatial> _grassAssets = new();
|
private readonly Array<Spatial> _grassAssets = new();
|
||||||
|
|
||||||
private enum GenerationState
|
private enum GenerationState {
|
||||||
{
|
|
||||||
Heightmap,
|
Heightmap,
|
||||||
Color,
|
Color,
|
||||||
Objects,
|
Objects,
|
||||||
|
@ -34,8 +32,7 @@ public class TileWorld : Spatial
|
||||||
private delegate void WorldGenerated();
|
private delegate void WorldGenerated();
|
||||||
|
|
||||||
// public members
|
// public members
|
||||||
public enum MapType
|
public enum MapType {
|
||||||
{
|
|
||||||
Noise,
|
Noise,
|
||||||
Debug,
|
Debug,
|
||||||
Flat
|
Flat
|
||||||
|
@ -62,8 +59,7 @@ public class TileWorld : Spatial
|
||||||
private Viewport _worldOffscreenViewport;
|
private Viewport _worldOffscreenViewport;
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
HexGrid = new HexGrid();
|
HexGrid = new HexGrid();
|
||||||
_tileTypeRandom = new Random();
|
_tileTypeRandom = new Random();
|
||||||
|
|
||||||
|
@ -83,18 +79,15 @@ public class TileWorld : Spatial
|
||||||
|
|
||||||
GetNode<Spatial>("Assets").Visible = false;
|
GetNode<Spatial>("Assets").Visible = false;
|
||||||
|
|
||||||
foreach (Spatial asset in GetNode<Node>("Assets/Rocks").GetChildren())
|
foreach (Spatial asset in GetNode<Node>("Assets/Rocks").GetChildren()) {
|
||||||
{
|
|
||||||
_rockAssets.Add(asset);
|
_rockAssets.Add(asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Spatial asset in GetNode<Node>("Assets/Grass").GetChildren())
|
foreach (Spatial asset in GetNode<Node>("Assets/Grass").GetChildren()) {
|
||||||
{
|
|
||||||
_grassAssets.Add(asset);
|
_grassAssets.Add(asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Spatial asset in GetNode<Node>("Assets/Trees").GetChildren())
|
foreach (Spatial asset in GetNode<Node>("Assets/Trees").GetChildren()) {
|
||||||
{
|
|
||||||
_treeAssets.Add(asset);
|
_treeAssets.Add(asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,8 +99,7 @@ public class TileWorld : Spatial
|
||||||
ResetWorldImages(Size);
|
ResetWorldImages(Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetWorldImages(int size)
|
public void ResetWorldImages(int size) {
|
||||||
{
|
|
||||||
GD.Print("Resetting World Images to size " + size);
|
GD.Print("Resetting World Images to size " + size);
|
||||||
|
|
||||||
Vector2 sizeVector = new Vector2(size, size);
|
Vector2 sizeVector = new Vector2(size, size);
|
||||||
|
@ -130,12 +122,10 @@ public class TileWorld : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Generate(int size)
|
public void Generate(int size) {
|
||||||
{
|
|
||||||
GD.Print("Triggering generation for size: " + size);
|
GD.Print("Triggering generation for size: " + size);
|
||||||
|
|
||||||
if (Size != size)
|
if (Size != size) {
|
||||||
{
|
|
||||||
ResetWorldImages(size);
|
ResetWorldImages(size);
|
||||||
_resizeTriggered = true;
|
_resizeTriggered = true;
|
||||||
_resizeExtraFrameCount = 1;
|
_resizeExtraFrameCount = 1;
|
||||||
|
@ -153,8 +143,7 @@ public class TileWorld : Spatial
|
||||||
|
|
||||||
OnMapGenerationStart();
|
OnMapGenerationStart();
|
||||||
|
|
||||||
switch (GenerationMapType)
|
switch (GenerationMapType) {
|
||||||
{
|
|
||||||
case MapType.Debug:
|
case MapType.Debug:
|
||||||
GenerateDebugMap();
|
GenerateDebugMap();
|
||||||
break;
|
break;
|
||||||
|
@ -167,8 +156,7 @@ public class TileWorld : Spatial
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateDebugMap()
|
private void GenerateDebugMap() {
|
||||||
{
|
|
||||||
ColormapImage = new Image();
|
ColormapImage = new Image();
|
||||||
ColormapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
ColormapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
||||||
|
|
||||||
|
@ -178,10 +166,8 @@ public class TileWorld : Spatial
|
||||||
HeightmapImage.Lock();
|
HeightmapImage.Lock();
|
||||||
ColormapImage.Lock();
|
ColormapImage.Lock();
|
||||||
|
|
||||||
foreach (int coordX in Enumerable.Range(0, Size))
|
foreach (int coordX in Enumerable.Range(0, Size)) {
|
||||||
{
|
foreach (int coordY in Enumerable.Range(0, Size)) {
|
||||||
foreach (int coordY in Enumerable.Range(0, Size))
|
|
||||||
{
|
|
||||||
ColormapImage.SetPixel(coordX, coordY,
|
ColormapImage.SetPixel(coordX, coordY,
|
||||||
new Color((float)Mathf.Min(coordX, coordY) / Size, 0, 0));
|
new Color((float)Mathf.Min(coordX, coordY) / Size, 0, 0));
|
||||||
HeightmapImage.SetPixel(coordX, coordY,
|
HeightmapImage.SetPixel(coordX, coordY,
|
||||||
|
@ -197,8 +183,7 @@ public class TileWorld : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void GenerateFlatMap()
|
private void GenerateFlatMap() {
|
||||||
{
|
|
||||||
ColormapImage = new Image();
|
ColormapImage = new Image();
|
||||||
ColormapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
ColormapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
||||||
|
|
||||||
|
@ -208,10 +193,8 @@ public class TileWorld : Spatial
|
||||||
HeightmapImage.Lock();
|
HeightmapImage.Lock();
|
||||||
ColormapImage.Lock();
|
ColormapImage.Lock();
|
||||||
|
|
||||||
foreach (int coordX in Enumerable.Range(0, Size))
|
foreach (int coordX in Enumerable.Range(0, Size)) {
|
||||||
{
|
foreach (int coordY in Enumerable.Range(0, Size)) {
|
||||||
foreach (int coordY in Enumerable.Range(0, Size))
|
|
||||||
{
|
|
||||||
HeightmapImage.SetPixel(coordX, coordY,
|
HeightmapImage.SetPixel(coordX, coordY,
|
||||||
new Color(0.5f, 0.5f, 0.5f));
|
new Color(0.5f, 0.5f, 0.5f));
|
||||||
}
|
}
|
||||||
|
@ -224,8 +207,7 @@ public class TileWorld : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void GenerateNoiseMap()
|
private void GenerateNoiseMap() {
|
||||||
{
|
|
||||||
HeightmapImage = new Image();
|
HeightmapImage = new Image();
|
||||||
HeightmapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
HeightmapImage.Create(Size, Size, false, Image.Format.Rgba8);
|
||||||
|
|
||||||
|
@ -245,28 +227,23 @@ public class TileWorld : Spatial
|
||||||
OnHeightMapChanged();
|
OnHeightMapChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMapGenerationStart()
|
private void OnMapGenerationStart() {
|
||||||
{
|
foreach (Node child in _environmentNode.GetChildren()) {
|
||||||
foreach (Node child in _environmentNode.GetChildren())
|
|
||||||
{
|
|
||||||
child.QueueFree();
|
child.QueueFree();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Node child in Entities.GetChildren())
|
foreach (Node child in Entities.GetChildren()) {
|
||||||
{
|
|
||||||
child.QueueFree();
|
child.QueueFree();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnHeightMapChanged()
|
private void OnHeightMapChanged() {
|
||||||
{
|
|
||||||
GD.Print("Triggering rendering of height map");
|
GD.Print("Triggering rendering of height map");
|
||||||
_currentGenerationState = GenerationState.Heightmap;
|
_currentGenerationState = GenerationState.Heightmap;
|
||||||
_heightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once;
|
_heightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMapGenerationComplete()
|
private void OnMapGenerationComplete() {
|
||||||
{
|
|
||||||
_currentGenerationState = GenerationState.Done;
|
_currentGenerationState = GenerationState.Done;
|
||||||
_worldOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
_worldOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
||||||
_heightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
_heightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
|
||||||
|
@ -276,10 +253,9 @@ public class TileWorld : Spatial
|
||||||
EmitSignal("WorldGenerated");
|
EmitSignal("WorldGenerated");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Spatial SelectAsset(Vector2 offsetCoord, Array<Spatial> assets, Random randomGenerator, double probability)
|
private Spatial SelectAsset(Vector2 offsetCoord, Array<Spatial> assets, Random randomGenerator,
|
||||||
{
|
double probability) {
|
||||||
if (randomGenerator.NextDouble() < 1.0 - probability)
|
if (randomGenerator.NextDouble() < 1.0 - probability) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,66 +271,52 @@ public class TileWorld : Spatial
|
||||||
return assetInstance;
|
return assetInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsColorEqualApprox(Color colorA, Color colorB)
|
private bool IsColorEqualApprox(Color colorA, Color colorB) {
|
||||||
{
|
|
||||||
Vector3 colorDifference = new Vector3(colorA.r - colorB.r, colorA.g - colorB.g, colorA.b - colorB.b);
|
Vector3 colorDifference = new Vector3(colorA.r - colorB.r, colorA.g - colorB.g, colorA.b - colorB.b);
|
||||||
return colorDifference.LengthSquared() < 0.1 * 0.1;
|
return colorDifference.LengthSquared() < 0.1 * 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsColorWater(Color color)
|
private bool IsColorWater(Color color) {
|
||||||
{
|
|
||||||
return (color.r == 0 && color.g == 0 && color.b > 0.01);
|
return (color.r == 0 && color.g == 0 && color.b > 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MarkCellUnwalkable(HexCell cell)
|
public void MarkCellUnwalkable(HexCell cell) {
|
||||||
{
|
|
||||||
HexGrid.AddObstacle(cell);
|
HexGrid.AddObstacle(cell);
|
||||||
NavigationmapImage.Lock();
|
NavigationmapImage.Lock();
|
||||||
NavigationmapImage.SetPixelv(OffsetToTextureCoord(cell.OffsetCoords), Colors.Red);
|
NavigationmapImage.SetPixelv(OffsetToTextureCoord(cell.OffsetCoords), Colors.Red);
|
||||||
NavigationmapImage.Unlock();
|
NavigationmapImage.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulateEnvironment()
|
private void PopulateEnvironment() {
|
||||||
{
|
|
||||||
Random environmentRandom = new Random(Seed);
|
Random environmentRandom = new Random(Seed);
|
||||||
|
|
||||||
ColormapImage.Lock();
|
ColormapImage.Lock();
|
||||||
HeightmapImage.Lock();
|
HeightmapImage.Lock();
|
||||||
|
|
||||||
foreach (int textureCoordU in Enumerable.Range(0, Size))
|
foreach (int textureCoordU in Enumerable.Range(0, Size)) {
|
||||||
{
|
foreach (int textureCoordV in Enumerable.Range(0, Size)) {
|
||||||
foreach (int textureCoordV in Enumerable.Range(0, Size))
|
|
||||||
{
|
|
||||||
Color colorValue = ColormapImage.GetPixel(textureCoordU, textureCoordV);
|
Color colorValue = ColormapImage.GetPixel(textureCoordU, textureCoordV);
|
||||||
Vector2 textureCoord = new Vector2(textureCoordU, textureCoordV);
|
Vector2 textureCoord = new Vector2(textureCoordU, textureCoordV);
|
||||||
HexCell cell = TextureCoordToCell(textureCoord);
|
HexCell cell = TextureCoordToCell(textureCoord);
|
||||||
Vector2 offsetCoord = cell.OffsetCoords;
|
Vector2 offsetCoord = cell.OffsetCoords;
|
||||||
|
|
||||||
if (IsColorEqualApprox(colorValue, RockColor))
|
if (IsColorEqualApprox(colorValue, RockColor)) {
|
||||||
{
|
|
||||||
Spatial rockAsset = SelectAsset(offsetCoord, _rockAssets, environmentRandom, 0.15);
|
Spatial rockAsset = SelectAsset(offsetCoord, _rockAssets, environmentRandom, 0.15);
|
||||||
if (rockAsset != null)
|
if (rockAsset != null) {
|
||||||
{
|
|
||||||
_environmentNode.AddChild(rockAsset);
|
_environmentNode.AddChild(rockAsset);
|
||||||
MarkCellUnwalkable(cell);
|
MarkCellUnwalkable(cell);
|
||||||
}
|
}
|
||||||
}
|
} else if (IsColorEqualApprox(colorValue, GrassColor)) {
|
||||||
else if (IsColorEqualApprox(colorValue, GrassColor))
|
|
||||||
{
|
|
||||||
Spatial grassAsset = SelectAsset(offsetCoord, _grassAssets, environmentRandom, 0.35);
|
Spatial grassAsset = SelectAsset(offsetCoord, _grassAssets, environmentRandom, 0.35);
|
||||||
if (grassAsset != null)
|
if (grassAsset != null) {
|
||||||
{
|
|
||||||
_environmentNode.AddChild(grassAsset);
|
_environmentNode.AddChild(grassAsset);
|
||||||
}
|
}
|
||||||
|
|
||||||
Spatial treeAsset = SelectAsset(offsetCoord, _treeAssets, environmentRandom, 0.10);
|
Spatial treeAsset = SelectAsset(offsetCoord, _treeAssets, environmentRandom, 0.10);
|
||||||
if (treeAsset != null)
|
if (treeAsset != null) {
|
||||||
{
|
|
||||||
Entities.AddChild(treeAsset);
|
Entities.AddChild(treeAsset);
|
||||||
MarkCellUnwalkable(cell);
|
MarkCellUnwalkable(cell);
|
||||||
}
|
} else if (environmentRandom.NextDouble() < 0.01) {
|
||||||
else if (environmentRandom.NextDouble() < 0.01)
|
|
||||||
{
|
|
||||||
Chest chestAsset = (Chest)_chestScene.Instance();
|
Chest chestAsset = (Chest)_chestScene.Instance();
|
||||||
Transform assetTransform = Transform.Identity;
|
Transform assetTransform = Transform.Identity;
|
||||||
assetTransform.origin = GetHexCenterFromOffset(offsetCoord);
|
assetTransform.origin = GetHexCenterFromOffset(offsetCoord);
|
||||||
|
@ -363,9 +325,7 @@ public class TileWorld : Spatial
|
||||||
Entities.AddChild(chestAsset);
|
Entities.AddChild(chestAsset);
|
||||||
MarkCellUnwalkable(cell);
|
MarkCellUnwalkable(cell);
|
||||||
}
|
}
|
||||||
}
|
} else if (IsColorWater(colorValue)) {
|
||||||
else if (IsColorWater(colorValue))
|
|
||||||
{
|
|
||||||
MarkCellUnwalkable(cell);
|
MarkCellUnwalkable(cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -375,16 +335,13 @@ public class TileWorld : Spatial
|
||||||
ColormapImage.Unlock();
|
ColormapImage.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process(float delta)
|
public override void _Process(float delta) {
|
||||||
{
|
if (_resizeTriggered && _resizeExtraFrameCount > 0) {
|
||||||
if (_resizeTriggered && _resizeExtraFrameCount > 0)
|
|
||||||
{
|
|
||||||
_resizeExtraFrameCount--;
|
_resizeExtraFrameCount--;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentGenerationState == GenerationState.Heightmap)
|
if (_currentGenerationState == GenerationState.Heightmap) {
|
||||||
{
|
|
||||||
HeightmapImage.CopyFrom(_heightmapOffscreenViewport.GetTexture().GetData());
|
HeightmapImage.CopyFrom(_heightmapOffscreenViewport.GetTexture().GetData());
|
||||||
|
|
||||||
_currentGenerationState = GenerationState.Color;
|
_currentGenerationState = GenerationState.Color;
|
||||||
|
@ -397,9 +354,7 @@ public class TileWorld : Spatial
|
||||||
|
|
||||||
_worldOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once;
|
_worldOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once;
|
||||||
_resizeExtraFrameCount = 1;
|
_resizeExtraFrameCount = 1;
|
||||||
}
|
} else if (_currentGenerationState == GenerationState.Color) {
|
||||||
else if (_currentGenerationState == GenerationState.Color)
|
|
||||||
{
|
|
||||||
ColormapImage = new Image();
|
ColormapImage = new Image();
|
||||||
ColormapImage.Create(Size, Size, false, Image.Format.Rgb8);
|
ColormapImage.Create(Size, Size, false, Image.Format.Rgb8);
|
||||||
ColormapImage.CopyFrom(_worldOffscreenViewport.GetTexture().GetData());
|
ColormapImage.CopyFrom(_worldOffscreenViewport.GetTexture().GetData());
|
||||||
|
@ -407,49 +362,30 @@ public class TileWorld : Spatial
|
||||||
_currentGenerationState = GenerationState.Objects;
|
_currentGenerationState = GenerationState.Objects;
|
||||||
|
|
||||||
PopulateEnvironment();
|
PopulateEnvironment();
|
||||||
}
|
} else if (_currentGenerationState == GenerationState.Objects) {
|
||||||
else if (_currentGenerationState == GenerationState.Objects)
|
|
||||||
{
|
|
||||||
OnMapGenerationComplete();
|
OnMapGenerationComplete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsOffsetCoordValid(Vector2 offsetCoord)
|
public bool IsOffsetCoordValid(Vector2 offsetCoord) {
|
||||||
{
|
|
||||||
return ((int)Math.Clamp(offsetCoord.x, -(float)Size / 2, (float)Size / 2 - 1) == (int)offsetCoord.x
|
return ((int)Math.Clamp(offsetCoord.x, -(float)Size / 2, (float)Size / 2 - 1) == (int)offsetCoord.x
|
||||||
&& (int)Math.Clamp(offsetCoord.y, -(float)Size / 2, (float)Size / 2 - 1) == (int)offsetCoord.y);
|
&& (int)Math.Clamp(offsetCoord.y, -(float)Size / 2, (float)Size / 2 - 1) == (int)offsetCoord.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public 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 mapSize = Vector2.One * Size;
|
||||||
Vector2 textureCoord = (offsetCoord + mapSize / 2).PosMod(mapSize);
|
Vector2 textureCoord = (offsetCoord + mapSize / 2).PosMod(mapSize);
|
||||||
return textureCoord;
|
return textureCoord;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetHeightAtOffset(Vector2 offsetCoord, float height)
|
public void SetHeightAtOffset(Vector2 offsetCoord, float height) {
|
||||||
{
|
|
||||||
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
|
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
|
||||||
|
|
||||||
HeightmapImage.SetPixel((int)textureCoord.x, (int)textureCoord.y, new Color(height, 0f, 0f));
|
HeightmapImage.SetPixel((int)textureCoord.x, (int)textureCoord.y, new Color(height, 0f, 0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetHeightAtOffset(Vector2 offsetCoord)
|
public float GetHeightAtOffset(Vector2 offsetCoord) {
|
||||||
{
|
if (_currentGenerationState != GenerationState.Done) {
|
||||||
if (_currentGenerationState != GenerationState.Done)
|
|
||||||
{
|
|
||||||
return 0f;
|
return 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,8 +403,7 @@ public class TileWorld : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void SetTileColorAtOffset(Vector2 offsetCoord, Color color)
|
public void SetTileColorAtOffset(Vector2 offsetCoord, Color color) {
|
||||||
{
|
|
||||||
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
|
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
|
||||||
|
|
||||||
ColormapImage.Lock();
|
ColormapImage.Lock();
|
||||||
|
@ -476,32 +411,27 @@ public class TileWorld : Spatial
|
||||||
ColormapImage.Unlock();
|
ColormapImage.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 WorldToOffsetCoords(Vector3 worldCoord)
|
public Vector2 WorldToOffsetCoords(Vector3 worldCoord) {
|
||||||
{
|
|
||||||
return HexGrid.GetHexAt(new Vector2(worldCoord.x, worldCoord.z)).OffsetCoords +
|
return HexGrid.GetHexAt(new Vector2(worldCoord.x, worldCoord.z)).OffsetCoords +
|
||||||
Vector2.One * Mathf.Round(Size / 2f);
|
Vector2.One * Mathf.Round(Size / 2f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 GetTileWorldCenterFromOffset(Vector2 offsetCoord)
|
public Vector3 GetTileWorldCenterFromOffset(Vector2 offsetCoord) {
|
||||||
{
|
|
||||||
Vector2 tileCenter = HexGrid.GetHexCenterFromOffset(offsetCoord - Vector2.One * Mathf.Round(Size / 2f));
|
Vector2 tileCenter = HexGrid.GetHexCenterFromOffset(offsetCoord - Vector2.One * Mathf.Round(Size / 2f));
|
||||||
return new Vector3(tileCenter.x, GetHeightAtOffset(offsetCoord), tileCenter.y);
|
return new Vector3(tileCenter.x, GetHeightAtOffset(offsetCoord), tileCenter.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Vector3 GetHexCenterFromOffset(Vector2 offsetCoord)
|
public Vector3 GetHexCenterFromOffset(Vector2 offsetCoord) {
|
||||||
{
|
|
||||||
Vector2 tileCenter = HexGrid.GetHexCenterFromOffset(offsetCoord);
|
Vector2 tileCenter = HexGrid.GetHexCenterFromOffset(offsetCoord);
|
||||||
return new Vector3(tileCenter.x, GetHeightAtOffset(offsetCoord), tileCenter.y);
|
return new Vector3(tileCenter.x, GetHeightAtOffset(offsetCoord), tileCenter.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HexCell TextureCoordToCell(Vector2 textureCoord)
|
public HexCell TextureCoordToCell(Vector2 textureCoord) {
|
||||||
{
|
|
||||||
return HexCell.FromOffsetCoords(textureCoord - Vector2.One * _halfSize);
|
return HexCell.FromOffsetCoords(textureCoord - Vector2.One * _halfSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 TextureCoordToOffsetCoord(Vector2 textureCoord)
|
public Vector2 TextureCoordToOffsetCoord(Vector2 textureCoord) {
|
||||||
{
|
|
||||||
return TextureCoordToCell(textureCoord).OffsetCoords;
|
return TextureCoordToCell(textureCoord).OffsetCoords;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[ext_resource path="res://scenes/TileWorld.cs" type="Script" id=1]
|
[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://icon.png" type="Texture" id=2]
|
||||||
[ext_resource path="res://materials/IslandColorRampShader.tres" type="Material" id=3]
|
[ext_resource path="res://materials/WorldTileTypeMaterial.tres" type="Material" id=3]
|
||||||
[ext_resource path="res://materials/IslandHeightmapFalloffShader.tres" type="Material" id=4]
|
[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/rockB.tscn" type="PackedScene" id=5]
|
||||||
[ext_resource path="res://entities/rockC.tscn" type="PackedScene" id=6]
|
[ext_resource path="res://entities/rockC.tscn" type="PackedScene" id=6]
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
[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 )
|
612
scenes/World.cs
612
scenes/World.cs
|
@ -4,12 +4,11 @@ using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Godot;
|
using Godot;
|
||||||
using Godot.Collections;
|
using Godot.Collections;
|
||||||
|
using Priority_Queue;
|
||||||
|
|
||||||
public class World : Spatial
|
public class World : Spatial {
|
||||||
{
|
public enum GenerationState {
|
||||||
public enum GenerationState
|
Empty,
|
||||||
{
|
|
||||||
Undefined,
|
|
||||||
Heightmap,
|
Heightmap,
|
||||||
TileType,
|
TileType,
|
||||||
Objects,
|
Objects,
|
||||||
|
@ -17,32 +16,30 @@ public class World : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
public const int ChunkSize = 12;
|
public int ChunkSize = 14;
|
||||||
public const int NumChunkRows = 3;
|
public const int NumChunkRows = 3;
|
||||||
public const int NumChunkColumns = NumChunkRows;
|
public const int NumChunkColumns = NumChunkRows;
|
||||||
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 readonly System.Collections.Generic.Dictionary<int, HexTile3D.TileTypeInfo> _tileTypeInfos = new();
|
||||||
private static readonly Color LightWaterColor = new(0.05882353f, 0.05882353f, 0.8627451f);
|
|
||||||
|
|
||||||
private readonly Godot.Collections.Dictionary<Vector2, WorldChunk> _cachedWorldChunks;
|
private readonly Godot.Collections.Dictionary<Vector2, WorldChunk> _cachedWorldChunks;
|
||||||
private readonly List<Vector2> _addedChunkIndices = new();
|
private readonly List<Vector2> _addedChunkIndices = new();
|
||||||
private readonly List<WorldChunk> _unusedWorldChunks = new();
|
private readonly List<WorldChunk> _deactivatedWorldChunks = new();
|
||||||
private readonly Image _heightmapImage = new();
|
private readonly Image _heightmapImage = new();
|
||||||
private readonly List<Vector2> _removedChunkIndices = new();
|
private readonly List<Vector2> _removedChunkIndices = new();
|
||||||
private readonly Image _tileTypeMapImage = new();
|
private readonly Image _tileTypeMapImage = new();
|
||||||
private int FrameCounter;
|
|
||||||
|
|
||||||
// referenced scenes
|
// referenced scenes
|
||||||
private readonly PackedScene _worldChunkScene = GD.Load<PackedScene>("res://scenes/WorldChunk.tscn");
|
private readonly PackedScene _worldChunkScene = GD.Load<PackedScene>("res://scenes/WorldChunk.tscn");
|
||||||
|
|
||||||
private List<Vector2> _activeChunkIndices = new();
|
private List<Vector2> _activeChunkIndices = new();
|
||||||
private Rect2 _centerChunkRect;
|
private Rect2 _centerChunkRect;
|
||||||
|
private readonly List<Spatial> _removedSpatialNodes = new();
|
||||||
|
|
||||||
// delegate void OnCoordClicked(Vector2 world_pos);
|
// delegate void OnCoordClicked(Vector2 world_pos);
|
||||||
|
|
||||||
// other members
|
// other members
|
||||||
private Vector2 _centerPlaneCoord;
|
|
||||||
private Vector2 _chunkIndexNorthEast;
|
private Vector2 _chunkIndexNorthEast;
|
||||||
private Vector2 _chunkIndexSouthWest;
|
private Vector2 _chunkIndexSouthWest;
|
||||||
private Array<Spatial> _grassAssets;
|
private Array<Spatial> _grassAssets;
|
||||||
|
@ -60,10 +57,9 @@ public class World : Spatial
|
||||||
public HexGrid HexGrid = new();
|
public HexGrid HexGrid = new();
|
||||||
public int Seed = 0;
|
public int Seed = 0;
|
||||||
|
|
||||||
public GenerationState State = GenerationState.Done;
|
public GenerationState State = GenerationState.Empty;
|
||||||
public Vector2 WorldTextureCoordinateOffset;
|
public Vector2 WorldTextureCoordinateOffset;
|
||||||
|
|
||||||
|
|
||||||
// ui elements
|
// ui elements
|
||||||
|
|
||||||
// scene nodes
|
// scene nodes
|
||||||
|
@ -93,43 +89,60 @@ public class World : Spatial
|
||||||
[Signal]
|
[Signal]
|
||||||
private delegate void TileHovered(HexTile3D tile3d);
|
private delegate void TileHovered(HexTile3D tile3d);
|
||||||
|
|
||||||
public World()
|
public World() {
|
||||||
{
|
|
||||||
Debug.Assert(ChunkSize % 2 == 0);
|
Debug.Assert(ChunkSize % 2 == 0);
|
||||||
|
|
||||||
_cachedWorldChunks = new Godot.Collections.Dictionary<Vector2, WorldChunk>();
|
_cachedWorldChunks = new Godot.Collections.Dictionary<Vector2, WorldChunk>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
Chunks = (Spatial)FindNode("Chunks");
|
Chunks = (Spatial)FindNode("Chunks");
|
||||||
Debug.Assert(Chunks != null);
|
Debug.Assert(Chunks != null);
|
||||||
|
|
||||||
_tileMultiMeshInstance = (MultiMeshInstance)FindNode("TileMultiMeshInstance");
|
_tileMultiMeshInstance = (MultiMeshInstance)FindNode("TileMultiMeshInstance");
|
||||||
Debug.Assert(_tileMultiMeshInstance != null);
|
Debug.Assert(_tileMultiMeshInstance != null);
|
||||||
_tileMultiMeshInstance.Multimesh.InstanceCount =
|
|
||||||
ChunkSize * ChunkSize * NumChunkColumns * NumChunkRows;
|
|
||||||
_usedTileMeshInstances = 0;
|
|
||||||
|
|
||||||
InitNoiseGenerator();
|
InitNoiseGenerator();
|
||||||
|
|
||||||
GetNode<Spatial>("Assets").Visible = false;
|
GetNode<Spatial>("Assets").Visible = false;
|
||||||
|
|
||||||
_rockAssets = new Array<Spatial>();
|
_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);
|
|
||||||
|
|
||||||
_treeAssets = new Array<Spatial>();
|
|
||||||
foreach (Spatial asset in GetNode<Node>("Assets/Trees").GetChildren()) _treeAssets.Add(asset);
|
|
||||||
|
|
||||||
SetCenterPlaneCoord(Vector2.Zero);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InitNoiseGenerator()
|
_grassAssets = new Array<Spatial>();
|
||||||
{
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
_noiseGenerator = new OpenSimplexNoise();
|
_noiseGenerator = new OpenSimplexNoise();
|
||||||
|
|
||||||
_noiseGenerator.Seed = Seed;
|
_noiseGenerator.Seed = Seed;
|
||||||
|
@ -139,22 +152,36 @@ public class World : Spatial
|
||||||
_noiseGenerator.Lacunarity = 2;
|
_noiseGenerator.Lacunarity = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorldChunk GetOrCreateWorldChunk(Vector2 chunkIndex, Color debugColor)
|
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) {
|
||||||
WorldChunk chunk;
|
WorldChunk chunk;
|
||||||
|
|
||||||
if (IsChunkCached(chunkIndex))
|
if (IsChunkCached(chunkIndex)) {
|
||||||
return _cachedWorldChunks[chunkIndex];
|
return _cachedWorldChunks[chunkIndex];
|
||||||
|
|
||||||
if (_unusedWorldChunks.Count > 0)
|
|
||||||
{
|
|
||||||
chunk = _unusedWorldChunks.First();
|
|
||||||
_unusedWorldChunks.RemoveAt(0);
|
|
||||||
|
|
||||||
GD.Print("Reusing chunk from former index " + chunk.ChunkIndex + " at new index " + chunkIndex);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
if (_deactivatedWorldChunks.Count > 0) {
|
||||||
|
chunk = _deactivatedWorldChunks.First();
|
||||||
|
_deactivatedWorldChunks.RemoveAt(0);
|
||||||
|
} else {
|
||||||
chunk = CreateWorldChunk(chunkIndex, debugColor);
|
chunk = CreateWorldChunk(chunkIndex, debugColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,15 +190,14 @@ public class World : Spatial
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsChunkCached(Vector2 chunkIndex)
|
private bool IsChunkCached(Vector2 chunkIndex) {
|
||||||
{
|
|
||||||
return _cachedWorldChunks.ContainsKey(chunkIndex);
|
return _cachedWorldChunks.ContainsKey(chunkIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private WorldChunk CreateWorldChunk(Vector2 chunkIndex, Color debugColor)
|
private WorldChunk CreateWorldChunk(Vector2 chunkIndex, Color debugColor) {
|
||||||
{
|
|
||||||
WorldChunk result = (WorldChunk)_worldChunkScene.Instance();
|
WorldChunk result = (WorldChunk)_worldChunkScene.Instance();
|
||||||
|
result.SetSize(ChunkSize);
|
||||||
Chunks.AddChild(result);
|
Chunks.AddChild(result);
|
||||||
result.Connect("TileClicked", this, nameof(OnTileClicked));
|
result.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||||
result.Connect("TileHovered", this, nameof(OnTileHovered));
|
result.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||||
|
@ -191,15 +217,16 @@ public class World : Spatial
|
||||||
return result;
|
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);
|
Vector3 colorDifference = new(colorA.r - colorB.r, colorA.g - colorB.g, colorA.b - colorB.b);
|
||||||
return colorDifference.LengthSquared() < 0.1 * 0.1;
|
return colorDifference.LengthSquared() < 0.1 * 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Spatial SelectAsset(Vector2 textureCoord, Array<Spatial> assets, Random randomGenerator, double probability)
|
private Spatial SelectAsset(Vector2 textureCoord, Array<Spatial> assets, Random randomGenerator,
|
||||||
{
|
double probability) {
|
||||||
if (randomGenerator.NextDouble() < 1.0 - probability) return null;
|
if (randomGenerator.NextDouble() < 1.0 - probability) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
int assetIndex = randomGenerator.Next(assets.Count);
|
int assetIndex = randomGenerator.Next(assets.Count);
|
||||||
Spatial assetInstance = (Spatial)assets[assetIndex].Duplicate();
|
Spatial assetInstance = (Spatial)assets[assetIndex].Duplicate();
|
||||||
|
@ -214,41 +241,47 @@ public class World : Spatial
|
||||||
return assetInstance;
|
return assetInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulateChunk(WorldChunk chunk)
|
private void PopulateChunk(WorldChunk chunk) {
|
||||||
{
|
|
||||||
Random environmentRandom = new(Seed);
|
Random environmentRandom = new(Seed);
|
||||||
|
|
||||||
Image tileTypeImage = chunk.TileTypeOffscreenViewport.GetTexture().GetData();
|
chunk.CreateUnlockedTileTypeImage();
|
||||||
tileTypeImage.Lock();
|
|
||||||
|
|
||||||
foreach (int textureCoordU in Enumerable.Range(0, chunk.Size))
|
foreach (int textureCoordU in Enumerable.Range(0, chunk.Size)) {
|
||||||
foreach (int textureCoordV 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 textureCoord = new(textureCoordU, textureCoordV);
|
||||||
Vector2 offsetCoord = chunk.ChunkIndex * ChunkSize + textureCoord;
|
Vector2 offsetCoord = chunk.ChunkIndex * ChunkSize + textureCoord;
|
||||||
|
|
||||||
if (IsColorEqualApprox(colorValue, RockColor))
|
HexTile3D.TileTypeInfo tileTypeInfo = GetTileTypeInfoAtOffset(offsetCoord);
|
||||||
{
|
|
||||||
|
if (tileTypeInfo.Name == "Rock") {
|
||||||
Spatial rockAsset = SelectAsset(textureCoord, _rockAssets, environmentRandom, 0.15);
|
Spatial rockAsset = SelectAsset(textureCoord, _rockAssets, environmentRandom, 0.15);
|
||||||
if (rockAsset != null) chunk.Entities.AddChild(rockAsset);
|
if (rockAsset != null) {
|
||||||
// TODO: MarkCellUnwalkable(cell);
|
chunk.Entities.AddChild(rockAsset);
|
||||||
|
MarkCellUnwalkable(HexGrid.GetHexAtOffset(offsetCoord));
|
||||||
}
|
}
|
||||||
else if (IsColorEqualApprox(colorValue, GrassColor) || IsColorEqualApprox(colorValue, DarkGrassColor))
|
} else if (tileTypeInfo.Name == "Grass" || tileTypeInfo.Name == "DarkGrass") {
|
||||||
{
|
|
||||||
Spatial grassAsset = SelectAsset(textureCoord, _grassAssets, environmentRandom, 0.15);
|
Spatial grassAsset = SelectAsset(textureCoord, _grassAssets, environmentRandom, 0.15);
|
||||||
if (grassAsset != null) chunk.Entities.AddChild(grassAsset);
|
if (grassAsset != null) {
|
||||||
|
chunk.Entities.AddChild(grassAsset);
|
||||||
|
}
|
||||||
|
|
||||||
Tree treeAsset = SelectAsset(textureCoord, _treeAssets, environmentRandom, 0.05) as Tree;
|
Tree treeAsset = SelectAsset(textureCoord, _treeAssets, environmentRandom, 0.05) as Tree;
|
||||||
if (treeAsset != null)
|
if (treeAsset != null) {
|
||||||
{
|
|
||||||
chunk.Entities.AddChild(treeAsset);
|
chunk.Entities.AddChild(treeAsset);
|
||||||
treeAsset.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
treeAsset.Connect("EntityClicked", this, nameof(OnEntityClicked));
|
||||||
|
treeAsset.Connect("TreeChopped", this, nameof(OnBlockingSpatialRemoved));
|
||||||
|
MarkCellUnwalkable(HexGrid.GetHexAtOffset(offsetCoord));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: MarkCellUnwalkable(cell);
|
// TODO: MarkCellUnwalkable(cell);
|
||||||
// else if (environmentRandom.NextDouble() < 0.01)
|
// 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));
|
||||||
|
}
|
||||||
// {
|
// {
|
||||||
// var chestAsset = (Chest)_chestScene.Instance();
|
// var chestAsset = (Chest)_chestScene.Instance();
|
||||||
// var assetTransform = Transform.Identity;
|
// var assetTransform = Transform.Identity;
|
||||||
|
@ -264,46 +297,29 @@ public class World : Spatial
|
||||||
// MarkCellUnwalkable(cell);
|
// MarkCellUnwalkable(cell);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
tileTypeImage.Unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 WorldToOffsetCoords(Vector3 fromPositionWorld)
|
public Vector2 WorldToOffsetCoords(Vector3 fromPositionWorld) {
|
||||||
{
|
|
||||||
return HexGrid.GetHexAt(new Vector2(fromPositionWorld.x, fromPositionWorld.z)).OffsetCoords;
|
return HexGrid.GetHexAt(new Vector2(fromPositionWorld.x, fromPositionWorld.z)).OffsetCoords;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 GetHexCenterFromOffset(Vector2 fromPositionOffset)
|
public Vector3 GetHexCenterFromOffset(Vector2 fromPositionOffset) {
|
||||||
{
|
|
||||||
return HexGrid.GetHexCenterVec3FromOffset(fromPositionOffset);
|
return HexGrid.GetHexCenterVec3FromOffset(fromPositionOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateCenterChunkFromPlaneCoord(Vector2 planeCoord)
|
public void UpdateCenterChunkFromPlaneCoord(Vector2 planeCoord) {
|
||||||
{
|
if (State != GenerationState.Done && State != GenerationState.Empty) {
|
||||||
if (State != GenerationState.Done)
|
|
||||||
{
|
|
||||||
GD.PrintErr("Cannot update chunk to new planeCoord " + planeCoord + ": Chunk generation not yet finished!");
|
GD.PrintErr("Cannot update chunk to new planeCoord " + planeCoord + ": Chunk generation not yet finished!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GD.Print("Update Chunks: " + FrameCounter);
|
|
||||||
|
|
||||||
// mark all chunks as retired
|
// mark all chunks as retired
|
||||||
Godot.Collections.Dictionary<Vector2, WorldChunk> oldCachedChunks = new(_cachedWorldChunks);
|
Godot.Collections.Dictionary<Vector2, WorldChunk> oldCachedChunks = new(_cachedWorldChunks);
|
||||||
|
|
||||||
// set new center chunk
|
// set new center chunk
|
||||||
CenterChunkIndex = GetChunkTupleFromPlaneCoord(planeCoord);
|
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
|
// load or create adjacent chunks
|
||||||
_activeChunkIndices = new List<Vector2>();
|
_activeChunkIndices = new List<Vector2>();
|
||||||
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(-1, -1));
|
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(-1, -1));
|
||||||
|
@ -319,50 +335,57 @@ public class World : Spatial
|
||||||
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(+1, +1));
|
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(+1, +1));
|
||||||
|
|
||||||
// clear unused chunks
|
// clear unused chunks
|
||||||
_unusedWorldChunks.Clear();
|
_deactivatedWorldChunks.Clear();
|
||||||
_addedChunkIndices.Clear();
|
_addedChunkIndices.Clear();
|
||||||
|
|
||||||
foreach (Vector2 oldChunkIndex in oldCachedChunks.Keys)
|
foreach (Vector2 oldChunkIndex in oldCachedChunks.Keys) {
|
||||||
if (!_activeChunkIndices.Contains(oldChunkIndex))
|
if (!_activeChunkIndices.Contains(oldChunkIndex)) {
|
||||||
DeactivateChunk(oldCachedChunks[oldChunkIndex]);
|
DeactivateChunk(oldCachedChunks[oldChunkIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (Vector2 activeChunkIndex in _activeChunkIndices)
|
foreach (Vector2 activeChunkIndex in _activeChunkIndices) {
|
||||||
{
|
|
||||||
WorldChunk chunk = GetOrCreateWorldChunk(activeChunkIndex,
|
WorldChunk chunk = GetOrCreateWorldChunk(activeChunkIndex,
|
||||||
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
|
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
|
||||||
_cachedWorldChunks[activeChunkIndex] = chunk;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Assert(_activeChunkIndices.Count == NumChunkRows * NumChunkColumns);
|
Debug.Assert(_activeChunkIndices.Count == NumChunkRows * NumChunkColumns);
|
||||||
|
|
||||||
foreach (Vector2 chunkKey in _activeChunkIndices)
|
foreach (Vector2 chunkKey in _activeChunkIndices) {
|
||||||
if (!oldCachedChunks.ContainsKey(chunkKey))
|
if (!oldCachedChunks.ContainsKey(chunkKey)) {
|
||||||
{
|
|
||||||
ActivateChunk(_cachedWorldChunks[chunkKey], chunkKey);
|
ActivateChunk(_cachedWorldChunks[chunkKey], chunkKey);
|
||||||
State = GenerationState.Heightmap;
|
State = GenerationState.Heightmap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ActivateChunk(WorldChunk chunk, Vector2 chunkIndex)
|
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) {
|
||||||
chunk.SetChunkIndex(chunkIndex, HexGrid);
|
chunk.SetChunkIndex(chunkIndex, HexGrid);
|
||||||
chunk.UpdateTileTransforms();
|
chunk.UpdateTileTransforms();
|
||||||
|
|
||||||
_addedChunkIndices.Add(chunk.ChunkIndex);
|
_addedChunkIndices.Add(chunk.ChunkIndex);
|
||||||
GD.Print("Generating noise for chunk " + chunk.ChunkIndex);
|
|
||||||
GenerateChunkNoiseMap(chunk);
|
GenerateChunkNoiseMap(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeactivateChunk(WorldChunk chunk)
|
private void DeactivateChunk(WorldChunk chunk) {
|
||||||
{
|
|
||||||
GD.Print("Clearing chunk index: " + chunk.ChunkIndex);
|
|
||||||
_cachedWorldChunks.Remove(chunk.ChunkIndex);
|
_cachedWorldChunks.Remove(chunk.ChunkIndex);
|
||||||
chunk.ClearContent();
|
chunk.ClearContent();
|
||||||
_unusedWorldChunks.Add(chunk);
|
_deactivatedWorldChunks.Add(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateChunkNoiseMap(WorldChunk chunk)
|
private void GenerateChunkNoiseMap(WorldChunk chunk) {
|
||||||
{
|
|
||||||
Vector2 chunkIndex = chunk.ChunkIndex;
|
Vector2 chunkIndex = chunk.ChunkIndex;
|
||||||
|
|
||||||
ImageTexture noiseImageTexture = new();
|
ImageTexture noiseImageTexture = new();
|
||||||
|
@ -372,37 +395,38 @@ public class World : Spatial
|
||||||
chunk.SetNoisemap(noiseImageTexture);
|
chunk.SetNoisemap(noiseImageTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveChunk(Vector2 cachedChunkKey)
|
private void RemoveChunk(Vector2 cachedChunkKey) {
|
||||||
{
|
|
||||||
_cachedWorldChunks.Remove(cachedChunkKey);
|
_cachedWorldChunks.Remove(cachedChunkKey);
|
||||||
_removedChunkIndices.Add(cachedChunkKey);
|
_removedChunkIndices.Add(cachedChunkKey);
|
||||||
|
|
||||||
foreach (WorldChunk chunk in Chunks.GetChildren())
|
foreach (WorldChunk chunk in Chunks.GetChildren()) {
|
||||||
if (chunk.ChunkIndex == new Vector2(cachedChunkKey.x, cachedChunkKey.y))
|
if (chunk.ChunkIndex == new Vector2(cachedChunkKey.x, cachedChunkKey.y)) {
|
||||||
chunk.QueueFree();
|
chunk.QueueFree();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Vector2 GetChunkTupleFromPlaneCoord(Vector2 planeCoord)
|
|
||||||
{
|
|
||||||
HexCell centerOffsetCoord = HexGrid.GetHexAt(planeCoord);
|
|
||||||
return (centerOffsetCoord.OffsetCoords / ChunkSize).Floor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCenterPlaneCoord(Vector2 centerPlaneCoord)
|
|
||||||
{
|
private Vector2 GetChunkTupleFromPlaneCoord(Vector2 planeCoord) {
|
||||||
if (!_centerChunkRect.HasPoint(centerPlaneCoord))
|
HexCell hexCell = HexGrid.GetHexAt(planeCoord);
|
||||||
{
|
return GetChunkIndexFromOffsetCoord(hexCell.OffsetCoords);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector2 GetChunkIndexFromOffsetCoord(Vector2 offsetCoord) {
|
||||||
|
return (offsetCoord / ChunkSize).Floor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCenterPlaneCoord(Vector2 centerPlaneCoord) {
|
||||||
|
if (State != GenerationState.Done) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_centerChunkRect.HasPoint(centerPlaneCoord)) {
|
||||||
UpdateCenterChunkFromPlaneCoord(centerPlaneCoord);
|
UpdateCenterChunkFromPlaneCoord(centerPlaneCoord);
|
||||||
|
|
||||||
UpdateChunkBounds();
|
|
||||||
|
|
||||||
UpdateNavigationBounds();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateWorldViewTexture()
|
private void UpdateWorldViewTexture() {
|
||||||
{
|
|
||||||
int worldChunkSize = ChunkSize;
|
int worldChunkSize = ChunkSize;
|
||||||
int numWorldChunkRows = NumChunkRows;
|
int numWorldChunkRows = NumChunkRows;
|
||||||
int numWorldChunkColumns = NumChunkColumns;
|
int numWorldChunkColumns = NumChunkColumns;
|
||||||
|
@ -412,8 +436,7 @@ public class World : Spatial
|
||||||
_tileTypeMapImage.Create(worldChunkSize * numWorldChunkColumns, worldChunkSize * numWorldChunkRows, false,
|
_tileTypeMapImage.Create(worldChunkSize * numWorldChunkColumns, worldChunkSize * numWorldChunkRows, false,
|
||||||
Image.Format.Rgba8);
|
Image.Format.Rgba8);
|
||||||
|
|
||||||
foreach (Vector2 chunkIndex in _activeChunkIndices)
|
foreach (Vector2 chunkIndex in _activeChunkIndices) {
|
||||||
{
|
|
||||||
WorldChunk worldChunk = GetOrCreateWorldChunk(chunkIndex, Colors.White);
|
WorldChunk worldChunk = GetOrCreateWorldChunk(chunkIndex, Colors.White);
|
||||||
|
|
||||||
_heightmapImage.BlendRect(
|
_heightmapImage.BlendRect(
|
||||||
|
@ -431,7 +454,7 @@ public class World : Spatial
|
||||||
_heightmapTexture.CreateFromImage(_heightmapImage);
|
_heightmapTexture.CreateFromImage(_heightmapImage);
|
||||||
|
|
||||||
_viewTileTypeTexture = new ImageTexture();
|
_viewTileTypeTexture = new ImageTexture();
|
||||||
_viewTileTypeTexture.CreateFromImage(_tileTypeMapImage);
|
_viewTileTypeTexture.CreateFromImage(_tileTypeMapImage, (uint)Texture.FlagsEnum.ConvertToLinear);
|
||||||
|
|
||||||
WorldTextureCoordinateOffset = _chunkIndexSouthWest * worldChunkSize;
|
WorldTextureCoordinateOffset = _chunkIndexSouthWest * worldChunkSize;
|
||||||
|
|
||||||
|
@ -439,113 +462,316 @@ public class World : Spatial
|
||||||
EmitSignal("OnHeightmapImageChanged", _heightmapImage);
|
EmitSignal("OnHeightmapImageChanged", _heightmapImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateChunkBounds()
|
private void UpdateChunkBounds() {
|
||||||
{
|
|
||||||
_chunkIndexSouthWest = Vector2.Inf;
|
_chunkIndexSouthWest = Vector2.Inf;
|
||||||
_chunkIndexNorthEast = -Vector2.Inf;
|
_chunkIndexNorthEast = -Vector2.Inf;
|
||||||
|
|
||||||
foreach (Vector2 chunkIndex in _activeChunkIndices)
|
foreach (Vector2 chunkIndex in _activeChunkIndices) {
|
||||||
{
|
if (chunkIndex.x <= _chunkIndexSouthWest.x && chunkIndex.y <= _chunkIndexSouthWest.y) {
|
||||||
WorldChunk worldChunk = GetOrCreateWorldChunk(chunkIndex, Colors.White);
|
|
||||||
|
|
||||||
if (chunkIndex.x <= _chunkIndexSouthWest.x && chunkIndex.y <= _chunkIndexSouthWest.y)
|
|
||||||
_chunkIndexSouthWest = chunkIndex;
|
_chunkIndexSouthWest = chunkIndex;
|
||||||
else if (chunkIndex.x >= _chunkIndexNorthEast.x && chunkIndex.y >= _chunkIndexNorthEast.y)
|
} else if (chunkIndex.x >= _chunkIndexNorthEast.x && chunkIndex.y >= _chunkIndexNorthEast.y) {
|
||||||
_chunkIndexNorthEast = chunkIndex;
|
_chunkIndexNorthEast = chunkIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateNavigationBounds()
|
private void UpdateNavigationBounds() {
|
||||||
{
|
|
||||||
HexCell cellSouthWest = HexGrid.GetHexAtOffset(_chunkIndexSouthWest * ChunkSize);
|
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));
|
HexGrid.SetBoundsOffset(cellSouthWest, ChunkSize * new Vector2(NumChunkColumns, NumChunkRows));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process(float delta)
|
public void MarkCellUnwalkable(HexCell cell) {
|
||||||
{
|
HexGrid.AddObstacle(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetHexCost(Entity entity, HexCell cell) {
|
||||||
|
float nextHexCost = HexGrid.GetHexCost(cell);
|
||||||
|
|
||||||
|
if (nextHexCost != 0) {
|
||||||
|
Vector2 nextOffset = cell.OffsetCoords;
|
||||||
|
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) {
|
||||||
GenerationState oldState = State;
|
GenerationState oldState = State;
|
||||||
|
|
||||||
UpdateGenerationState();
|
UpdateGenerationState();
|
||||||
|
|
||||||
if (oldState != GenerationState.Done && State == GenerationState.Done)
|
if (oldState != GenerationState.Done && State == GenerationState.Done) {
|
||||||
UpdateWorldViewTexture();
|
UpdateWorldViewTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateGenerationState()
|
while (_removedSpatialNodes.Count > 0) {
|
||||||
{
|
GD.Print("Queueing deletion of " + _removedSpatialNodes[0]);
|
||||||
FrameCounter++;
|
_removedSpatialNodes[0].QueueFree();
|
||||||
|
_removedSpatialNodes.RemoveAt(0);
|
||||||
if (State == GenerationState.Heightmap)
|
}
|
||||||
{
|
|
||||||
int numChunksGeneratingHeightmap = 0;
|
|
||||||
foreach (Vector2 chunkIndex in _addedChunkIndices)
|
|
||||||
{
|
|
||||||
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
|
||||||
if (chunk.HeightMapFrameCount > 0) numChunksGeneratingHeightmap++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numChunksGeneratingHeightmap == 0)
|
private void UpdateGenerationState() {
|
||||||
{
|
if (State == GenerationState.Heightmap) {
|
||||||
|
int numChunksGeneratingHeightmap = 0;
|
||||||
|
foreach (Vector2 chunkIndex in _addedChunkIndices) {
|
||||||
|
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
||||||
|
if (chunk.HeightMapFrameCount > 0) {
|
||||||
|
numChunksGeneratingHeightmap++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numChunksGeneratingHeightmap == 0) {
|
||||||
// assign height map images
|
// assign height map images
|
||||||
foreach (Vector2 chunkIndex in _addedChunkIndices)
|
foreach (Vector2 chunkIndex in _addedChunkIndices) {
|
||||||
{
|
|
||||||
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
||||||
chunk.SetHeightmap(chunk.HeightmapOffscreenViewport.GetTexture());
|
chunk.SetHeightmap(chunk.HeightmapOffscreenViewport.GetTexture());
|
||||||
}
|
}
|
||||||
|
|
||||||
GD.Print("Switching to TileType Generation: " + FrameCounter);
|
|
||||||
State = GenerationState.TileType;
|
State = GenerationState.TileType;
|
||||||
}
|
}
|
||||||
}
|
} else if (State == GenerationState.TileType) {
|
||||||
else if (State == GenerationState.TileType)
|
|
||||||
{
|
|
||||||
int numChunksGeneratingTileType = 0;
|
int numChunksGeneratingTileType = 0;
|
||||||
foreach (Vector2 chunkIndex in _addedChunkIndices)
|
foreach (Vector2 chunkIndex in _addedChunkIndices) {
|
||||||
{
|
|
||||||
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
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;
|
State = GenerationState.Objects;
|
||||||
}
|
}
|
||||||
}
|
} else if (State == GenerationState.Objects) {
|
||||||
else if (State == GenerationState.Objects)
|
|
||||||
{
|
|
||||||
// generate objects
|
// generate objects
|
||||||
foreach (Vector2 chunkIndex in _addedChunkIndices)
|
foreach (Vector2 chunkIndex in _addedChunkIndices) {
|
||||||
PopulateChunk(_cachedWorldChunks[chunkIndex]);
|
PopulateChunk(_cachedWorldChunks[chunkIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
_addedChunkIndices.Clear();
|
_addedChunkIndices.Clear();
|
||||||
|
|
||||||
GD.Print("Generation done: " + FrameCounter);
|
|
||||||
State = GenerationState.Done;
|
State = GenerationState.Done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEntityClicked(Entity entity)
|
private void OnEntityClicked(Entity entity) {
|
||||||
{
|
|
||||||
EmitSignal("EntityClicked", entity);
|
EmitSignal("EntityClicked", entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTileClicked(HexTile3D tile)
|
public void OnTileClicked(HexTile3D tile) {
|
||||||
{
|
if (State != GenerationState.Done) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
EmitSignal("TileClicked", tile);
|
EmitSignal("TileClicked", tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTileHovered(HexTile3D tile)
|
public void OnTileHovered(HexTile3D tile) {
|
||||||
{
|
if (State != GenerationState.Done) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
EmitSignal("TileHovered", 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
[gd_scene load_steps=10 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://scenes/World.cs" type="Script" id=1]
|
||||||
|
[ext_resource path="res://entities/rockA.tscn" type="PackedScene" id=2]
|
||||||
|
[ext_resource path="res://assets/Environment/HexTileMesh.tres" type="CylinderMesh" id=3]
|
||||||
|
[ext_resource path="res://entities/Tree.cs" type="Script" id=4]
|
||||||
|
[ext_resource path="res://entities/rockC.tscn" type="PackedScene" id=5]
|
||||||
|
[ext_resource path="res://assets/Environment/grassLarge.tscn" type="PackedScene" id=6]
|
||||||
|
[ext_resource path="res://entities/rockB.tscn" type="PackedScene" id=7]
|
||||||
|
[ext_resource path="res://entities/Tree.tscn" type="PackedScene" id=8]
|
||||||
|
|
||||||
|
[sub_resource type="MultiMesh" id=27]
|
||||||
|
color_format = 1
|
||||||
|
transform_format = 1
|
||||||
|
custom_data_format = 1
|
||||||
|
visible_instance_count = 0
|
||||||
|
mesh = ExtResource( 3 )
|
||||||
|
|
||||||
|
[node name="World" type="Spatial"]
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="Chunks" type="Spatial" parent="."]
|
||||||
|
|
||||||
|
[node name="TileMultiMeshInstance" type="MultiMeshInstance" parent="."]
|
||||||
|
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -2.5, 0 )
|
||||||
|
multimesh = SubResource( 27 )
|
||||||
|
|
||||||
|
[node name="Assets" type="Spatial" parent="."]
|
||||||
|
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -5, 0 )
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
[node name="Rocks" type="Spatial" parent="Assets"]
|
||||||
|
|
||||||
|
[node name="rockA" type="StaticBody" parent="Assets/Rocks" instance=ExtResource( 2 )]
|
||||||
|
input_ray_pickable = false
|
||||||
|
|
||||||
|
[node name="rockB" type="StaticBody" parent="Assets/Rocks" instance=ExtResource( 7 )]
|
||||||
|
input_ray_pickable = false
|
||||||
|
|
||||||
|
[node name="rockC" type="StaticBody" parent="Assets/Rocks" instance=ExtResource( 5 )]
|
||||||
|
input_ray_pickable = false
|
||||||
|
|
||||||
|
[node name="Grass" type="Spatial" parent="Assets"]
|
||||||
|
|
||||||
|
[node name="grassLarge" type="Spatial" parent="Assets/Grass" groups=["GameGeometry"] instance=ExtResource( 6 )]
|
||||||
|
|
||||||
|
[node name="Trees" type="Spatial" parent="Assets"]
|
||||||
|
|
||||||
|
[node name="tree" type="StaticBody" parent="Assets/Trees" instance=ExtResource( 8 )]
|
||||||
|
script = ExtResource( 4 )
|
|
@ -3,8 +3,7 @@ using System.Linq;
|
||||||
using Godot;
|
using Godot;
|
||||||
using Godot.Collections;
|
using Godot.Collections;
|
||||||
|
|
||||||
public class WorldChunk : Spatial
|
public class WorldChunk : Spatial {
|
||||||
{
|
|
||||||
private readonly PackedScene _hexTile3DScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
private readonly PackedScene _hexTile3DScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
||||||
private MultiMeshInstance _multiMeshInstance;
|
private MultiMeshInstance _multiMeshInstance;
|
||||||
private readonly Array<int> _tileInstanceIndices = new();
|
private readonly Array<int> _tileInstanceIndices = new();
|
||||||
|
@ -28,10 +27,11 @@ public class WorldChunk : Spatial
|
||||||
[Export] public Texture HeightMap;
|
[Export] public Texture HeightMap;
|
||||||
public int HeightMapFrameCount;
|
public int HeightMapFrameCount;
|
||||||
|
|
||||||
|
public Image TileTypeImage;
|
||||||
public Viewport HeightmapOffscreenViewport;
|
public Viewport HeightmapOffscreenViewport;
|
||||||
[Export] public Texture NavigationMap;
|
[Export] public Texture NavigationMap;
|
||||||
|
|
||||||
public bool NoiseTextureCheckerboardOverlay = true;
|
public bool NoiseTextureCheckerboardOverlay = false;
|
||||||
|
|
||||||
// signals
|
// signals
|
||||||
[Signal]
|
[Signal]
|
||||||
|
@ -47,7 +47,7 @@ public class WorldChunk : Spatial
|
||||||
|
|
||||||
// scene nodes
|
// scene nodes
|
||||||
private MeshInstance PlaneRectMesh;
|
private MeshInstance PlaneRectMesh;
|
||||||
[Export] public int Size = 32;
|
public int Size = 32;
|
||||||
|
|
||||||
// resources
|
// resources
|
||||||
|
|
||||||
|
@ -56,32 +56,24 @@ public class WorldChunk : Spatial
|
||||||
public int TileTypeMapFrameCount;
|
public int TileTypeMapFrameCount;
|
||||||
public Viewport TileTypeOffscreenViewport;
|
public Viewport TileTypeOffscreenViewport;
|
||||||
|
|
||||||
public WorldChunk()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorldChunk(int size)
|
|
||||||
{
|
|
||||||
SetSize(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public bool ShowTextureOverlay
|
public bool ShowTextureOverlay {
|
||||||
{
|
|
||||||
get => _showTextureOverlay;
|
get => _showTextureOverlay;
|
||||||
|
|
||||||
set
|
set {
|
||||||
{
|
if (PlaneRectMesh != null) {
|
||||||
if (PlaneRectMesh != null) PlaneRectMesh.Visible = value;
|
PlaneRectMesh.Visible = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
PlaneRectMesh = (MeshInstance)FindNode("PlaneRectMesh");
|
PlaneRectMesh = (MeshInstance)FindNode("PlaneRectMesh");
|
||||||
Debug.Assert(PlaneRectMesh != null);
|
Debug.Assert(PlaneRectMesh != null);
|
||||||
if (PlaneRectMesh.Visible) _showTextureOverlay = true;
|
if (PlaneRectMesh.Visible) {
|
||||||
|
_showTextureOverlay = true;
|
||||||
|
}
|
||||||
|
|
||||||
Transform planeRectTransform = Transform.Identity;
|
Transform planeRectTransform = Transform.Identity;
|
||||||
planeRectTransform =
|
planeRectTransform =
|
||||||
|
@ -112,16 +104,12 @@ public class WorldChunk : Spatial
|
||||||
|
|
||||||
Tiles = (Spatial)FindNode("Tiles");
|
Tiles = (Spatial)FindNode("Tiles");
|
||||||
Debug.Assert(Tiles != null);
|
Debug.Assert(Tiles != null);
|
||||||
|
|
||||||
SetSize(World.ChunkSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetSize(int size)
|
public void SetSize(int size) {
|
||||||
{
|
|
||||||
Size = size;
|
Size = size;
|
||||||
|
|
||||||
if (TileTypeOffscreenViewport != null)
|
if (TileTypeOffscreenViewport != null) {
|
||||||
{
|
|
||||||
TileTypeOffscreenViewport.Size = Vector2.One * size;
|
TileTypeOffscreenViewport.Size = Vector2.One * size;
|
||||||
HeightmapOffscreenViewport.Size = Vector2.One * size;
|
HeightmapOffscreenViewport.Size = Vector2.One * size;
|
||||||
_noiseMask.Transform = Transform2D.Identity.Scaled(Vector2.One * size / _noiseMask.Texture.GetSize().x);
|
_noiseMask.Transform = Transform2D.Identity.Scaled(Vector2.One * size / _noiseMask.Texture.GetSize().x);
|
||||||
|
@ -131,10 +119,9 @@ public class WorldChunk : Spatial
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetChunkIndex(Vector2 chunkIndex, HexGrid hexGrid)
|
public void SetChunkIndex(Vector2 chunkIndex, HexGrid hexGrid) {
|
||||||
{
|
|
||||||
ChunkIndex = chunkIndex;
|
ChunkIndex = chunkIndex;
|
||||||
float chunkSize = World.ChunkSize;
|
float chunkSize = Size;
|
||||||
|
|
||||||
Vector2 planeCoordSouthWest = hexGrid.GetHexCenterFromOffset(chunkIndex * chunkSize);
|
Vector2 planeCoordSouthWest = hexGrid.GetHexCenterFromOffset(chunkIndex * chunkSize);
|
||||||
|
|
||||||
|
@ -152,24 +139,23 @@ public class WorldChunk : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InitializeTileInstances(Vector2 chunkIndex, MultiMeshInstance multiMeshInstance,
|
public void InitializeTileInstances(Vector2 chunkIndex, MultiMeshInstance multiMeshInstance,
|
||||||
int tileInstanceIndexStart)
|
int tileInstanceIndexStart) {
|
||||||
{
|
|
||||||
_multiMeshInstance = multiMeshInstance;
|
_multiMeshInstance = multiMeshInstance;
|
||||||
_tileInstanceIndices.Clear();
|
_tileInstanceIndices.Clear();
|
||||||
|
|
||||||
int chunkSize = World.ChunkSize;
|
int chunkSize = Size;
|
||||||
|
|
||||||
foreach (Spatial node in Tiles.GetChildren())
|
foreach (Spatial node in Tiles.GetChildren()) {
|
||||||
node.QueueFree();
|
node.QueueFree();
|
||||||
|
}
|
||||||
|
|
||||||
foreach (int i in Enumerable.Range(0, chunkSize))
|
foreach (int i in Enumerable.Range(0, chunkSize)) {
|
||||||
foreach (int j in Enumerable.Range(0, chunkSize))
|
foreach (int j in Enumerable.Range(0, chunkSize)) {
|
||||||
{
|
|
||||||
HexTile3D tile3D = (HexTile3D)_hexTile3DScene.Instance();
|
HexTile3D tile3D = (HexTile3D)_hexTile3DScene.Instance();
|
||||||
tile3D.Connect("TileClicked", this, nameof(OnTileClicked));
|
tile3D.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||||
tile3D.Connect("TileHovered", this, nameof(OnTileHovered));
|
tile3D.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||||
|
|
||||||
tile3D.Cell.OffsetCoords = new Vector2(chunkIndex * World.ChunkSize + new Vector2(i, j));
|
tile3D.Cell.OffsetCoords = new Vector2(chunkIndex * chunkSize + new Vector2(i, j));
|
||||||
_tileInstanceIndices.Add(tileInstanceIndexStart + _tileInstanceIndices.Count);
|
_tileInstanceIndices.Add(tileInstanceIndexStart + _tileInstanceIndices.Count);
|
||||||
|
|
||||||
Transform tileTransform = Transform.Identity;
|
Transform tileTransform = Transform.Identity;
|
||||||
|
@ -179,31 +165,30 @@ public class WorldChunk : Spatial
|
||||||
|
|
||||||
Tiles.AddChild(tile3D);
|
Tiles.AddChild(tile3D);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_multiMeshInstance.Multimesh.VisibleInstanceCount = _multiMeshInstance.Multimesh.InstanceCount;
|
_multiMeshInstance.Multimesh.VisibleInstanceCount = _multiMeshInstance.Multimesh.InstanceCount;
|
||||||
|
|
||||||
|
GD.Print("Chunk: " + chunkIndex + " Last index: " + _tileInstanceIndices.Last());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearContent()
|
public void ClearContent() {
|
||||||
{
|
foreach (Spatial child in Entities.GetChildren()) {
|
||||||
foreach (Spatial child in Entities.GetChildren())
|
|
||||||
child.QueueFree();
|
child.QueueFree();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateTileTransforms()
|
public void UpdateTileTransforms() {
|
||||||
{
|
|
||||||
Transform chunkTransform = Transform.Identity;
|
Transform chunkTransform = Transform.Identity;
|
||||||
Vector2 chunkOriginPlaneCoord = _hexGrid.GetHexCenterFromOffset(ChunkIndex * World.ChunkSize);
|
Vector2 chunkOriginPlaneCoord = _hexGrid.GetHexCenterFromOffset(ChunkIndex * Size);
|
||||||
chunkTransform.origin = new Vector3(chunkOriginPlaneCoord.x, 0, chunkOriginPlaneCoord.y);
|
chunkTransform.origin = new Vector3(chunkOriginPlaneCoord.x, 0, chunkOriginPlaneCoord.y);
|
||||||
Transform = chunkTransform;
|
Transform = chunkTransform;
|
||||||
|
|
||||||
Basis tileOrientation = new(Vector3.Up, 90f * Mathf.Pi / 180f);
|
Basis tileOrientation = new(Vector3.Up, 90f * Mathf.Pi / 180f);
|
||||||
|
|
||||||
GD.Print("Updating transforms for instances of chunk " + ChunkIndex + " origin: " + chunkTransform.origin);
|
foreach (int i in Enumerable.Range(0, _tileInstanceIndices.Count)) {
|
||||||
|
int column = i % Size;
|
||||||
foreach (int i in Enumerable.Range(0, _tileInstanceIndices.Count))
|
int row = i / Size;
|
||||||
{
|
|
||||||
int column = i % World.ChunkSize;
|
|
||||||
int row = i / World.ChunkSize;
|
|
||||||
|
|
||||||
Vector2 tilePlaneCoord =
|
Vector2 tilePlaneCoord =
|
||||||
_hexGrid.GetHexCenterFromOffset(new Vector2(column, row));
|
_hexGrid.GetHexCenterFromOffset(new Vector2(column, row));
|
||||||
|
@ -211,17 +196,17 @@ public class WorldChunk : Spatial
|
||||||
Transform hexTransform = new(tileOrientation,
|
Transform hexTransform = new(tileOrientation,
|
||||||
chunkTransform.origin + new Vector3(tilePlaneCoord.x, 0, tilePlaneCoord.y));
|
chunkTransform.origin + new Vector3(tilePlaneCoord.x, 0, tilePlaneCoord.y));
|
||||||
|
|
||||||
if (_showHexTiles)
|
if (_showHexTiles) {
|
||||||
hexTransform = new Transform(tileOrientation.Scaled(Vector3.One * 0.95f),
|
hexTransform = new Transform(tileOrientation.Scaled(Vector3.One * 0.95f),
|
||||||
hexTransform.origin);
|
hexTransform.origin);
|
||||||
|
}
|
||||||
|
|
||||||
_multiMeshInstance.Multimesh.SetInstanceTransform(_tileInstanceIndices[i], hexTransform);
|
_multiMeshInstance.Multimesh.SetInstanceTransform(_tileInstanceIndices[i], hexTransform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// other members
|
// other members
|
||||||
public void SaveToFile(string chunkName)
|
public void SaveToFile(string chunkName) {
|
||||||
{
|
|
||||||
Image image = new();
|
Image image = new();
|
||||||
|
|
||||||
image.CreateFromData(Size, Size, false, Image.Format.Rgba8, TileTypeMap.GetData().GetData());
|
image.CreateFromData(Size, Size, false, Image.Format.Rgba8, TileTypeMap.GetData().GetData());
|
||||||
|
@ -234,13 +219,10 @@ public class WorldChunk : Spatial
|
||||||
image.SavePng(chunkName + "_heightMap.png");
|
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.Texture = texture;
|
||||||
_noiseSprite.Transform =
|
_noiseSprite.Transform =
|
||||||
Transform2D.Identity.Scaled(HeightmapOffscreenViewport.Size / _noiseSprite.Texture.GetSize().x);
|
Transform2D.Identity.Scaled(HeightmapOffscreenViewport.Size / _noiseSprite.Texture.GetSize().x);
|
||||||
|
@ -248,8 +230,7 @@ public class WorldChunk : Spatial
|
||||||
HeightMapFrameCount = 1;
|
HeightMapFrameCount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetHeightmap(Texture texture)
|
public void SetHeightmap(Texture texture) {
|
||||||
{
|
|
||||||
_heightmapSprite.Texture = texture;
|
_heightmapSprite.Texture = texture;
|
||||||
_heightmapSprite.Transform =
|
_heightmapSprite.Transform =
|
||||||
Transform2D.Identity.Scaled(TileTypeOffscreenViewport.Size / _heightmapSprite.Texture.GetSize());
|
Transform2D.Identity.Scaled(TileTypeOffscreenViewport.Size / _heightmapSprite.Texture.GetSize());
|
||||||
|
@ -258,26 +239,30 @@ public class WorldChunk : Spatial
|
||||||
TileTypeMapFrameCount = 1;
|
TileTypeMapFrameCount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process(float delta)
|
public void CreateUnlockedTileTypeImage() {
|
||||||
{
|
TileTypeImage = TileTypeOffscreenViewport.GetTexture().GetData();
|
||||||
|
TileTypeImage.Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _Process(float delta) {
|
||||||
Texture tileTypeTexture = TileTypeOffscreenViewport.GetTexture();
|
Texture tileTypeTexture = TileTypeOffscreenViewport.GetTexture();
|
||||||
|
|
||||||
if (NoiseTextureCheckerboardOverlay)
|
if (NoiseTextureCheckerboardOverlay) {
|
||||||
{
|
|
||||||
Image tileTypeImage = tileTypeTexture.GetData();
|
Image tileTypeImage = tileTypeTexture.GetData();
|
||||||
tileTypeImage.Lock();
|
tileTypeImage.Lock();
|
||||||
|
|
||||||
foreach (int i in Enumerable.Range(0, Size))
|
foreach (int i in Enumerable.Range(0, Size)) {
|
||||||
foreach (int j in Enumerable.Range(0, Size))
|
foreach (int j in Enumerable.Range(0, Size)) {
|
||||||
{
|
|
||||||
Vector2 textureCoord = new(i, j);
|
Vector2 textureCoord = new(i, j);
|
||||||
Color baseColor = tileTypeImage.GetPixelv(textureCoord);
|
Color baseColor = tileTypeImage.GetPixelv(textureCoord);
|
||||||
|
|
||||||
if ((i + j) % 2 == 0)
|
if ((i + j) % 2 == 0) {
|
||||||
tileTypeImage.SetPixelv(textureCoord, baseColor);
|
tileTypeImage.SetPixelv(textureCoord, baseColor);
|
||||||
else
|
} else {
|
||||||
tileTypeImage.SetPixelv(textureCoord, baseColor * 0.6f);
|
tileTypeImage.SetPixelv(textureCoord, baseColor * 0.6f);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tileTypeImage.Unlock();
|
tileTypeImage.Unlock();
|
||||||
ImageTexture imageTexture = new();
|
ImageTexture imageTexture = new();
|
||||||
|
@ -295,24 +280,26 @@ public class WorldChunk : Spatial
|
||||||
//RectMaterial.Uv1Triplanar = true;
|
//RectMaterial.Uv1Triplanar = true;
|
||||||
PlaneRectMesh.SetSurfaceMaterial(0, _rectMaterial);
|
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;
|
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;
|
TileTypeMapFrameCount = TileTypeMapFrameCount > 0 ? TileTypeMapFrameCount - 1 : 0;
|
||||||
|
|
||||||
PlaneRectMesh.MaterialOverride = null;
|
PlaneRectMesh.MaterialOverride = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTileClicked(HexTile3D tile)
|
public void OnTileClicked(HexTile3D tile) {
|
||||||
{
|
|
||||||
EmitSignal("TileClicked", tile);
|
EmitSignal("TileClicked", tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTileHovered(HexTile3D tile)
|
public void OnTileHovered(HexTile3D tile) {
|
||||||
{
|
|
||||||
EmitSignal("TileHovered", tile);
|
EmitSignal("TileHovered", tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
[gd_scene load_steps=10 format=2]
|
[gd_scene load_steps=10 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://scenes/WorldChunk.cs" type="Script" id=1]
|
[ext_resource path="res://scenes/WorldChunk.cs" type="Script" id=1]
|
||||||
[ext_resource path="res://materials/IslandColorRampShader.tres" type="Material" id=2]
|
[ext_resource path="res://materials/WorldTileTypeMaterial.tres" type="Material" id=2]
|
||||||
[ext_resource path="res://assets/TestHeightmap.tres" type="Texture" id=3]
|
[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://assets/4x4checkerColor.png" type="Texture" id=4]
|
||||||
[ext_resource path="res://addons/gdhexgrid/icon.png" type="Texture" id=6]
|
[ext_resource path="res://addons/gdhexgrid/icon.png" type="Texture" id=6]
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
|
using Godot.Collections;
|
||||||
|
|
||||||
public class EditorUI : Control
|
public class EditorUI : Control {
|
||||||
{
|
public enum InputMode {
|
||||||
public enum InputMode
|
|
||||||
{
|
|
||||||
None,
|
None,
|
||||||
Grass,
|
Grass,
|
||||||
Sand,
|
Sand,
|
||||||
|
@ -35,8 +34,7 @@ public class EditorUI : Control
|
||||||
public Vector2 currentTileOffset = Vector2.Zero;
|
public Vector2 currentTileOffset = Vector2.Zero;
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
_tileMaterial = GD.Load<ShaderMaterial>("materials/HexTileTextureLookup.tres");
|
_tileMaterial = GD.Load<ShaderMaterial>("materials/HexTileTextureLookup.tres");
|
||||||
|
|
||||||
// signals
|
// signals
|
||||||
|
@ -69,74 +67,65 @@ public class EditorUI : Control
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void OnResetButton()
|
public void OnResetButton() {
|
||||||
{
|
|
||||||
GD.Print("Resetting Map");
|
GD.Print("Resetting Map");
|
||||||
_tileWorld.Seed = _tileWorld.Seed + 1;
|
_tileWorld.Seed = _tileWorld.Seed + 1;
|
||||||
_tileWorld.Generate(24);
|
_tileWorld.Generate(24);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnGrassButton()
|
public void OnGrassButton() {
|
||||||
{
|
|
||||||
CurrentInputMode = InputMode.Grass;
|
CurrentInputMode = InputMode.Grass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnSandButton()
|
public void OnSandButton() {
|
||||||
{
|
|
||||||
CurrentInputMode = InputMode.Sand;
|
CurrentInputMode = InputMode.Sand;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnWaterButton()
|
public void OnWaterButton() {
|
||||||
{
|
|
||||||
CurrentInputMode = InputMode.Water;
|
CurrentInputMode = InputMode.Water;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnObstacleButton()
|
public void OnObstacleButton() {
|
||||||
{
|
|
||||||
CurrentInputMode = InputMode.Obstacle;
|
CurrentInputMode = InputMode.Obstacle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnNavigateButton()
|
public void OnNavigateButton() {
|
||||||
{
|
|
||||||
CurrentInputMode = InputMode.Navigate;
|
CurrentInputMode = InputMode.Navigate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnGameGeometryCheckBoxToggled(bool pressed)
|
public void OnGameGeometryCheckBoxToggled(bool pressed) {
|
||||||
{
|
Array gameGeometries = GetTree().GetNodesInGroup("GameGeometry");
|
||||||
var gameGeometries = GetTree().GetNodesInGroup("GameGeometry");
|
foreach (Spatial mesh in gameGeometries) {
|
||||||
foreach (Spatial mesh in gameGeometries)
|
if (mesh != null) {
|
||||||
if (mesh != null)
|
|
||||||
mesh.Visible = pressed;
|
mesh.Visible = pressed;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void OnPhysicsGeometryCheckBoxToggled(bool pressed)
|
public void OnPhysicsGeometryCheckBoxToggled(bool pressed) {
|
||||||
{
|
Array physicsGeometries = GetTree().GetNodesInGroup("PhysicsGeometry");
|
||||||
var physicsGeometries = GetTree().GetNodesInGroup("PhysicsGeometry");
|
foreach (Spatial mesh in physicsGeometries) {
|
||||||
foreach (Spatial mesh in physicsGeometries)
|
if (mesh != null) {
|
||||||
if (mesh != null)
|
|
||||||
mesh.Visible = pressed;
|
mesh.Visible = pressed;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void OnNavigationGeometryCheckBoxToggled(bool pressed)
|
public void OnNavigationGeometryCheckBoxToggled(bool pressed) {
|
||||||
{
|
|
||||||
UpdateTileMaterial();
|
UpdateTileMaterial();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateTileMaterial()
|
public void UpdateTileMaterial() {
|
||||||
{
|
if (_navigationGeometryCheckBox.Pressed) {
|
||||||
if (_navigationGeometryCheckBox.Pressed)
|
ImageTexture newWorldTexture = new();
|
||||||
{
|
|
||||||
ImageTexture newWorldTexture = new ImageTexture();
|
|
||||||
newWorldTexture.CreateFromImage(_tileWorld.NavigationmapImage,
|
newWorldTexture.CreateFromImage(_tileWorld.NavigationmapImage,
|
||||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||||
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
|
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
|
||||||
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.NavigationmapImage.GetSize().x);
|
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.NavigationmapImage.GetSize().x);
|
||||||
}
|
} else {
|
||||||
else
|
ImageTexture newWorldTexture = new();
|
||||||
{
|
|
||||||
ImageTexture newWorldTexture = new ImageTexture();
|
|
||||||
newWorldTexture.CreateFromImage(_tileWorld.ColormapImage,
|
newWorldTexture.CreateFromImage(_tileWorld.ColormapImage,
|
||||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||||
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
|
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
|
||||||
|
@ -145,10 +134,8 @@ public class EditorUI : Control
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void OnTileClicked(Vector2 offsetCoord)
|
public void OnTileClicked(Vector2 offsetCoord) {
|
||||||
{
|
switch (CurrentInputMode) {
|
||||||
switch (CurrentInputMode)
|
|
||||||
{
|
|
||||||
case InputMode.Grass:
|
case InputMode.Grass:
|
||||||
_tileWorld.SetTileColorAtOffset(currentTileOffset, Colors.Green);
|
_tileWorld.SetTileColorAtOffset(currentTileOffset, Colors.Green);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
using Godot;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
public class HexTile3DMaterialAssign : Spatial
|
public class HexTile3DMaterialAssign : Spatial {
|
||||||
{
|
|
||||||
// Declare member variables here. Examples:
|
// Declare member variables here. Examples:
|
||||||
// private int a = 2;
|
// private int a = 2;
|
||||||
// private string b = "text";
|
// private string b = "text";
|
||||||
|
@ -17,8 +15,7 @@ public class HexTile3DMaterialAssign : Spatial
|
||||||
private ImageTexture _colorPatternTexture;
|
private ImageTexture _colorPatternTexture;
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
_blackWhitePatternButton = (Button)FindNode("BlackWhitePatternButton");
|
_blackWhitePatternButton = (Button)FindNode("BlackWhitePatternButton");
|
||||||
Debug.Assert(_blackWhitePatternButton != null);
|
Debug.Assert(_blackWhitePatternButton != null);
|
||||||
_blackWhitePatternButton.Connect("pressed", this, nameof(OnBlackWhitePatternButton));
|
_blackWhitePatternButton.Connect("pressed", this, nameof(OnBlackWhitePatternButton));
|
||||||
|
@ -37,23 +34,21 @@ public class HexTile3DMaterialAssign : Spatial
|
||||||
_customTileMaterial = GD.Load<ShaderMaterial>("materials/HexTileTextureLookup.tres");
|
_customTileMaterial = GD.Load<ShaderMaterial>("materials/HexTileTextureLookup.tres");
|
||||||
|
|
||||||
_blackWhitePatternTexture = new ImageTexture();
|
_blackWhitePatternTexture = new ImageTexture();
|
||||||
Image image = new Image();
|
Image image = new();
|
||||||
image.Load("assets/4x4checker.png");
|
image.Load("assets/4x4checker.png");
|
||||||
_blackWhitePatternTexture.CreateFromImage(image, (uint) (Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
_blackWhitePatternTexture.CreateFromImage(image, (uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||||
|
|
||||||
_colorPatternTexture = new ImageTexture();
|
_colorPatternTexture = new ImageTexture();
|
||||||
image.Load("assets/4x4checkerColor.png");
|
image.Load("assets/4x4checkerColor.png");
|
||||||
_colorPatternTexture.CreateFromImage(image, (uint) (Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
_colorPatternTexture.CreateFromImage(image, (uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnBlackWhitePatternButton()
|
public void OnBlackWhitePatternButton() {
|
||||||
{
|
|
||||||
GD.Print("Apply Black White Pattern!");
|
GD.Print("Apply Black White Pattern!");
|
||||||
_customTileMaterial.SetShaderParam("MapAlbedoTexture", _blackWhitePatternTexture);
|
_customTileMaterial.SetShaderParam("MapAlbedoTexture", _blackWhitePatternTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnColorPatternButton()
|
public void OnColorPatternButton() {
|
||||||
{
|
|
||||||
GD.Print("Apply Collor Pattern!");
|
GD.Print("Apply Collor Pattern!");
|
||||||
//currentMaterial.SetShaderParam("MapAlbedoTexture", _colorPatternTexture);
|
//currentMaterial.SetShaderParam("MapAlbedoTexture", _colorPatternTexture);
|
||||||
_customTileMaterial.SetShaderParam("MapAlbedoTexture", _colorPatternTexture);
|
_customTileMaterial.SetShaderParam("MapAlbedoTexture", _colorPatternTexture);
|
||||||
|
@ -63,9 +58,8 @@ public class HexTile3DMaterialAssign : Spatial
|
||||||
// _hexTile.Mesh.SetSurfaceMaterial(0, _customTileMaterial);
|
// _hexTile.Mesh.SetSurfaceMaterial(0, _customTileMaterial);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTextureSizeChanged(float value)
|
public void OnTextureSizeChanged(float value) {
|
||||||
{
|
_customTileMaterial.SetShaderParam("TextureSize", (int)value);
|
||||||
_customTileMaterial.SetShaderParam("TextureSize", (int) value);
|
|
||||||
GD.Print("Texture size: " + _customTileMaterial.GetShaderParam("TextureSize"));
|
GD.Print("Texture size: " + _customTileMaterial.GetShaderParam("TextureSize"));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,8 @@
|
||||||
using Godot;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using Godot;
|
||||||
using Godot.Collections;
|
using Godot.Collections;
|
||||||
|
|
||||||
public class NavigationTests : Spatial
|
public class NavigationTests : Spatial {
|
||||||
{
|
|
||||||
private HexGrid _hexGrid;
|
private HexGrid _hexGrid;
|
||||||
private HexCell _currentTile;
|
private HexCell _currentTile;
|
||||||
private HexCell _lastTile;
|
private HexCell _lastTile;
|
||||||
|
@ -13,13 +11,11 @@ public class NavigationTests : Spatial
|
||||||
private ShaderMaterial _tileMaterial;
|
private ShaderMaterial _tileMaterial;
|
||||||
|
|
||||||
private EditorUI _editorUi;
|
private EditorUI _editorUi;
|
||||||
private TileWorld _tileWorld;
|
private World _world;
|
||||||
private StreamContainer _streamContainer;
|
|
||||||
private Player _player;
|
private Player _player;
|
||||||
private NavigationComponent _playerNavigationComponent;
|
private NavigationComponent _playerNavigationComponent;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
_hexGrid = new HexGrid();
|
_hexGrid = new HexGrid();
|
||||||
_currentTile = new HexCell();
|
_currentTile = new HexCell();
|
||||||
_lastTile = new HexCell();
|
_lastTile = new HexCell();
|
||||||
|
@ -29,37 +25,32 @@ public class NavigationTests : Spatial
|
||||||
_mouseHighlight = GetNode<Spatial>("MouseHighlight");
|
_mouseHighlight = GetNode<Spatial>("MouseHighlight");
|
||||||
|
|
||||||
_editorUi = GetNode<EditorUI>("EditorUI");
|
_editorUi = GetNode<EditorUI>("EditorUI");
|
||||||
_tileWorld = GetNode<TileWorld>("TileWorld");
|
_world = GetNode<World>("World");
|
||||||
_tileWorld.Connect("WorldGenerated", this, nameof(OnWorldGenerated));
|
|
||||||
_streamContainer = GetNode<StreamContainer>("StreamContainer");
|
|
||||||
|
|
||||||
_streamContainer.SetCenterTile(_currentTile);
|
|
||||||
|
|
||||||
_player = GetNode<Player>("Player");
|
_player = GetNode<Player>("Player");
|
||||||
_playerNavigationComponent = _player.GetNode<NavigationComponent>("Navigation");
|
_playerNavigationComponent = _player.GetNode<NavigationComponent>("Navigation");
|
||||||
|
|
||||||
// input handling
|
// connect signals
|
||||||
// _groundLayer.Connect("input_event", this, nameof(OnGroundLayerInputEvent));
|
_world.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||||
_streamContainer.Connect("TileClicked", this, nameof(OnTileClicked));
|
_world.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||||
_streamContainer.Connect("TileHovered", this, nameof(OnTileHovered));
|
_world.Connect("OnWorldViewTileTypeImageChanged", this, nameof(OnWorldViewTileTypeImageChanged));
|
||||||
|
_world.Connect("OnHeightmapImageChanged", this, nameof(OnHeightmapImageChanged));
|
||||||
|
|
||||||
|
|
||||||
CorrectEntityGridPositions();
|
CorrectEntityGridPositions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CorrectEntityGridPositions()
|
public void CorrectEntityGridPositions() {
|
||||||
{
|
|
||||||
Spatial entitiesNode = GetNode<Spatial>("Entities");
|
Spatial entitiesNode = GetNode<Spatial>("Entities");
|
||||||
if (entitiesNode == null)
|
if (entitiesNode == null) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var entities = entitiesNode.GetChildren();
|
Array entities = entitiesNode.GetChildren();
|
||||||
foreach (Spatial entity in entities)
|
foreach (Spatial entity in entities) {
|
||||||
{
|
Vector2 entityPlaneCoords = new(entity.GlobalTranslation.x, entity.GlobalTranslation.z);
|
||||||
Vector2 entityPlaneCoords = new Vector2(entity.GlobalTranslation.x, entity.GlobalTranslation.z);
|
HexCell entityCell = _world.HexGrid.GetHexAt(entityPlaneCoords);
|
||||||
HexCell entityCell = _tileWorld.HexGrid.GetHexAt(entityPlaneCoords);
|
_world.MarkCellUnwalkable(entityCell);
|
||||||
_tileWorld.MarkCellUnwalkable(entityCell);
|
|
||||||
Vector2 cellPlaneCoords = _hexGrid.GetHexCenterFromOffset(entityCell.OffsetCoords);
|
Vector2 cellPlaneCoords = _hexGrid.GetHexCenterFromOffset(entityCell.OffsetCoords);
|
||||||
Vector3 entityGlobalTranslation = entity.GlobalTranslation;
|
Vector3 entityGlobalTranslation = entity.GlobalTranslation;
|
||||||
entityGlobalTranslation.x = cellPlaneCoords.x;
|
entityGlobalTranslation.x = cellPlaneCoords.x;
|
||||||
|
@ -68,32 +59,26 @@ public class NavigationTests : Spatial
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnWorldGenerated()
|
private void OnHeightmapImageChanged(Image heightmapImage) {
|
||||||
{
|
ImageTexture newHeightmapTexture = new();
|
||||||
_streamContainer.OnWorldGenerated();
|
newHeightmapTexture.CreateFromImage(heightmapImage,
|
||||||
|
|
||||||
// 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));
|
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||||
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
|
}
|
||||||
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.ColormapImage.GetSize().x);
|
|
||||||
|
|
||||||
CorrectEntityGridPositions();
|
private void OnWorldViewTileTypeImageChanged(Image viewTileTypeImage) {
|
||||||
|
ImageTexture newWorldTexture = new();
|
||||||
|
newWorldTexture.CreateFromImage(viewTileTypeImage,
|
||||||
|
(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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void UpdateCurrentTile(HexCell tile)
|
public void UpdateCurrentTile(HexCell tile) {
|
||||||
{
|
if (_currentTile.AxialCoords == tile.AxialCoords) {
|
||||||
if (_currentTile.AxialCoords == tile.AxialCoords)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,41 +87,29 @@ public class NavigationTests : Spatial
|
||||||
|
|
||||||
GD.Print("Current tile: " + _currentTile.OffsetCoords);
|
GD.Print("Current tile: " + _currentTile.OffsetCoords);
|
||||||
|
|
||||||
if (_lastTile.OffsetCoords != _currentTile.OffsetCoords && _editorUi != null)
|
if (_lastTile.OffsetCoords != _currentTile.OffsetCoords && _editorUi != null) {
|
||||||
{
|
|
||||||
_editorUi.currentTileOffset = _currentTile.OffsetCoords;
|
_editorUi.currentTileOffset = _currentTile.OffsetCoords;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 planeCoords = _hexGrid.GetHexCenterFromOffset(_currentTile.OffsetCoords);
|
Vector2 planeCoords = _hexGrid.GetHexCenterFromOffset(_currentTile.OffsetCoords);
|
||||||
Transform tileTransform = Transform.Identity;
|
|
||||||
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,
|
public void OnGroundLayerInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
|
||||||
int shapeIndex)
|
int shapeIndex) {
|
||||||
{
|
|
||||||
UpdateCurrentTile(_hexGrid.GetHexAt(new Vector2(position.x, position.z)));
|
UpdateCurrentTile(_hexGrid.GetHexAt(new Vector2(position.x, position.z)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTileClicked(HexTile3D tile)
|
public void OnTileClicked(HexTile3D tile) {
|
||||||
{
|
if (_editorUi != null) {
|
||||||
if (_editorUi != null)
|
|
||||||
{
|
|
||||||
_editorUi.OnTileClicked(tile.OffsetCoords);
|
_editorUi.OnTileClicked(tile.OffsetCoords);
|
||||||
|
|
||||||
if (_editorUi.CurrentInputMode == EditorUI.InputMode.Navigate)
|
if (_editorUi.CurrentInputMode == EditorUI.InputMode.Navigate) {
|
||||||
{
|
|
||||||
_playerNavigationComponent.FindPath(_player, _player.GlobalTranslation, tile.GlobalTranslation);
|
_playerNavigationComponent.FindPath(_player, _player.GlobalTranslation, tile.GlobalTranslation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTileHovered(HexTile3D tile)
|
public void OnTileHovered(HexTile3D tile) {
|
||||||
{
|
|
||||||
UpdateCurrentTile(tile.Cell);
|
UpdateCurrentTile(tile.Cell);
|
||||||
|
|
||||||
Debug.Assert(_playerNavigationComponent != null);
|
Debug.Assert(_playerNavigationComponent != null);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=25 format=2]
|
[gd_scene load_steps=26 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://entities/Player.tscn" type="PackedScene" id=1]
|
[ext_resource path="res://entities/Player.tscn" type="PackedScene" id=1]
|
||||||
[ext_resource path="res://scenes/TileWorld.tscn" type="PackedScene" id=2]
|
[ext_resource path="res://scenes/TileWorld.tscn" type="PackedScene" id=2]
|
||||||
|
@ -11,6 +11,7 @@
|
||||||
[ext_resource path="res://scenes/HexTile3DPatch.tscn" type="PackedScene" id=9]
|
[ext_resource path="res://scenes/HexTile3DPatch.tscn" type="PackedScene" id=9]
|
||||||
[ext_resource path="res://entities/rockB.tscn" type="PackedScene" id=10]
|
[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://entities/Chest.tscn" type="PackedScene" id=11]
|
||||||
|
[ext_resource path="res://scenes/World.tscn" type="PackedScene" id=12]
|
||||||
|
|
||||||
[sub_resource type="AnimationNodeStateMachinePlayback" id=8]
|
[sub_resource type="AnimationNodeStateMachinePlayback" id=8]
|
||||||
|
|
||||||
|
@ -289,18 +290,21 @@ script = ExtResource( 4 )
|
||||||
|
|
||||||
[node name="Player" parent="." instance=ExtResource( 1 )]
|
[node name="Player" parent="." instance=ExtResource( 1 )]
|
||||||
collision_mask = 1
|
collision_mask = 1
|
||||||
TileWorldNode = NodePath("../TileWorld")
|
WorldNode = NodePath("../World")
|
||||||
|
|
||||||
[node name="ToolAttachement" parent="Player/Geometry/Armature/Skeleton" index="5"]
|
[node name="WorldInfo" parent="Player" index="2"]
|
||||||
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 )
|
WorldPath = NodePath("../../World")
|
||||||
|
|
||||||
|
[node name="ToolAttachement" parent="Player/Geometry/PirateAsset/Armature/Skeleton" index="5"]
|
||||||
|
transform = Transform( 1, 7.13626e-08, -4.47035e-08, 1.64262e-07, -1, -1.00583e-07, 1.19209e-07, 1.18278e-07, -1, -0.72, 0.45, 1.78362e-08 )
|
||||||
|
|
||||||
[node name="AnimationTree" parent="Player/Geometry" index="2"]
|
[node name="AnimationTree" parent="Player/Geometry" index="2"]
|
||||||
parameters/playback = SubResource( 8 )
|
parameters/playback = SubResource( 8 )
|
||||||
|
|
||||||
[node name="TileWorld" parent="." instance=ExtResource( 2 )]
|
[node name="TileWorld" parent="." instance=ExtResource( 2 )]
|
||||||
|
DebugMap = true
|
||||||
GenerationMapType = 2
|
GenerationMapType = 2
|
||||||
Size = 20
|
Size = 20
|
||||||
DebugMap = true
|
|
||||||
|
|
||||||
[node name="MouseHighlight" parent="." instance=ExtResource( 3 )]
|
[node name="MouseHighlight" parent="." instance=ExtResource( 3 )]
|
||||||
|
|
||||||
|
@ -374,8 +378,10 @@ anims/TreeShake = SubResource( 17 )
|
||||||
[node name="Geometry" parent="Entities/Tree5" index="2"]
|
[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 )
|
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"]
|
||||||
[editable path="Player/Geometry"]
|
[editable path="Player/Geometry/PirateAsset"]
|
||||||
[editable path="TileWorld"]
|
[editable path="TileWorld"]
|
||||||
[editable path="StreamContainer"]
|
[editable path="StreamContainer"]
|
||||||
[editable path="Entities/Chest"]
|
[editable path="Entities/Chest"]
|
||||||
|
|
|
@ -1,51 +1,40 @@
|
||||||
using Godot;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Godot.Collections;
|
using Godot;
|
||||||
using GodotComponentTest.components;
|
using GodotComponentTest.components;
|
||||||
using GodotComponentTest.entities;
|
using GodotComponentTest.entities;
|
||||||
using Array = System.Array;
|
|
||||||
using NodePair = System.Tuple<Godot.Node, Godot.Node>;
|
using NodePair = System.Tuple<Godot.Node, Godot.Node>;
|
||||||
|
|
||||||
public class InteractionSystem : Node
|
public class InteractionSystem : Node {
|
||||||
{
|
|
||||||
private List<InteractionComponent> _activeInteractions;
|
private List<InteractionComponent> _activeInteractions;
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
_activeInteractions = new List<InteractionComponent>();
|
_activeInteractions = new List<InteractionComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process(float delta)
|
public override void _Process(float delta) {
|
||||||
{
|
|
||||||
base._Process(delta);
|
base._Process(delta);
|
||||||
|
|
||||||
List<NodePair> invalidInteractionPairs = new List<NodePair>();
|
List<InteractionComponent> endedInteractions = new();
|
||||||
List<InteractionComponent> endedInteractions = new List<InteractionComponent>();
|
|
||||||
|
|
||||||
foreach (InteractionComponent interaction in _activeInteractions)
|
foreach (InteractionComponent interaction in _activeInteractions) {
|
||||||
{
|
|
||||||
Spatial owningEntity = interaction.OwningEntity;
|
Spatial owningEntity = interaction.OwningEntity;
|
||||||
Spatial targetEntity = interaction.TargetEntity;
|
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;
|
interaction.hasStopped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interaction.hasStopped)
|
if (interaction.hasStopped) {
|
||||||
{
|
|
||||||
IInteractionInterface interactableA = owningEntity as IInteractionInterface;
|
IInteractionInterface interactableA = owningEntity as IInteractionInterface;
|
||||||
if (interactableA != null)
|
if (interactableA != null) {
|
||||||
{
|
|
||||||
interactableA.OnInteractionEnd();
|
interactableA.OnInteractionEnd();
|
||||||
interactableA.InteractionComponent = null;
|
interactableA.InteractionComponent = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
IInteractionInterface interactableB = targetEntity as IInteractionInterface;
|
IInteractionInterface interactableB = targetEntity as IInteractionInterface;
|
||||||
if (interactableB != null)
|
if (interactableB != null) {
|
||||||
{
|
|
||||||
interactableB.OnInteractionEnd();
|
interactableB.OnInteractionEnd();
|
||||||
interactableB.InteractionComponent = null;
|
interactableB.InteractionComponent = null;
|
||||||
}
|
}
|
||||||
|
@ -55,14 +44,11 @@ public class InteractionSystem : Node
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (InteractionComponent interaction in endedInteractions)
|
foreach (InteractionComponent interaction in endedInteractions)
|
||||||
{
|
|
||||||
_activeInteractions.Remove(interaction);
|
_activeInteractions.Remove(interaction);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void OnStartInteraction(Entity owningEntity, Entity targetEntity)
|
public void OnStartInteraction(Entity owningEntity, Entity targetEntity) {
|
||||||
{
|
InteractionComponent interactionComponent = new();
|
||||||
InteractionComponent interactionComponent = new InteractionComponent();
|
|
||||||
interactionComponent.OwningEntity = owningEntity;
|
interactionComponent.OwningEntity = owningEntity;
|
||||||
interactionComponent.TargetEntity = targetEntity;
|
interactionComponent.TargetEntity = targetEntity;
|
||||||
|
|
||||||
|
@ -74,11 +60,9 @@ public class InteractionSystem : Node
|
||||||
_activeInteractions.Add(interactionComponent);
|
_activeInteractions.Add(interactionComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ConnectInteractionSignals(Entity entity, InteractionComponent interactionComponent)
|
private static void ConnectInteractionSignals(Entity entity, InteractionComponent interactionComponent) {
|
||||||
{
|
|
||||||
IInteractionInterface interactable = entity as IInteractionInterface;
|
IInteractionInterface interactable = entity as IInteractionInterface;
|
||||||
if (interactable != null)
|
if (interactable != null) {
|
||||||
{
|
|
||||||
interactable.InteractionComponent = interactionComponent;
|
interactable.InteractionComponent = interactionComponent;
|
||||||
interactionComponent.Connect("InteractionStart", entity, nameof(interactable.OnInteractionStart));
|
interactionComponent.Connect("InteractionStart", entity, nameof(interactable.OnInteractionStart));
|
||||||
interactionComponent.Connect("InteractionEnd", entity, nameof(interactable.OnInteractionEnd));
|
interactionComponent.Connect("InteractionEnd", entity, nameof(interactable.OnInteractionEnd));
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
public class LookupWorldSystem : IWorldSystemInterface
|
using System;
|
||||||
{
|
|
||||||
public void RegisterEntityComponent(Entity entity, Component component)
|
public class LookupWorldSystem : IWorldSystemInterface {
|
||||||
{
|
public void RegisterEntityComponent(Entity entity, Component component) {
|
||||||
throw new System.NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(float delta)
|
public void Update(float delta) {
|
||||||
{
|
throw new NotImplementedException();
|
||||||
throw new System.NotImplementedException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
public interface IWorldSystemInterface
|
public interface IWorldSystemInterface {
|
||||||
{
|
|
||||||
void RegisterEntityComponent(Entity entity, Component component);
|
void RegisterEntityComponent(Entity entity, Component component);
|
||||||
void Update(float delta);
|
void Update(float delta);
|
||||||
}
|
}
|
|
@ -1,27 +1,22 @@
|
||||||
using Godot;
|
|
||||||
using GoDotTest;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Godot;
|
||||||
|
using GoDotTest;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
public class HexCellTests : TestClass
|
public class HexCellTests : TestClass {
|
||||||
{
|
public HexCellTests(Node testScene) : base(testScene) { }
|
||||||
public HexCellTests(Node testScene) : base(testScene)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestHexCellSimple()
|
public void TestHexCellSimple() {
|
||||||
{
|
HexCell cell = new();
|
||||||
HexCell cell = new HexCell();
|
|
||||||
Debug.Assert(cell.CubeCoords == new Vector3(0, 0, 0));
|
Debug.Assert(cell.CubeCoords == new Vector3(0, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestHexCellEqualityInequality()
|
public void TestHexCellEqualityInequality() {
|
||||||
{
|
HexCell cellA = new();
|
||||||
HexCell cellA = new HexCell();
|
HexCell cellB = new();
|
||||||
HexCell cellB = new HexCell();
|
|
||||||
|
|
||||||
cellA.AxialCoords = new Vector2(2, 3);
|
cellA.AxialCoords = new Vector2(2, 3);
|
||||||
cellB.AxialCoords = new Vector2(2, 3);
|
cellB.AxialCoords = new Vector2(2, 3);
|
||||||
|
@ -37,9 +32,8 @@ public class HexCellTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAxialCoords()
|
public void TestAxialCoords() {
|
||||||
{
|
HexCell cell = new(1, 1, -2);
|
||||||
HexCell cell = new HexCell(1, 1, -2);
|
|
||||||
Debug.Assert(cell.AxialCoords == new Vector2(1, 1));
|
Debug.Assert(cell.AxialCoords == new Vector2(1, 1));
|
||||||
|
|
||||||
cell = new HexCell(1, -1);
|
cell = new HexCell(1, -1);
|
||||||
|
@ -51,9 +45,8 @@ public class HexCellTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAxialCoordsRounded()
|
public void TestAxialCoordsRounded() {
|
||||||
{
|
HexCell cell = new(new Vector2(-0.1f, 0.6f));
|
||||||
HexCell cell = new HexCell(new Vector2(-0.1f, 0.6f));
|
|
||||||
Debug.Assert(cell.CubeCoords == new Vector3(0, 1, -1));
|
Debug.Assert(cell.CubeCoords == new Vector3(0, 1, -1));
|
||||||
|
|
||||||
cell = new HexCell(new Vector2(4.2f, -5.5f));
|
cell = new HexCell(new Vector2(4.2f, -5.5f));
|
||||||
|
@ -61,17 +54,15 @@ public class HexCellTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestConversion()
|
public void TestConversion() {
|
||||||
{
|
HexCell cell = new();
|
||||||
HexCell cell = new HexCell();
|
|
||||||
Debug.Assert(cell.AxialToCubeCoords(new Vector2(2, 1)) == new Vector3(2, 1, -3));
|
Debug.Assert(cell.AxialToCubeCoords(new Vector2(2, 1)) == new Vector3(2, 1, -3));
|
||||||
Debug.Assert(cell.AxialToCubeCoords(new Vector2(-1, -1)) == new Vector3(-1, -1, 2));
|
Debug.Assert(cell.AxialToCubeCoords(new Vector2(-1, -1)) == new Vector3(-1, -1, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestRounding()
|
public void TestRounding() {
|
||||||
{
|
HexCell cell = new();
|
||||||
HexCell cell = new HexCell();
|
|
||||||
Debug.Assert(cell.RoundCoords(new Vector3(0.1f, 0.5f, -0.6f)) == new Vector3(0, 1, -1));
|
Debug.Assert(cell.RoundCoords(new Vector3(0.1f, 0.5f, -0.6f)) == new Vector3(0, 1, -1));
|
||||||
Debug.Assert(cell.RoundCoords(new Vector3(-0.4f, -1.3f, 1.7f)) == new Vector3(-1, -1, 2));
|
Debug.Assert(cell.RoundCoords(new Vector3(-0.4f, -1.3f, 1.7f)) == new Vector3(-1, -1, 2));
|
||||||
|
|
||||||
|
@ -80,9 +71,8 @@ public class HexCellTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestCoords()
|
public void TestCoords() {
|
||||||
{
|
HexCell cell = new();
|
||||||
HexCell cell = new HexCell();
|
|
||||||
|
|
||||||
// from cubic positive
|
// from cubic positive
|
||||||
cell.CubeCoords = new Vector3(2, 1, -3);
|
cell.CubeCoords = new Vector3(2, 1, -3);
|
||||||
|
@ -104,9 +94,8 @@ public class HexCellTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNearby()
|
public void TestNearby() {
|
||||||
{
|
HexCell cell = new(new Vector2(1, 2));
|
||||||
HexCell cell = new HexCell(new Vector2(1, 2));
|
|
||||||
|
|
||||||
// adjacent
|
// adjacent
|
||||||
HexCell otherCell = cell.GetAdjacent(HexCell.DIR_N);
|
HexCell otherCell = cell.GetAdjacent(HexCell.DIR_N);
|
||||||
|
@ -128,9 +117,8 @@ public class HexCellTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestDistance()
|
public void TestDistance() {
|
||||||
{
|
HexCell cell = new();
|
||||||
HexCell cell = new HexCell();
|
|
||||||
cell.OffsetCoords = new Vector2(1, 2);
|
cell.OffsetCoords = new Vector2(1, 2);
|
||||||
|
|
||||||
Debug.Assert(cell.DistanceTo(new HexCell(new Vector2(0, 0))) == 3);
|
Debug.Assert(cell.DistanceTo(new HexCell(new Vector2(0, 0))) == 3);
|
||||||
|
@ -140,80 +128,71 @@ public class HexCellTests : TestClass
|
||||||
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestLineTo()
|
public void TestLineTo() {
|
||||||
{
|
HexCell cell = new();
|
||||||
HexCell cell = new HexCell();
|
|
||||||
cell.OffsetCoords = new Vector2(1, 2);
|
cell.OffsetCoords = new Vector2(1, 2);
|
||||||
|
|
||||||
HexCell[] path = cell.LineTo(new HexCell(5, 2));
|
HexCell[] path = cell.LineTo(new HexCell(5, 2));
|
||||||
|
|
||||||
HexCell[] pathExpected =
|
HexCell[] pathExpected = {
|
||||||
{
|
new(1, 2),
|
||||||
new HexCell(1, 2),
|
new(2, 2),
|
||||||
new HexCell(2, 2),
|
new(3, 2),
|
||||||
new HexCell(3, 2),
|
new(4, 2),
|
||||||
new HexCell(4, 2),
|
new(5, 2)
|
||||||
new HexCell(5, 2)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Debug.Assert(path.Length == pathExpected.Length);
|
Debug.Assert(path.Length == pathExpected.Length);
|
||||||
|
|
||||||
foreach (int index in Enumerable.Range(0, path.Length))
|
foreach (int index in Enumerable.Range(0, path.Length)) {
|
||||||
{
|
|
||||||
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestLineToAngled()
|
public void TestLineToAngled() {
|
||||||
{
|
HexCell cell = new();
|
||||||
HexCell cell = new HexCell();
|
|
||||||
cell.OffsetCoords = new Vector2(1, 2);
|
cell.OffsetCoords = new Vector2(1, 2);
|
||||||
|
|
||||||
HexCell[] path = cell.LineTo(new HexCell(5, 4));
|
HexCell[] path = cell.LineTo(new HexCell(5, 4));
|
||||||
|
|
||||||
HexCell[] pathExpected =
|
HexCell[] pathExpected = {
|
||||||
{
|
new(1, 2),
|
||||||
new HexCell(1, 2),
|
new(2, 2),
|
||||||
new HexCell(2, 2),
|
new(2, 3),
|
||||||
new HexCell(2, 3),
|
new(3, 3),
|
||||||
new HexCell(3, 3),
|
new(4, 3),
|
||||||
new HexCell(4, 3),
|
new(4, 4),
|
||||||
new HexCell(4, 4),
|
new(5, 4)
|
||||||
new HexCell(5, 4)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Debug.Assert(path.Length == pathExpected.Length);
|
Debug.Assert(path.Length == pathExpected.Length);
|
||||||
|
|
||||||
foreach (int index in Enumerable.Range(0, path.Length))
|
foreach (int index in Enumerable.Range(0, path.Length)) {
|
||||||
{
|
|
||||||
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestLineEdge()
|
public void TestLineEdge() {
|
||||||
{
|
HexCell cell = new();
|
||||||
HexCell cell = new HexCell();
|
|
||||||
cell.OffsetCoords = new Vector2(1, 2);
|
cell.OffsetCoords = new Vector2(1, 2);
|
||||||
|
|
||||||
HexCell[] path = cell.LineTo(new HexCell(3, 4));
|
HexCell[] path = cell.LineTo(new HexCell(3, 4));
|
||||||
|
|
||||||
HexCell[] pathExpected =
|
HexCell[] pathExpected = {
|
||||||
{
|
new(1, 2),
|
||||||
new HexCell(1, 2),
|
new(2, 2),
|
||||||
new HexCell(2, 2),
|
new(2, 3),
|
||||||
new HexCell(2, 3),
|
new(2, 4),
|
||||||
new HexCell(2, 4),
|
new(3, 4)
|
||||||
new HexCell(3, 4)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Debug.Assert(path.Length == pathExpected.Length);
|
Debug.Assert(path.Length == pathExpected.Length);
|
||||||
|
|
||||||
foreach (int index in Enumerable.Range(0, path.Length))
|
foreach (int index in Enumerable.Range(0, path.Length)) {
|
||||||
{
|
|
||||||
Debug.Print("index: " + index + " path: " + path[index].AxialCoords + " expected: " +
|
Debug.Print("index: " + index + " path: " + path[index].AxialCoords + " expected: " +
|
||||||
pathExpected[index].AxialCoords);
|
pathExpected[index].AxialCoords);
|
||||||
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
||||||
|
@ -221,9 +200,8 @@ public class HexCellTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestCellDirections()
|
public void TestCellDirections() {
|
||||||
{
|
HexCell cell = new();
|
||||||
HexCell cell = new HexCell();
|
|
||||||
|
|
||||||
HexCell cellN = HexCell.FromOffsetCoords(new Vector2(0, 1));
|
HexCell cellN = HexCell.FromOffsetCoords(new Vector2(0, 1));
|
||||||
HexCell cellNW = HexCell.FromOffsetCoords(new Vector2(-1, 0));
|
HexCell cellNW = HexCell.FromOffsetCoords(new Vector2(-1, 0));
|
||||||
|
@ -252,8 +230,7 @@ public class HexCellTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestCellDirectionsNonzeroReference()
|
public void TestCellDirectionsNonzeroReference() {
|
||||||
{
|
|
||||||
HexCell cell = HexCell.FromOffsetCoords(new Vector2(-4, -3));
|
HexCell cell = HexCell.FromOffsetCoords(new Vector2(-4, -3));
|
||||||
|
|
||||||
HexCell cellN = HexCell.FromOffsetCoords(new Vector2(-4, -2));
|
HexCell cellN = HexCell.FromOffsetCoords(new Vector2(-4, -2));
|
||||||
|
@ -283,9 +260,8 @@ public class HexCellTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNextCellAlongLine()
|
public void TestNextCellAlongLine() {
|
||||||
{
|
HexCell cell = new();
|
||||||
HexCell cell = new HexCell();
|
|
||||||
HexCell cellN = HexCell.FromOffsetCoords(new Vector2(0, 1));
|
HexCell cellN = HexCell.FromOffsetCoords(new Vector2(0, 1));
|
||||||
HexCell cellNE = HexCell.FromOffsetCoords(new Vector2(1, 0));
|
HexCell cellNE = HexCell.FromOffsetCoords(new Vector2(1, 0));
|
||||||
HexCell cellSE = HexCell.FromOffsetCoords(new Vector2(1, -1));
|
HexCell cellSE = HexCell.FromOffsetCoords(new Vector2(1, -1));
|
||||||
|
|
|
@ -7,50 +7,43 @@ using Xunit;
|
||||||
|
|
||||||
namespace GodotComponentTest.tests;
|
namespace GodotComponentTest.tests;
|
||||||
|
|
||||||
public class HexGridPathFindingTests : TestClass
|
public class HexGridPathFindingTests : TestClass {
|
||||||
{
|
|
||||||
private HexGrid _hexGrid;
|
private HexGrid _hexGrid;
|
||||||
private HexCell _hexCell;
|
private HexCell _hexCell;
|
||||||
|
|
||||||
private HexCell _positionA = new HexCell(new Vector2(2, 0));
|
private readonly HexCell _positionA = new(new Vector2(2, 0));
|
||||||
private HexCell _positionB = new HexCell(new Vector2(4, 2));
|
private readonly HexCell _positionB = new(new Vector2(4, 2));
|
||||||
private HexCell _positionC = new HexCell(new Vector2(7, 0));
|
private readonly HexCell _positionC = new(new Vector2(7, 0));
|
||||||
private HexCell _positionD = new HexCell(new Vector2(5, 0));
|
private readonly HexCell _positionD = new(new Vector2(5, 0));
|
||||||
private HexCell _positionE = new HexCell(new Vector2(2, 2));
|
private HexCell _positionE = new(new Vector2(2, 2));
|
||||||
private HexCell _positionF = new HexCell(new Vector2(1, 3));
|
private HexCell _positionF = new(new Vector2(1, 3));
|
||||||
private HexCell _positionG = new HexCell(new Vector2(1, 0));
|
private readonly HexCell _positionG = new(new Vector2(1, 0));
|
||||||
|
|
||||||
private Vector2[] _obstacles =
|
private readonly Vector2[] _obstacles = {
|
||||||
{
|
new(2, 1),
|
||||||
new Vector2(2, 1),
|
new(3, 1),
|
||||||
new Vector2(3, 1),
|
new(4, 1),
|
||||||
new Vector2(4, 1),
|
new(1, 2),
|
||||||
new Vector2(1, 2),
|
new(3, 2),
|
||||||
new Vector2(3, 2),
|
new(1, 3),
|
||||||
new Vector2(1, 3),
|
new(2, 3)
|
||||||
new Vector2(2, 3),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public HexGridPathFindingTests(Node testScene) : base(testScene)
|
public HexGridPathFindingTests(Node testScene) : base(testScene) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
public void Setup()
|
public void Setup() {
|
||||||
{
|
|
||||||
_hexGrid = new HexGrid();
|
_hexGrid = new HexGrid();
|
||||||
_hexCell = new HexCell();
|
_hexCell = new HexCell();
|
||||||
|
|
||||||
_hexGrid.SetBounds(new Vector2(0, 0), new Vector2(7, 4));
|
_hexGrid.SetBounds(new Vector2(0, 0), new Vector2(7, 4));
|
||||||
foreach (Vector2 obstacle in _obstacles)
|
foreach (Vector2 obstacle in _obstacles) {
|
||||||
{
|
|
||||||
_hexGrid.AddObstacle(new HexCell(obstacle));
|
_hexGrid.AddObstacle(new HexCell(obstacle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestBounds()
|
public void TestBounds() {
|
||||||
{
|
|
||||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(0, 0)));
|
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(0, 0)));
|
||||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(0, 4)));
|
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(0, 4)));
|
||||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(7, 0)));
|
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(7, 0)));
|
||||||
|
@ -63,9 +56,8 @@ public class HexGridPathFindingTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNegativeBounds()
|
public void TestNegativeBounds() {
|
||||||
{
|
HexGrid grid = new();
|
||||||
HexGrid grid = new HexGrid();
|
|
||||||
grid.SetBounds(new Vector2(-5, -5), new Vector2(-2, -2));
|
grid.SetBounds(new Vector2(-5, -5), new Vector2(-2, -2));
|
||||||
|
|
||||||
Assert.Equal(grid.PathCostDefault, grid.GetHexCost(new Vector2(-2, -2)));
|
Assert.Equal(grid.PathCostDefault, grid.GetHexCost(new Vector2(-2, -2)));
|
||||||
|
@ -76,9 +68,8 @@ public class HexGridPathFindingTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNegativeBoundsAlt()
|
public void TestNegativeBoundsAlt() {
|
||||||
{
|
HexGrid grid = new();
|
||||||
HexGrid grid = new HexGrid();
|
|
||||||
grid.SetBounds(new Vector2(-3, -3), new Vector2(2, 2));
|
grid.SetBounds(new Vector2(-3, -3), new Vector2(2, 2));
|
||||||
|
|
||||||
Assert.Equal(grid.PathCostDefault, grid.GetHexCost(new Vector2(-3, -3)));
|
Assert.Equal(grid.PathCostDefault, grid.GetHexCost(new Vector2(-3, -3)));
|
||||||
|
@ -89,8 +80,7 @@ public class HexGridPathFindingTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestGridObstacles()
|
public void TestGridObstacles() {
|
||||||
{
|
|
||||||
Assert.Equal(_obstacles.Length, _hexGrid.Obstacles.Count);
|
Assert.Equal(_obstacles.Length, _hexGrid.Obstacles.Count);
|
||||||
|
|
||||||
// Adding an obstacle
|
// Adding an obstacle
|
||||||
|
@ -110,8 +100,7 @@ public class HexGridPathFindingTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestHexCost()
|
public void TestHexCost() {
|
||||||
{
|
|
||||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(1, 1)));
|
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetHexCost(new Vector2(1, 1)));
|
||||||
Assert.Equal(0, _hexGrid.GetHexCost(new HexCell(new Vector3(2, 1, -3))));
|
Assert.Equal(0, _hexGrid.GetHexCost(new HexCell(new Vector3(2, 1, -3))));
|
||||||
|
|
||||||
|
@ -120,14 +109,12 @@ public class HexGridPathFindingTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestMoveCost()
|
public void TestMoveCost() {
|
||||||
{
|
|
||||||
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetMoveCost(new Vector2(0, 0), HexCell.DIR_N));
|
Assert.Equal(_hexGrid.PathCostDefault, _hexGrid.GetMoveCost(new Vector2(0, 0), HexCell.DIR_N));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestMovieCostCumulative()
|
public void TestMovieCostCumulative() {
|
||||||
{
|
|
||||||
_hexGrid.AddObstacle(new Vector2(0, 0), 1);
|
_hexGrid.AddObstacle(new Vector2(0, 0), 1);
|
||||||
_hexGrid.AddObstacle(new Vector2(0, 1), 2);
|
_hexGrid.AddObstacle(new Vector2(0, 1), 2);
|
||||||
_hexGrid.AddBarrier(new Vector2(0, 0), HexCell.DIR_N, 4);
|
_hexGrid.AddBarrier(new Vector2(0, 0), HexCell.DIR_N, 4);
|
||||||
|
@ -138,12 +125,10 @@ public class HexGridPathFindingTests : TestClass
|
||||||
Assert.Equal(14, _hexGrid.GetMoveCost(new Vector2(0, 0), HexCell.DIR_N));
|
Assert.Equal(14, _hexGrid.GetMoveCost(new Vector2(0, 0), HexCell.DIR_N));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComparePath(List<HexCell> expected, List<HexCell> path)
|
private void ComparePath(List<HexCell> expected, List<HexCell> path) {
|
||||||
{
|
|
||||||
Assert.Equal(expected.Count, path.Count());
|
Assert.Equal(expected.Count, path.Count());
|
||||||
|
|
||||||
foreach (int i in Enumerable.Range(0, Math.Min(expected.Count, path.Count())))
|
foreach (int i in Enumerable.Range(0, Math.Min(expected.Count, path.Count()))) {
|
||||||
{
|
|
||||||
HexCell pathCell = path[i];
|
HexCell pathCell = path[i];
|
||||||
HexCell expectedCell = expected[i];
|
HexCell expectedCell = expected[i];
|
||||||
Assert.Equal(expectedCell.AxialCoords, pathCell.AxialCoords);
|
Assert.Equal(expectedCell.AxialCoords, pathCell.AxialCoords);
|
||||||
|
@ -151,10 +136,8 @@ public class HexGridPathFindingTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestStraightLine()
|
public void TestStraightLine() {
|
||||||
{
|
List<HexCell> expectedPath = new() {
|
||||||
List<HexCell> expectedPath = new List<HexCell>()
|
|
||||||
{
|
|
||||||
_positionA,
|
_positionA,
|
||||||
new HexCell(new Vector2(3, 0)),
|
new HexCell(new Vector2(3, 0)),
|
||||||
new HexCell(new Vector2(4, 0)),
|
new HexCell(new Vector2(4, 0)),
|
||||||
|
@ -184,10 +167,8 @@ public class HexGridPathFindingTests : TestClass
|
||||||
// }
|
// }
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestObstacle()
|
public void TestObstacle() {
|
||||||
{
|
List<HexCell> expectedPath = new() {
|
||||||
List<HexCell> expectedPath = new List<HexCell>()
|
|
||||||
{
|
|
||||||
_positionA,
|
_positionA,
|
||||||
new HexCell(new Vector2(3, 0)),
|
new HexCell(new Vector2(3, 0)),
|
||||||
new HexCell(new Vector2(4, 0)),
|
new HexCell(new Vector2(4, 0)),
|
||||||
|
@ -200,10 +181,8 @@ public class HexGridPathFindingTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestWalls()
|
public void TestWalls() {
|
||||||
{
|
Vector3[] walls = {
|
||||||
Vector3[] walls =
|
|
||||||
{
|
|
||||||
HexCell.DIR_N,
|
HexCell.DIR_N,
|
||||||
HexCell.DIR_NE,
|
HexCell.DIR_NE,
|
||||||
HexCell.DIR_SE,
|
HexCell.DIR_SE,
|
||||||
|
@ -212,13 +191,11 @@ public class HexGridPathFindingTests : TestClass
|
||||||
HexCell.DIR_NW
|
HexCell.DIR_NW
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (Vector3 wall in walls)
|
foreach (Vector3 wall in walls) {
|
||||||
{
|
|
||||||
_hexGrid.AddBarrier(_positionG, wall);
|
_hexGrid.AddBarrier(_positionG, wall);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<HexCell> expectedPath = new List<HexCell>()
|
List<HexCell> expectedPath = new() {
|
||||||
{
|
|
||||||
_positionA,
|
_positionA,
|
||||||
new HexCell(new Vector2(1, 1)),
|
new HexCell(new Vector2(1, 1)),
|
||||||
new HexCell(new Vector2(0, 1)),
|
new HexCell(new Vector2(0, 1)),
|
||||||
|
@ -230,13 +207,11 @@ public class HexGridPathFindingTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSlopes()
|
public void TestSlopes() {
|
||||||
{
|
|
||||||
_hexGrid.AddBarrier(_positionG, HexCell.DIR_NE, 3);
|
_hexGrid.AddBarrier(_positionG, HexCell.DIR_NE, 3);
|
||||||
_hexGrid.AddBarrier(_positionG, HexCell.DIR_N, _hexGrid.PathCostDefault - 0.1f);
|
_hexGrid.AddBarrier(_positionG, HexCell.DIR_N, _hexGrid.PathCostDefault - 0.1f);
|
||||||
|
|
||||||
List<HexCell> expectedPath = new List<HexCell>()
|
List<HexCell> expectedPath = new() {
|
||||||
{
|
|
||||||
_positionA,
|
_positionA,
|
||||||
new HexCell(new Vector2(1, 1)),
|
new HexCell(new Vector2(1, 1)),
|
||||||
_positionG
|
_positionG
|
||||||
|
@ -246,20 +221,17 @@ public class HexGridPathFindingTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestRoughTerrain()
|
public void TestRoughTerrain() {
|
||||||
{
|
List<HexCell> shortPath = new() {
|
||||||
List<HexCell> shortPath = new List<HexCell>()
|
|
||||||
{
|
|
||||||
_positionA,
|
_positionA,
|
||||||
new HexCell(new Vector2(3, 0)),
|
new HexCell(new Vector2(3, 0)),
|
||||||
new HexCell(new Vector2(4, 0)),
|
new HexCell(new Vector2(4, 0)),
|
||||||
_positionD,
|
_positionD,
|
||||||
new HexCell(new Vector2(5, 1)),
|
new HexCell(new Vector2(5, 1)),
|
||||||
_positionB,
|
_positionB
|
||||||
};
|
};
|
||||||
|
|
||||||
List<HexCell> longPath = new List<HexCell>()
|
List<HexCell> longPath = new() {
|
||||||
{
|
|
||||||
_positionA,
|
_positionA,
|
||||||
new HexCell(new Vector2(1, 1)),
|
new HexCell(new Vector2(1, 1)),
|
||||||
new HexCell(new Vector2(0, 2)),
|
new HexCell(new Vector2(0, 2)),
|
||||||
|
@ -268,7 +240,7 @@ public class HexGridPathFindingTests : TestClass
|
||||||
new HexCell(new Vector2(1, 4)),
|
new HexCell(new Vector2(1, 4)),
|
||||||
new HexCell(new Vector2(2, 4)),
|
new HexCell(new Vector2(2, 4)),
|
||||||
new HexCell(new Vector2(3, 3)),
|
new HexCell(new Vector2(3, 3)),
|
||||||
_positionB,
|
_positionB
|
||||||
};
|
};
|
||||||
|
|
||||||
_hexGrid.PathCostDefault = 1f;
|
_hexGrid.PathCostDefault = 1f;
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using Godot;
|
using Godot;
|
||||||
using GoDotTest;
|
using GoDotTest;
|
||||||
using System.Diagnostics;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
public class HexGridTests : TestClass
|
public class HexGridTests : TestClass {
|
||||||
{
|
public HexGridTests(Node testScene) : base(testScene) { }
|
||||||
public HexGridTests(Node testScene) : base(testScene)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestGetAt()
|
public void TestGetAt() {
|
||||||
{
|
HexGrid grid = new();
|
||||||
HexGrid grid = new HexGrid();
|
|
||||||
float w = grid.HexSize.x;
|
float w = grid.HexSize.x;
|
||||||
float h = grid.HexSize.y;
|
float h = grid.HexSize.y;
|
||||||
|
|
||||||
|
@ -24,9 +20,8 @@ public class HexGridTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestGetCellsForLineSimple()
|
public void TestGetCellsForLineSimple() {
|
||||||
{
|
HexGrid grid = new();
|
||||||
HexGrid grid = new HexGrid();
|
|
||||||
|
|
||||||
List<HexCell> lineCells =
|
List<HexCell> lineCells =
|
||||||
grid.GetCellsForLine(new Vector2(0, 0), grid.GetHexCenterFromOffset(new Vector2(0, 2)));
|
grid.GetCellsForLine(new Vector2(0, 0), grid.GetHexCenterFromOffset(new Vector2(0, 2)));
|
||||||
|
@ -46,9 +41,8 @@ public class HexGridTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestGetCellsDiagonal()
|
public void TestGetCellsDiagonal() {
|
||||||
{
|
HexGrid grid = new();
|
||||||
HexGrid grid = new HexGrid();
|
|
||||||
|
|
||||||
List<HexCell> lineCells =
|
List<HexCell> lineCells =
|
||||||
grid.GetCellsForLine(new Vector2(0, 0), grid.GetHexCenterFromOffset(new Vector2(2, 1)));
|
grid.GetCellsForLine(new Vector2(0, 0), grid.GetHexCenterFromOffset(new Vector2(2, 1)));
|
||||||
|
@ -68,9 +62,8 @@ public class HexGridTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestGetCellsForLineAlongEdge()
|
public void TestGetCellsForLineAlongEdge() {
|
||||||
{
|
HexGrid grid = new();
|
||||||
HexGrid grid = new HexGrid();
|
|
||||||
|
|
||||||
List<HexCell> lineCells =
|
List<HexCell> lineCells =
|
||||||
grid.GetCellsForLine(new Vector2(0, -0.0001f), grid.GetHexCenterFromOffset(new Vector2(2, 0)));
|
grid.GetCellsForLine(new Vector2(0, -0.0001f), grid.GetHexCenterFromOffset(new Vector2(2, 0)));
|
||||||
|
@ -90,12 +83,11 @@ public class HexGridTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void GetTestsInfiniteLoop()
|
public void GetTestsInfiniteLoop() {
|
||||||
{
|
HexGrid grid = new();
|
||||||
HexGrid grid = new HexGrid();
|
|
||||||
|
|
||||||
Vector2 fromPlane = new Vector2(-2.31678f, -5.024752f);
|
Vector2 fromPlane = new(-2.31678f, -5.024752f);
|
||||||
Vector2 toPlane = new Vector2(-2.599937f, -6.134028f);
|
Vector2 toPlane = new(-2.599937f, -6.134028f);
|
||||||
|
|
||||||
List<HexCell> cellList = grid.GetCellsForLine(fromPlane, toPlane);
|
List<HexCell> cellList = grid.GetCellsForLine(fromPlane, toPlane);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
using GoDotTest;
|
using GoDotTest;
|
||||||
|
|
||||||
public class NavigationComponentTests : TestClass
|
public class NavigationComponentTests : TestClass {
|
||||||
{
|
|
||||||
private readonly Node _testScene;
|
private readonly Node _testScene;
|
||||||
|
|
||||||
private readonly PackedScene _WorldScene = GD.Load<PackedScene>("res://scenes/World.tscn");
|
private readonly PackedScene _WorldScene = GD.Load<PackedScene>("res://scenes/World.tscn");
|
||||||
|
@ -10,14 +9,12 @@ public class NavigationComponentTests : TestClass
|
||||||
private NavigationComponent _navigationComponent;
|
private NavigationComponent _navigationComponent;
|
||||||
private World _world;
|
private World _world;
|
||||||
|
|
||||||
public NavigationComponentTests(Node testScene) : base(testScene)
|
public NavigationComponentTests(Node testScene) : base(testScene) {
|
||||||
{
|
|
||||||
_testScene = testScene;
|
_testScene = testScene;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
public void Setup()
|
public void Setup() {
|
||||||
{
|
|
||||||
_world = (World)_WorldScene.Instance();
|
_world = (World)_WorldScene.Instance();
|
||||||
_world.HexGrid = new HexGrid();
|
_world.HexGrid = new HexGrid();
|
||||||
_testScene.AddChild(_world);
|
_testScene.AddChild(_world);
|
||||||
|
|
|
@ -6,41 +6,35 @@ using Xunit;
|
||||||
|
|
||||||
namespace GodotComponentTest.tests;
|
namespace GodotComponentTest.tests;
|
||||||
|
|
||||||
public class Plane2DTests : TestClass
|
public class Plane2DTests : TestClass {
|
||||||
{
|
public Plane2DTests(Node testScene) : base(testScene) { }
|
||||||
public Plane2DTests(Node testScene) : base(testScene)
|
|
||||||
{
|
[Test]
|
||||||
|
public void Plane2DDistSimple() {
|
||||||
|
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(0, -1));
|
||||||
|
|
||||||
|
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 0)) - 1) < float.Epsilon);
|
||||||
|
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 1))) < float.Epsilon);
|
||||||
|
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 2)) + 1) < float.Epsilon);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Plane2DDistSimple()
|
public void Plane2DDistAngled() {
|
||||||
{
|
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(0, -1));
|
|
||||||
|
|
||||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 0)) - 1) < Single.Epsilon);
|
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 1))) < float.Epsilon);
|
||||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 1))) < Single.Epsilon);
|
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 0)) - MathF.Sqrt(2) / 2) < float.Epsilon);
|
||||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 2)) + 1) < Single.Epsilon);
|
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(-1, 0))) < float.Epsilon);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Plane2DDistAngled()
|
public void Plane2DDistLineSegment() {
|
||||||
{
|
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
|
||||||
|
|
||||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 1))) < Single.Epsilon);
|
|
||||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(0, 0)) - MathF.Sqrt(2) / 2) < Single.Epsilon);
|
|
||||||
Assert.True(Mathf.Abs(plane2D.DistanceToPoint(new Vector2(-1, 0))) < Single.Epsilon);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void Plane2DDistLineSegment()
|
|
||||||
{
|
|
||||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
|
||||||
|
|
||||||
Assert.True(
|
Assert.True(
|
||||||
Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(-1, 0)) - 1) < Single.Epsilon);
|
Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(-1, 0)) - 1) < float.Epsilon);
|
||||||
Assert.True(Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(0, 1)) - 1) <
|
Assert.True(Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(0, 1)) - 1) <
|
||||||
Single.Epsilon);
|
float.Epsilon);
|
||||||
Assert.True(Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(1, -1).Normalized()) +
|
Assert.True(Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(1, -1).Normalized()) +
|
||||||
MathF.Sqrt(2) / 2) < Plane2D.DistancePrecision);
|
MathF.Sqrt(2) / 2) < Plane2D.DistancePrecision);
|
||||||
Assert.True(Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(-1, 1).Normalized()) -
|
Assert.True(Mathf.Abs(plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(-1, 1).Normalized()) -
|
||||||
|
@ -48,22 +42,20 @@ public class Plane2DTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Plane2DTestIsParallel()
|
public void Plane2DTestIsParallel() {
|
||||||
{
|
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
|
||||||
|
|
||||||
Assert.True(plane2D.IsParallelToDir(new Vector2(1, 1.00001f).Normalized()));
|
Assert.True(plane2D.IsParallelToDir(new Vector2(1, 1.00001f).Normalized()));
|
||||||
Assert.True(plane2D.IsParallelToDir(new Vector2(1, 0.99999f).Normalized()));
|
Assert.True(plane2D.IsParallelToDir(new Vector2(1, 0.99999f).Normalized()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Plane2DDistLineSegmentParallel()
|
public void Plane2DDistLineSegmentParallel() {
|
||||||
{
|
Plane2D plane2D = new(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
||||||
Plane2D plane2D = new Plane2D(new Vector2(0, 1), new Vector2(1, -1).Normalized());
|
|
||||||
|
|
||||||
Assert.Equal(Single.PositiveInfinity,
|
Assert.Equal(float.PositiveInfinity,
|
||||||
plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(1, 1.00001f).Normalized()));
|
plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(1, 1.00001f).Normalized()));
|
||||||
Assert.Equal(Single.NegativeInfinity,
|
Assert.Equal(float.NegativeInfinity,
|
||||||
plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(1, 0.99999f).Normalized()));
|
plane2D.DistanceToLineSegment(new Vector2(0, 0), new Vector2(1, 0.99999f).Normalized()));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,37 +1,29 @@
|
||||||
using System;
|
|
||||||
using Godot;
|
using Godot;
|
||||||
using GodotComponentTest.utils;
|
|
||||||
using GoDotTest;
|
using GoDotTest;
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace GodotComponentTest.tests;
|
namespace GodotComponentTest.tests;
|
||||||
|
|
||||||
public class StreamContainerTests : TestClass
|
public class StreamContainerTests : TestClass {
|
||||||
{
|
private readonly Node _testScene;
|
||||||
private Node _testScene = null;
|
|
||||||
private TileWorld _tileWorld;
|
private TileWorld _tileWorld;
|
||||||
private StreamContainer _streamContainer;
|
private StreamContainer _streamContainer;
|
||||||
|
|
||||||
private PackedScene _tileWorldScene = GD.Load<PackedScene>("res://scenes/TileWorld.tscn");
|
private readonly PackedScene _tileWorldScene = GD.Load<PackedScene>("res://scenes/TileWorld.tscn");
|
||||||
private PackedScene _streamContainerScene = GD.Load<PackedScene>("res://scenes/StreamContainer.tscn");
|
private readonly PackedScene _streamContainerScene = GD.Load<PackedScene>("res://scenes/StreamContainer.tscn");
|
||||||
|
|
||||||
public StreamContainerTests(Node testScene) : base(testScene)
|
public StreamContainerTests(Node testScene) : base(testScene) {
|
||||||
{
|
|
||||||
_testScene = testScene;
|
_testScene = testScene;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
public void Setup()
|
public void Setup() {
|
||||||
{
|
_tileWorld = (TileWorld)_tileWorldScene.Instance();
|
||||||
_tileWorld = (TileWorld) _tileWorldScene.Instance();
|
|
||||||
_tileWorld.HexGrid = new HexGrid();
|
_tileWorld.HexGrid = new HexGrid();
|
||||||
_testScene.AddChild(_tileWorld);
|
_testScene.AddChild(_tileWorld);
|
||||||
_streamContainer = (StreamContainer) _streamContainerScene.Instance();
|
_streamContainer = (StreamContainer)_streamContainerScene.Instance();
|
||||||
|
|
||||||
foreach (Node node in _testScene.GetChildren())
|
foreach (Node node in _testScene.GetChildren()) {
|
||||||
{
|
if (node is TileWorld) {
|
||||||
if (node is TileWorld)
|
|
||||||
{
|
|
||||||
_streamContainer.World = node.GetPath();
|
_streamContainer.World = node.GetPath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,10 +32,8 @@ public class StreamContainerTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cleanup]
|
[Cleanup]
|
||||||
public void Cleanup()
|
public void Cleanup() {
|
||||||
{
|
foreach (Node node in _testScene.GetChildren()) {
|
||||||
foreach (Node node in _testScene.GetChildren())
|
|
||||||
{
|
|
||||||
node.QueueFree();
|
node.QueueFree();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,8 +42,7 @@ public class StreamContainerTests : TestClass
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Plane2DDistSimple()
|
public void Plane2DDistSimple() {
|
||||||
{
|
|
||||||
// _streamContainer.UpdateRects(new Vector2(0, 0));
|
// _streamContainer.UpdateRects(new Vector2(0, 0));
|
||||||
// _streamContainer.UpdateRects(new Vector2(1, 0));
|
// _streamContainer.UpdateRects(new Vector2(1, 0));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ using System.Reflection;
|
||||||
using Godot;
|
using Godot;
|
||||||
using GoDotTest;
|
using GoDotTest;
|
||||||
|
|
||||||
public class Tests : Control
|
public class Tests : Control {
|
||||||
{
|
public override async void _Ready() {
|
||||||
public override async void _Ready()
|
await GoTest.RunTests(Assembly.GetExecutingAssembly(), this);
|
||||||
=> await GoTest.RunTests(Assembly.GetExecutingAssembly(), this);
|
}
|
||||||
}
|
}
|
|
@ -1,21 +1,26 @@
|
||||||
extends VBoxContainer
|
extends CenterContainer
|
||||||
|
|
||||||
var world_size_label = null
|
onready var SeedLineEdit: LineEdit
|
||||||
var world_size_slider = null
|
onready var ChunkSizeSpinBox: SpinBox
|
||||||
|
#onready var GameScene: PackedScene = preload ("res://scenes/Game.tscn")
|
||||||
|
|
||||||
onready var WorldTextureRect = $WorldTextureRect
|
|
||||||
onready var HeightTextureRect = $HeightTextureRect
|
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
|
||||||
func _ready():
|
func _ready():
|
||||||
world_size_label = find_node("WorldSizeLabel")
|
SeedLineEdit = find_node("SeedLineEdit")
|
||||||
world_size_slider = find_node("WorldSizeSlider");
|
assert(SeedLineEdit)
|
||||||
|
|
||||||
world_size_slider.value = 4
|
ChunkSizeSpinBox = find_node("ChunkSizeSpinBox")
|
||||||
|
assert(ChunkSizeSpinBox)
|
||||||
|
|
||||||
func _on_HSlider_value_changed(value):
|
|
||||||
world_size_label.text = str(value)
|
|
||||||
|
|
||||||
func _on_ShowTexturesCheckButton_toggled(button_pressed):
|
func _on_RefreshSeedButton_pressed():
|
||||||
WorldTextureRect.visible = button_pressed
|
var rng = RandomNumberGenerator.new()
|
||||||
HeightTextureRect.visible = button_pressed
|
rng.seed = Time.get_ticks_msec()
|
||||||
|
SeedLineEdit.text = str(rng.randi())
|
||||||
|
|
||||||
|
|
||||||
|
func _on_GenerateButton_pressed():
|
||||||
|
# var game_scene_instance = GameScene.instance()
|
||||||
|
|
||||||
|
self.visible = false
|
||||||
|
# get_tree().get_root().add_child(game_scene_instance)
|
||||||
|
# game_scene_instance.StartNewGame(int(SeedLineEdit.text), int(ChunkSizeSpinBox.value))
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
[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"]
|
|
@ -0,0 +1,21 @@
|
||||||
|
extends VBoxContainer
|
||||||
|
|
||||||
|
var world_size_label = null
|
||||||
|
var world_size_slider = null
|
||||||
|
|
||||||
|
onready var WorldTextureRect = $WorldTextureRect
|
||||||
|
onready var HeightTextureRect = $HeightTextureRect
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready():
|
||||||
|
world_size_label = find_node("WorldSizeLabel")
|
||||||
|
world_size_slider = find_node("WorldSizeSlider");
|
||||||
|
|
||||||
|
world_size_slider.value = 4
|
||||||
|
|
||||||
|
func _on_HSlider_value_changed(value):
|
||||||
|
world_size_label.text = str(value)
|
||||||
|
|
||||||
|
func _on_ShowTexturesCheckButton_toggled(button_pressed):
|
||||||
|
WorldTextureRect.visible = button_pressed
|
||||||
|
HeightTextureRect.visible = button_pressed
|
|
@ -0,0 +1,5 @@
|
||||||
|
[gd_resource type="ButtonGroup" format=2]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
resource_local_to_scene = false
|
||||||
|
resource_name = "ActionButtonGroup"
|
|
@ -0,0 +1,11 @@
|
||||||
|
[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,18 +1,15 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace GodotComponentTest.utils;
|
namespace GodotComponentTest.utils;
|
||||||
|
|
||||||
public class DebugGeometry : Spatial
|
public class DebugGeometry : Spatial {
|
||||||
{
|
|
||||||
private ImmediateGeometry _immediateGeometry;
|
private ImmediateGeometry _immediateGeometry;
|
||||||
|
|
||||||
private List<Transform> _transformStack;
|
private List<Transform> _transformStack;
|
||||||
private Transform _currentTransform = Transform.Identity;
|
private Transform _currentTransform = Transform.Identity;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready() {
|
||||||
{
|
|
||||||
base._Ready();
|
base._Ready();
|
||||||
|
|
||||||
_immediateGeometry = (ImmediateGeometry)FindNode("ImmediateGeometry");
|
_immediateGeometry = (ImmediateGeometry)FindNode("ImmediateGeometry");
|
||||||
|
@ -20,57 +17,47 @@ public class DebugGeometry : Spatial
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear() {
|
||||||
{
|
|
||||||
_immediateGeometry.Clear();
|
_immediateGeometry.Clear();
|
||||||
_transformStack = new List<Transform>();
|
_transformStack = new List<Transform>();
|
||||||
_transformStack.Add(Transform.Identity);
|
_transformStack.Add(Transform.Identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PushTransform(Transform transform)
|
public void PushTransform(Transform transform) {
|
||||||
{
|
|
||||||
_transformStack.Add(transform);
|
_transformStack.Add(transform);
|
||||||
_currentTransform = transform;
|
_currentTransform = transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PushTranslated(Vector3 offset)
|
public void PushTranslated(Vector3 offset) {
|
||||||
{
|
|
||||||
PushTransform(_currentTransform.Translated(offset));
|
PushTransform(_currentTransform.Translated(offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PopTransform()
|
public void PopTransform() {
|
||||||
{
|
|
||||||
_transformStack.RemoveAt(_transformStack.Count - 1);
|
_transformStack.RemoveAt(_transformStack.Count - 1);
|
||||||
_currentTransform = PeekTransform();
|
_currentTransform = PeekTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Transform PeekTransform()
|
public Transform PeekTransform() {
|
||||||
{
|
|
||||||
return _transformStack[_transformStack.Count - 1];
|
return _transformStack[_transformStack.Count - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Begin(Mesh.PrimitiveType primitive, Texture texture = null)
|
public void Begin(Mesh.PrimitiveType primitive, Texture texture = null) {
|
||||||
{
|
|
||||||
_immediateGeometry.Begin(primitive, texture);
|
_immediateGeometry.Begin(primitive, texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void End()
|
public void End() {
|
||||||
{
|
|
||||||
_immediateGeometry.End();
|
_immediateGeometry.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddVertex(Vector3 vertex)
|
public void AddVertex(Vector3 vertex) {
|
||||||
{
|
|
||||||
_immediateGeometry.AddVertex(_currentTransform.Xform(vertex));
|
_immediateGeometry.AddVertex(_currentTransform.Xform(vertex));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetColor(Color color)
|
public void SetColor(Color color) {
|
||||||
{
|
|
||||||
_immediateGeometry.SetColor(color);
|
_immediateGeometry.SetColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddBox(Vector3 extents)
|
public void AddBox(Vector3 extents) {
|
||||||
{
|
|
||||||
Transform currentTransform = PeekTransform();
|
Transform currentTransform = PeekTransform();
|
||||||
// bottom square
|
// bottom square
|
||||||
AddVertex(new Vector3(extents.x * -0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
AddVertex(new Vector3(extents.x * -0.5f, extents.y * -0.5f, extents.z * -0.5f));
|
||||||
|
|
|
@ -5,43 +5,39 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace Namespace
|
namespace Namespace;
|
||||||
{
|
|
||||||
using UnderlyingType = UInt64;
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
using UnderlyingType = UInt64;
|
||||||
public class ExportFlagsEnumAttribute : ExportAttribute
|
|
||||||
{
|
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||||
|
public class ExportFlagsEnumAttribute : ExportAttribute {
|
||||||
public ExportFlagsEnumAttribute(Type enumType)
|
public ExportFlagsEnumAttribute(Type enumType)
|
||||||
: base(PropertyHint.Flags, GetFlagsEnumHintString(enumType))
|
: base(PropertyHint.Flags, GetFlagsEnumHintString(enumType)) { }
|
||||||
{ }
|
|
||||||
|
|
||||||
private static string GetFlagsEnumHintString(Type enumType)
|
private static string GetFlagsEnumHintString(Type enumType) {
|
||||||
{
|
Dictionary<UnderlyingType, List<string>> flagNamesByFlag = new();
|
||||||
Dictionary<UnderlyingType, List<string>> flagNamesByFlag = new Dictionary<UnderlyingType, List<string>>();
|
UnderlyingType flag = 1;
|
||||||
UnderlyingType flag = (UnderlyingType)1;
|
foreach (string name in Enum.GetNames(enumType)) {
|
||||||
foreach (string name in Enum.GetNames(enumType))
|
UnderlyingType value =
|
||||||
{
|
(UnderlyingType)Convert.ChangeType(Enum.Parse(enumType, name), typeof(UnderlyingType));
|
||||||
UnderlyingType value = (UnderlyingType)Convert.ChangeType(Enum.Parse(enumType, name), typeof(UnderlyingType));
|
while (value > flag) {
|
||||||
while (value > flag)
|
if (!flagNamesByFlag.ContainsKey(flag)) {
|
||||||
{
|
|
||||||
if (!flagNamesByFlag.ContainsKey(flag))
|
|
||||||
{
|
|
||||||
flagNamesByFlag.Add(flag, new List<string>());
|
flagNamesByFlag.Add(flag, new List<string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
flag <<= 1;
|
flag <<= 1;
|
||||||
}
|
}
|
||||||
if (value == flag)
|
|
||||||
{
|
if (value == flag) {
|
||||||
if (!flagNamesByFlag.TryGetValue(flag, out List<string> names))
|
if (!flagNamesByFlag.TryGetValue(flag, out List<string> names)) {
|
||||||
{
|
|
||||||
names = new List<string>();
|
names = new List<string>();
|
||||||
flagNamesByFlag.Add(flag, names);
|
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,11 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public class NavigationPoint
|
public class NavigationPoint {
|
||||||
{
|
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum NavigationFlags
|
public enum NavigationFlags {
|
||||||
{
|
|
||||||
Position = 1,
|
Position = 1,
|
||||||
Orientation = 2
|
Orientation = 2
|
||||||
}
|
}
|
||||||
|
@ -16,20 +14,17 @@ public class NavigationPoint
|
||||||
|
|
||||||
public Vector3 WorldPosition = Vector3.Zero;
|
public Vector3 WorldPosition = Vector3.Zero;
|
||||||
|
|
||||||
public NavigationPoint(Vector3 worldPosition)
|
public NavigationPoint(Vector3 worldPosition) {
|
||||||
{
|
|
||||||
WorldPosition = worldPosition;
|
WorldPosition = worldPosition;
|
||||||
Flags = NavigationFlags.Position;
|
Flags = NavigationFlags.Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NavigationPoint(Quat worldOrientation)
|
public NavigationPoint(Quat worldOrientation) {
|
||||||
{
|
|
||||||
WorldOrientation = worldOrientation;
|
WorldOrientation = worldOrientation;
|
||||||
Flags = NavigationFlags.Orientation;
|
Flags = NavigationFlags.Orientation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NavigationPoint(Transform worldTransform)
|
public NavigationPoint(Transform worldTransform) {
|
||||||
{
|
|
||||||
WorldPosition = worldTransform.origin;
|
WorldPosition = worldTransform.origin;
|
||||||
WorldOrientation = worldTransform.basis.Quat();
|
WorldOrientation = worldTransform.basis.Quat();
|
||||||
WorldAngle = Globals.CalcPlaneAngle(worldTransform);
|
WorldAngle = Globals.CalcPlaneAngle(worldTransform);
|
||||||
|
@ -37,31 +32,25 @@ public class NavigationPoint
|
||||||
Flags = NavigationFlags.Position | NavigationFlags.Orientation;
|
Flags = NavigationFlags.Position | NavigationFlags.Orientation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsReached(Transform worldTransform)
|
public bool IsReached(Transform worldTransform) {
|
||||||
{
|
bool goalReached = false;
|
||||||
var goalReached = false;
|
Vector2 positionError = new Vector2(WorldPosition.x - worldTransform.origin.x,
|
||||||
var positionError = new Vector2(WorldPosition.x - worldTransform.origin.x,
|
|
||||||
WorldPosition.z - worldTransform.origin.z);
|
WorldPosition.z - worldTransform.origin.z);
|
||||||
var positionErrorSquared = positionError.LengthSquared();
|
float positionErrorSquared = positionError.LengthSquared();
|
||||||
worldTransform.basis.Quat();
|
worldTransform.basis.Quat();
|
||||||
var orientationError = Mathf.Abs(worldTransform.basis.Quat().AngleTo(WorldOrientation));
|
float orientationError = Mathf.Abs(worldTransform.basis.Quat().AngleTo(WorldOrientation));
|
||||||
var angleError = Mathf.Abs(Globals.CalcPlaneAngle(worldTransform) - WorldAngle);
|
float angleError = Mathf.Abs(Globals.CalcPlaneAngle(worldTransform) - WorldAngle);
|
||||||
|
|
||||||
if (Flags.HasFlag(NavigationFlags.Position)
|
if (Flags.HasFlag(NavigationFlags.Position)
|
||||||
&& Flags.HasFlag(NavigationFlags.Orientation)
|
&& Flags.HasFlag(NavigationFlags.Orientation)
|
||||||
&& positionErrorSquared < Globals.EpsPositionSquared
|
&& positionErrorSquared < Globals.EpsPositionSquared
|
||||||
&& angleError < Globals.EpsRadians)
|
&& angleError < Globals.EpsRadians) {
|
||||||
{
|
|
||||||
goalReached = true;
|
goalReached = true;
|
||||||
}
|
} else if (Flags == NavigationFlags.Position &&
|
||||||
else if (Flags == NavigationFlags.Position &&
|
positionErrorSquared < Globals.EpsPositionSquared) {
|
||||||
positionErrorSquared < Globals.EpsPositionSquared)
|
|
||||||
{
|
|
||||||
goalReached = true;
|
goalReached = true;
|
||||||
}
|
} else if (Flags == NavigationFlags.Orientation &&
|
||||||
else if (Flags == NavigationFlags.Orientation &&
|
angleError < Globals.EpsRadians) {
|
||||||
angleError < Globals.EpsRadians)
|
|
||||||
{
|
|
||||||
goalReached = true;
|
goalReached = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,47 +1,39 @@
|
||||||
using System;
|
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace GodotComponentTest.utils;
|
namespace GodotComponentTest.utils;
|
||||||
|
|
||||||
public class Plane2D
|
public class Plane2D {
|
||||||
{
|
|
||||||
public static readonly float DistancePrecision = 1.0e-5f;
|
public static readonly float DistancePrecision = 1.0e-5f;
|
||||||
|
|
||||||
private Vector2 _planePoint;
|
private Vector2 _planePoint;
|
||||||
public Vector2 Normal;
|
public Vector2 Normal;
|
||||||
|
|
||||||
public Plane2D(Vector2 planePoint, Vector2 normal)
|
public Plane2D(Vector2 planePoint, Vector2 normal) {
|
||||||
{
|
|
||||||
_planePoint = planePoint;
|
_planePoint = planePoint;
|
||||||
Normal = normal;
|
Normal = normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float DistanceToPoint(Vector2 point)
|
public float DistanceToPoint(Vector2 point) {
|
||||||
{
|
|
||||||
return (point - _planePoint).Dot(Normal);
|
return (point - _planePoint).Dot(Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsParallelToDir(Vector2 dir)
|
public bool IsParallelToDir(Vector2 dir) {
|
||||||
{
|
|
||||||
float normalDotDir = Normal.Dot(dir);
|
float normalDotDir = Normal.Dot(dir);
|
||||||
|
|
||||||
return (Mathf.Abs(normalDotDir) <= Plane2D.DistancePrecision);
|
return Mathf.Abs(normalDotDir) <= DistancePrecision;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float DistanceToLineSegment(Vector2 point, Vector2 dir)
|
public float DistanceToLineSegment(Vector2 point, Vector2 dir) {
|
||||||
{
|
|
||||||
float normalDotDir = Normal.Dot(dir);
|
float normalDotDir = Normal.Dot(dir);
|
||||||
|
|
||||||
if (Mathf.Abs(normalDotDir) > Plane2D.DistancePrecision)
|
if (Mathf.Abs(normalDotDir) > DistancePrecision) {
|
||||||
{
|
|
||||||
return (_planePoint.Dot(Normal) - point.Dot(Normal)) / normalDotDir;
|
return (_planePoint.Dot(Normal) - point.Dot(Normal)) / normalDotDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalDotDir < 0)
|
if (normalDotDir < 0) {
|
||||||
{
|
return float.PositiveInfinity;
|
||||||
return Single.PositiveInfinity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Single.NegativeInfinity;
|
return float.NegativeInfinity;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,23 +1,19 @@
|
||||||
// Based on: allenchou.net/2015/04/game-math-precise-control-over-numeric-springing/
|
// Based on: allenchou.net/2015/04/game-math-precise-control-over-numeric-springing/
|
||||||
|
|
||||||
using Godot;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
public class SpringDamper
|
public class SpringDamper {
|
||||||
{
|
|
||||||
public float omega = 1;
|
public float omega = 1;
|
||||||
public float zeta = 1;
|
public float zeta = 1;
|
||||||
|
|
||||||
public SpringDamper(float osc_freq = 1.0f, float osc_red = 0.1f, float osc_red_h = 1.0f)
|
public SpringDamper(float osc_freq = 1.0f, float osc_red = 0.1f, float osc_red_h = 1.0f) {
|
||||||
{
|
|
||||||
Debug.Assert(osc_red > 0.001 && osc_red < 0.999);
|
Debug.Assert(osc_red > 0.001 && osc_red < 0.999);
|
||||||
omega = osc_freq * 2 * Mathf.Pi;
|
omega = osc_freq * 2 * Mathf.Pi;
|
||||||
zeta = Mathf.Log(1.0f - osc_red) / (-omega * osc_red_h);
|
zeta = Mathf.Log(1.0f - osc_red) / (-omega * osc_red_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
public (float, float) Calc(float x, float v, float xt, float h)
|
public (float, float) Calc(float x, float v, float xt, float h) {
|
||||||
{
|
|
||||||
float f = 1 + 2 * h * zeta * omega;
|
float f = 1 + 2 * h * zeta * omega;
|
||||||
float oo = omega * omega;
|
float oo = omega * omega;
|
||||||
float hoo = oo * h;
|
float hoo = oo * h;
|
||||||
|
@ -30,8 +26,7 @@ public class SpringDamper
|
||||||
return (det_x * det_inv, det_v * det_inv);
|
return (det_x * det_inv, det_v * det_inv);
|
||||||
}
|
}
|
||||||
|
|
||||||
public (Vector3, Vector3) Calc(Vector3 x, Vector3 v, Vector3 xt, float h)
|
public (Vector3, Vector3) Calc(Vector3 x, Vector3 v, Vector3 xt, float h) {
|
||||||
{
|
|
||||||
float f = 1 + 2 * h * zeta * omega;
|
float f = 1 + 2 * h * zeta * omega;
|
||||||
float oo = omega * omega;
|
float oo = omega * omega;
|
||||||
float hoo = oo * h;
|
float hoo = oo * h;
|
||||||
|
@ -44,27 +39,24 @@ public class SpringDamper
|
||||||
return (det_x * det_inv, det_v * det_inv);
|
return (det_x * det_inv, det_v * det_inv);
|
||||||
}
|
}
|
||||||
|
|
||||||
public (Vector3, Vector3) CalcClampedSpeed(Vector3 x, Vector3 v, Vector3 xt, float h, float speedMax)
|
public (Vector3, Vector3) CalcClampedSpeed(Vector3 x, Vector3 v, Vector3 xt, float h, float speedMax) {
|
||||||
{
|
(Vector3, Vector3) defaultResult = Calc(x, v, xt, h);
|
||||||
var defaultResult = Calc(x, v, xt, h);
|
|
||||||
|
|
||||||
Vector3 x_new = defaultResult.Item1;
|
Vector3 x_new = defaultResult.Item1;
|
||||||
Vector3 vel_new = (x_new - x) / h;
|
Vector3 vel_new = (x_new - x) / h;
|
||||||
float speed_new = vel_new.Length();
|
float speed_new = vel_new.Length();
|
||||||
|
|
||||||
if (speed_new > speedMax)
|
if (speed_new > speedMax) {
|
||||||
{
|
vel_new = vel_new / speed_new * speedMax;
|
||||||
vel_new = (vel_new / speed_new) * speedMax;
|
|
||||||
x_new = x + vel_new * h;
|
x_new = x + vel_new * h;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (x_new, vel_new);
|
return (x_new, vel_new);
|
||||||
}
|
}
|
||||||
|
|
||||||
public (Vector3, Vector3) CalcClampedSpeedXZ(Vector3 x, Vector3 v, Vector3 xt, float h, float speedMax)
|
public (Vector3, Vector3) CalcClampedSpeedXZ(Vector3 x, Vector3 v, Vector3 xt, float h, float speedMax) {
|
||||||
{
|
(float, float) result_x = Calc(x.x, v.x, xt.x, h);
|
||||||
var result_x = Calc(x.x, v.x, xt.x, h);
|
(float, float) result_z = Calc(x.z, v.z, xt.z, h);
|
||||||
var result_z = Calc(x.z, v.z, xt.z, h);
|
|
||||||
|
|
||||||
Vector3 x_new = x;
|
Vector3 x_new = x;
|
||||||
Vector3 v_new = v;
|
Vector3 v_new = v;
|
||||||
|
@ -75,16 +67,15 @@ public class SpringDamper
|
||||||
x_new.z = result_z.Item1;
|
x_new.z = result_z.Item1;
|
||||||
v_new.z = result_z.Item2;
|
v_new.z = result_z.Item2;
|
||||||
|
|
||||||
Vector3 result_v_xz = new Vector3(
|
Vector3 result_v_xz = new(
|
||||||
(result_x.Item1 - x.x) / h,
|
(result_x.Item1 - x.x) / h,
|
||||||
0,
|
0,
|
||||||
(result_z.Item1 - x.z) / h);
|
(result_z.Item1 - x.z) / h);
|
||||||
|
|
||||||
float speed_new = result_v_xz.Length();
|
float speed_new = result_v_xz.Length();
|
||||||
|
|
||||||
if (speed_new > speedMax)
|
if (speed_new > speedMax) {
|
||||||
{
|
result_v_xz = result_v_xz / speed_new * speedMax;
|
||||||
result_v_xz = (result_v_xz) / speed_new * speedMax;
|
|
||||||
x_new.x = x.x + result_v_xz.x * h;
|
x_new.x = x.x + result_v_xz.x * h;
|
||||||
x_new.z = x.z + result_v_xz.z * h;
|
x_new.z = x.z + result_v_xz.z * h;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue