Also populate chunks with entities when chunks are being generated.
parent
928ddd3937
commit
4c0a2e7714
142
HexGrid.cs
142
HexGrid.cs
|
@ -6,31 +6,33 @@ using AxialCoordDirectionPair = System.Tuple<Godot.Vector2, Godot.Vector3>;
|
||||||
|
|
||||||
public class HexGrid : Resource
|
public class HexGrid : Resource
|
||||||
{
|
{
|
||||||
private Vector2 _baseHexSize = new(1, Mathf.Sqrt(3) / 2);
|
private readonly Vector2 _baseHexSize = new(1, Mathf.Sqrt(3) / 2);
|
||||||
private Vector2 _hexSize = new(1, Mathf.Sqrt(3) / 2);
|
private Rect2 _boundsAxialCoords;
|
||||||
private Vector2 _hexScale = new(1, 1);
|
private Vector2 _hexScale = new(1, 1);
|
||||||
|
private Vector2 _hexSize = new(1, Mathf.Sqrt(3) / 2);
|
||||||
private Transform2D _hexTransform;
|
private Transform2D _hexTransform;
|
||||||
private Transform2D _hexTransformInv;
|
private Transform2D _hexTransformInv;
|
||||||
private HexCell _minCoords = new();
|
|
||||||
private HexCell _maxCoords = new();
|
private HexCell _maxCoords = new();
|
||||||
private Rect2 _boundsAxialCoords;
|
private HexCell _minCoords = new();
|
||||||
|
|
||||||
|
public Dictionary<(Vector2, Vector3), float> Barriers = new();
|
||||||
|
public int FindPathCheckedCellCount;
|
||||||
|
|
||||||
public Dictionary<Vector2, float> Obstacles = new();
|
public Dictionary<Vector2, float> Obstacles = new();
|
||||||
|
|
||||||
public Dictionary<(Vector2, Vector3), float> Barriers = new();
|
|
||||||
|
|
||||||
|
|
||||||
public float PathCostDefault = 1;
|
public float PathCostDefault = 1;
|
||||||
public int FindPathCheckedCellCount;
|
|
||||||
|
|
||||||
public Vector2 HexSize
|
public HexGrid()
|
||||||
{
|
{
|
||||||
get { return _hexSize; }
|
HexScale = new Vector2(1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vector2 HexSize => _hexSize;
|
||||||
|
|
||||||
public Vector2 HexScale
|
public Vector2 HexScale
|
||||||
{
|
{
|
||||||
get { return _hexScale; }
|
get => _hexScale;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_hexScale = value;
|
_hexScale = value;
|
||||||
|
@ -45,11 +47,6 @@ public class HexGrid : Resource
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public HexGrid()
|
|
||||||
{
|
|
||||||
HexScale = new Vector2(1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 GetHexCenter(HexCell cell)
|
public Vector2 GetHexCenter(HexCell cell)
|
||||||
{
|
{
|
||||||
return _hexTransform * cell.AxialCoords;
|
return _hexTransform * cell.AxialCoords;
|
||||||
|
@ -57,21 +54,29 @@ public class HexGrid : Resource
|
||||||
|
|
||||||
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)
|
||||||
|
{
|
||||||
|
var cell = new HexCell();
|
||||||
|
cell.OffsetCoords = offsetCoord;
|
||||||
|
var hexCenter = GetHexCenter(cell);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,12 +90,12 @@ public class HexGrid : Resource
|
||||||
_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));
|
||||||
}
|
}
|
||||||
|
@ -123,10 +128,7 @@ public class HexGrid : Resource
|
||||||
|
|
||||||
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)
|
||||||
|
@ -136,10 +138,7 @@ public class HexGrid : Resource
|
||||||
|
|
||||||
public float GetHexCost(Vector2 axialCoords)
|
public float GetHexCost(Vector2 axialCoords)
|
||||||
{
|
{
|
||||||
if (!_boundsAxialCoords.HasPoint(axialCoords))
|
if (!_boundsAxialCoords.HasPoint(axialCoords)) return 0;
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float value;
|
float value;
|
||||||
return Obstacles.TryGetValue(axialCoords, out value) ? value : PathCostDefault;
|
return Obstacles.TryGetValue(axialCoords, out value) ? value : PathCostDefault;
|
||||||
|
@ -147,29 +146,20 @@ public class HexGrid : Resource
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
float cost = GetHexCost(axialCoords);
|
var cost = GetHexCost(axialCoords);
|
||||||
if (cost == 0)
|
if (cost == 0) return 0;
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cost = GetHexCost(targetCell.AxialCoords);
|
cost = GetHexCost(targetCell.AxialCoords);
|
||||||
if (cost == 0)
|
if (cost == 0) return 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)
|
if (barrierCost == 0) return 0;
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cost += barrierCost;
|
cost += barrierCost;
|
||||||
}
|
}
|
||||||
|
@ -177,10 +167,7 @@ public class HexGrid : Resource
|
||||||
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)
|
if (barrierCost == 0) return 0;
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cost += barrierCost;
|
cost += barrierCost;
|
||||||
}
|
}
|
||||||
|
@ -193,30 +180,28 @@ public class HexGrid : Resource
|
||||||
{
|
{
|
||||||
if (GetHexCost(toCell) == 0)
|
if (GetHexCost(toCell) == 0)
|
||||||
{
|
{
|
||||||
HexCell[] line = fromCell.LineTo(toCell);
|
var line = fromCell.LineTo(toCell);
|
||||||
|
|
||||||
foreach (int i in Enumerable.Range(1, line.Length))
|
foreach (var 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;
|
||||||
|
|
||||||
SimplePriorityQueue<Vector2, float> frontier = new SimplePriorityQueue<Vector2, float>();
|
var frontier = new SimplePriorityQueue<Vector2, float>();
|
||||||
frontier.Enqueue(startHex.AxialCoords, 0);
|
frontier.Enqueue(startHex.AxialCoords, 0);
|
||||||
Dictionary<Vector2, Vector2> cameFrom =
|
var cameFrom =
|
||||||
new Dictionary<Vector2, Vector2>();
|
new Dictionary<Vector2, Vector2>();
|
||||||
Dictionary<Vector2, float> costSoFar =
|
var costSoFar =
|
||||||
new Dictionary<Vector2, float>();
|
new Dictionary<Vector2, float>();
|
||||||
|
|
||||||
cameFrom.Add(startHex.AxialCoords, startHex.AxialCoords);
|
cameFrom.Add(startHex.AxialCoords, startHex.AxialCoords);
|
||||||
|
@ -227,20 +212,17 @@ public class HexGrid : Resource
|
||||||
while (frontier.Any())
|
while (frontier.Any())
|
||||||
{
|
{
|
||||||
FindPathCheckedCellCount++;
|
FindPathCheckedCellCount++;
|
||||||
HexCell currentHex = new HexCell(frontier.Dequeue());
|
var currentHex = new HexCell(frontier.Dequeue());
|
||||||
Vector2 currentAxial = currentHex.AxialCoords;
|
var currentAxial = currentHex.AxialCoords;
|
||||||
|
|
||||||
if (currentHex == goalHex)
|
if (currentHex == goalHex) break;
|
||||||
|
|
||||||
|
foreach (var nextHex in currentHex.GetAllAdjacent())
|
||||||
{
|
{
|
||||||
break;
|
var nextAxial = nextHex.AxialCoords;
|
||||||
}
|
var nextCost = GetMoveCost(currentAxial, new HexCell(nextAxial - currentHex.AxialCoords).CubeCoords);
|
||||||
|
|
||||||
foreach (HexCell nextHex in currentHex.GetAllAdjacent())
|
if (nextHex == goalHex && GetHexCost(nextAxial) == 0)
|
||||||
{
|
|
||||||
Vector2 nextAxial = nextHex.AxialCoords;
|
|
||||||
float nextCost = GetMoveCost(currentAxial, new HexCell(nextAxial - currentHex.AxialCoords).CubeCoords);
|
|
||||||
|
|
||||||
if ((nextHex == goalHex) && (GetHexCost(nextAxial) == 0))
|
|
||||||
{
|
{
|
||||||
// Goal ist an obstacle
|
// Goal ist an obstacle
|
||||||
cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
|
cameFrom[nextHex.AxialCoords] = currentHex.AxialCoords;
|
||||||
|
@ -248,16 +230,13 @@ public class HexGrid : Resource
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextCost == 0)
|
if (nextCost == 0) continue;
|
||||||
{
|
|
||||||
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;
|
||||||
float priority = nextCost + nextHex.DistanceTo(goalHex);
|
var 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;
|
||||||
|
@ -267,19 +246,16 @@ public class HexGrid : Resource
|
||||||
|
|
||||||
// GD.Print("Checked Cell Count: " + FindPathCheckedCellCount);
|
// GD.Print("Checked Cell Count: " + FindPathCheckedCellCount);
|
||||||
|
|
||||||
List<HexCell> result = new List<HexCell>();
|
var 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)
|
if (GetHexCost(goalAxialCoords) != 0) result.Add(goalHex);
|
||||||
{
|
|
||||||
result.Add(goalHex);
|
|
||||||
}
|
|
||||||
|
|
||||||
HexCell pathHex = goalHex;
|
var pathHex = goalHex;
|
||||||
while (pathHex != startHex)
|
while (pathHex != startHex)
|
||||||
{
|
{
|
||||||
pathHex = new HexCell(cameFrom[pathHex.AxialCoords]);
|
pathHex = new HexCell(cameFrom[pathHex.AxialCoords]);
|
||||||
|
@ -292,20 +268,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>();
|
||||||
|
|
||||||
float distance = (toPlane - fromPlane).Length();
|
var distance = (toPlane - fromPlane).Length();
|
||||||
Vector2 direction = (toPlane - fromPlane) / distance;
|
var direction = (toPlane - fromPlane) / distance;
|
||||||
|
|
||||||
Vector2 currentPointPlane = fromPlane;
|
var currentPointPlane = fromPlane;
|
||||||
HexCell currentCell = GetHexAt(currentPointPlane);
|
var currentCell = GetHexAt(currentPointPlane);
|
||||||
float currentDistance = 0;
|
float currentDistance = 0;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
result.Add(currentCell);
|
result.Add(currentCell);
|
||||||
GetHexCenter(currentCell);
|
GetHexCenter(currentCell);
|
||||||
Vector2 currentPointLocal = currentPointPlane - GetHexCenter(currentCell);
|
var currentPointLocal = currentPointPlane - GetHexCenter(currentCell);
|
||||||
|
|
||||||
int neighbourIndex;
|
int neighbourIndex;
|
||||||
float boundaryPlaneDistance;
|
float boundaryPlaneDistance;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
name="PirateGame3D"
|
name="PirateGame3D"
|
||||||
platform="Android"
|
platform="Android"
|
||||||
runnable=true
|
runnable=false
|
||||||
custom_features=""
|
custom_features=""
|
||||||
export_filter="all_resources"
|
export_filter="all_resources"
|
||||||
include_filter=""
|
include_filter=""
|
||||||
|
@ -15,7 +15,7 @@ script_encryption_key=""
|
||||||
|
|
||||||
custom_template/debug=""
|
custom_template/debug=""
|
||||||
custom_template/release=""
|
custom_template/release=""
|
||||||
custom_build/use_custom_build=true
|
custom_build/use_custom_build=false
|
||||||
custom_build/export_format=0
|
custom_build/export_format=0
|
||||||
custom_build/min_sdk=""
|
custom_build/min_sdk=""
|
||||||
custom_build/target_sdk=""
|
custom_build/target_sdk=""
|
||||||
|
|
|
@ -132,5 +132,7 @@ common/enable_pause_aware_picking=true
|
||||||
|
|
||||||
[rendering]
|
[rendering]
|
||||||
|
|
||||||
quality/shadows/filter_mode.mobile=1
|
quality/directional_shadow/size.mobile=512
|
||||||
|
quality/shadow_atlas/size.mobile=1024
|
||||||
|
quality/subsurface_scattering/quality=0
|
||||||
environment/default_environment="res://default_env.tres"
|
environment/default_environment="res://default_env.tres"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=19 format=2]
|
[gd_scene load_steps=24 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://scenes/StreamContainer.tscn" type="PackedScene" id=1]
|
[ext_resource path="res://scenes/StreamContainer.tscn" type="PackedScene" id=1]
|
||||||
[ext_resource path="res://entities/Player.tscn" type="PackedScene" id=2]
|
[ext_resource path="res://entities/Player.tscn" type="PackedScene" id=2]
|
||||||
|
@ -15,6 +15,11 @@
|
||||||
[ext_resource path="res://assets/Environment/HexTileMesh.tres" type="CylinderMesh" id=13]
|
[ext_resource path="res://assets/Environment/HexTileMesh.tres" type="CylinderMesh" id=13]
|
||||||
[ext_resource path="res://entities/Axe.tscn" type="PackedScene" id=14]
|
[ext_resource path="res://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]
|
||||||
|
[ext_resource path="res://entities/rockB.tscn" type="PackedScene" id=18]
|
||||||
|
[ext_resource path="res://entities/Tree.tscn" type="PackedScene" id=19]
|
||||||
|
[ext_resource path="res://assets/Environment/grassLarge.tscn" type="PackedScene" id=20]
|
||||||
|
|
||||||
[sub_resource type="Animation" id=25]
|
[sub_resource type="Animation" id=25]
|
||||||
resource_name = "FlashLabel"
|
resource_name = "FlashLabel"
|
||||||
|
@ -35,7 +40,9 @@ tracks/0/keys = {
|
||||||
[sub_resource type="AnimationNodeStateMachinePlayback" id=26]
|
[sub_resource type="AnimationNodeStateMachinePlayback" id=26]
|
||||||
|
|
||||||
[sub_resource type="MultiMesh" id=27]
|
[sub_resource type="MultiMesh" id=27]
|
||||||
|
color_format = 1
|
||||||
transform_format = 1
|
transform_format = 1
|
||||||
|
custom_data_format = 1
|
||||||
visible_instance_count = 0
|
visible_instance_count = 0
|
||||||
mesh = ExtResource( 13 )
|
mesh = ExtResource( 13 )
|
||||||
|
|
||||||
|
@ -351,9 +358,6 @@ script = ExtResource( 15 )
|
||||||
[node name="Player" parent="." instance=ExtResource( 2 )]
|
[node name="Player" parent="." instance=ExtResource( 2 )]
|
||||||
TileWorldNode = NodePath("../TileWorld")
|
TileWorldNode = NodePath("../TileWorld")
|
||||||
|
|
||||||
[node name="Skeleton" parent="Player/Geometry/Armature" index="0"]
|
|
||||||
bones/4/bound_children = [ ]
|
|
||||||
|
|
||||||
[node name="ToolAttachement" parent="Player/Geometry/Armature/Skeleton" index="5"]
|
[node name="ToolAttachement" parent="Player/Geometry/Armature/Skeleton" index="5"]
|
||||||
transform = Transform( 1, 8.68458e-08, -1.04308e-07, 1.74623e-07, -1, -1.30385e-07, 1.41561e-07, 1.50874e-07, -1, -0.72, 0.45, 3.28113e-08 )
|
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 )
|
||||||
|
|
||||||
|
@ -382,6 +386,26 @@ World = NodePath("..")
|
||||||
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, 0, -2.5, 0 )
|
||||||
multimesh = SubResource( 27 )
|
multimesh = SubResource( 27 )
|
||||||
|
|
||||||
|
[node name="Assets" type="Spatial" parent="World"]
|
||||||
|
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -5, 0 )
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
[node name="Rocks" type="Spatial" parent="World/Assets"]
|
||||||
|
|
||||||
|
[node name="rockA" parent="World/Assets/Rocks" instance=ExtResource( 16 )]
|
||||||
|
|
||||||
|
[node name="rockB" parent="World/Assets/Rocks" instance=ExtResource( 18 )]
|
||||||
|
|
||||||
|
[node name="rockC" parent="World/Assets/Rocks" instance=ExtResource( 17 )]
|
||||||
|
|
||||||
|
[node name="Grass" type="Spatial" parent="World/Assets"]
|
||||||
|
|
||||||
|
[node name="grassLarge" parent="World/Assets/Grass" instance=ExtResource( 20 )]
|
||||||
|
|
||||||
|
[node name="Trees" type="Spatial" parent="World/Assets"]
|
||||||
|
|
||||||
|
[node name="tree" parent="World/Assets/Trees" instance=ExtResource( 19 )]
|
||||||
|
|
||||||
[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/WorldGeneratorContainer/HBoxContainer/WorldSizeSlider" to="Generator Container/WorldGeneratorContainer" method="_on_HSlider_value_changed"]
|
||||||
[connection signal="toggled" from="Generator Container/WorldGeneratorContainer/ShowTexturesCheckButton" to="Generator Container/WorldGeneratorContainer" method="_on_ShowTexturesCheckButton_toggled"]
|
[connection signal="toggled" from="Generator Container/WorldGeneratorContainer/ShowTexturesCheckButton" to="Generator Container/WorldGeneratorContainer" method="_on_ShowTexturesCheckButton_toggled"]
|
||||||
|
|
|
@ -142,6 +142,7 @@ public class TileInstanceManager : Spatial
|
||||||
foreach (var j in Enumerable.Range(0, chunkSize))
|
foreach (var j in Enumerable.Range(0, chunkSize))
|
||||||
{
|
{
|
||||||
var tile3D = (HexTile3D)_hexTile3DScene.Instance();
|
var tile3D = (HexTile3D)_hexTile3DScene.Instance();
|
||||||
|
tile3D.Cell.OffsetCoords = new Vector2(chunkIndex * global::World.ChunkSize + new Vector2(i, j));
|
||||||
|
|
||||||
var tileTransform = Transform.Identity;
|
var tileTransform = Transform.Identity;
|
||||||
var centerPlaneCoord = HexGrid.GetHexCenterFromOffset(new Vector2(i, j));
|
var centerPlaneCoord = HexGrid.GetHexCenterFromOffset(new Vector2(i, j));
|
||||||
|
@ -181,7 +182,7 @@ public class TileInstanceManager : Spatial
|
||||||
|
|
||||||
var tileOrientation = new Basis(Vector3.Up, 90f * Mathf.Pi / 180f);
|
var tileOrientation = new Basis(Vector3.Up, 90f * Mathf.Pi / 180f);
|
||||||
|
|
||||||
GD.Print("Updating transforms for instances of chunk " + value);
|
GD.Print("Updating transforms for instances of chunk " + value + " origin: " + chunkTransform.origin);
|
||||||
|
|
||||||
foreach (var i in Enumerable.Range(0, TileInstanceIndices.Count))
|
foreach (var i in Enumerable.Range(0, TileInstanceIndices.Count))
|
||||||
{
|
{
|
||||||
|
@ -190,6 +191,7 @@ public class TileInstanceManager : Spatial
|
||||||
|
|
||||||
var tilePlaneCoord =
|
var tilePlaneCoord =
|
||||||
HexGrid.GetHexCenterFromOffset(new Vector2(column, row));
|
HexGrid.GetHexCenterFromOffset(new Vector2(column, row));
|
||||||
|
|
||||||
_multiMeshInstance.Multimesh.SetInstanceTransform(TileInstanceIndices[i],
|
_multiMeshInstance.Multimesh.SetInstanceTransform(TileInstanceIndices[i],
|
||||||
new Transform(tileOrientation,
|
new Transform(tileOrientation,
|
||||||
chunkTransform.origin + new Vector3(tilePlaneCoord.x, 0, tilePlaneCoord.y)));
|
chunkTransform.origin + new Vector3(tilePlaneCoord.x, 0, tilePlaneCoord.y)));
|
||||||
|
|
|
@ -17,16 +17,18 @@ public class World : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
public const int ChunkSize = 16;
|
public const int ChunkSize = 10;
|
||||||
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 static readonly Color LightWaterColor = new(0.05882353f, 0.05882353f, 0.8627451f);
|
||||||
|
|
||||||
private readonly List<Vector2> _addedChunkIndices = new();
|
private readonly List<Vector2> _addedChunkIndices = new();
|
||||||
private readonly Godot.Collections.Dictionary<Vector2, WorldChunk> _cachedWorldChunks;
|
private readonly Godot.Collections.Dictionary<Vector2, WorldChunk> _cachedWorldChunks;
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
// referenced scenes
|
// referenced scenes
|
||||||
|
@ -39,10 +41,13 @@ public class World : Spatial
|
||||||
|
|
||||||
// other members
|
// other members
|
||||||
private Vector2 _centerPlaneCoord;
|
private Vector2 _centerPlaneCoord;
|
||||||
|
private Array<Spatial> _grassAssets;
|
||||||
private ImageTexture _heightmapTexture;
|
private ImageTexture _heightmapTexture;
|
||||||
|
|
||||||
private OpenSimplexNoise _noiseGenerator = new();
|
private OpenSimplexNoise _noiseGenerator = new();
|
||||||
|
private Array<Spatial> _rockAssets;
|
||||||
private TileInstanceManager _tileInstanceManager;
|
private TileInstanceManager _tileInstanceManager;
|
||||||
|
private Array<Spatial> _treeAssets;
|
||||||
private ImageTexture _viewTileTypeTexture;
|
private ImageTexture _viewTileTypeTexture;
|
||||||
public Vector2 CenterChunkIndex = Vector2.Zero;
|
public Vector2 CenterChunkIndex = Vector2.Zero;
|
||||||
public Spatial Chunks;
|
public Spatial Chunks;
|
||||||
|
@ -71,6 +76,17 @@ public class World : Spatial
|
||||||
|
|
||||||
InitNoiseGenerator();
|
InitNoiseGenerator();
|
||||||
|
|
||||||
|
GetNode<Spatial>("Assets").Visible = false;
|
||||||
|
|
||||||
|
_rockAssets = new Array<Spatial>();
|
||||||
|
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);
|
SetCenterPlaneCoord(Vector2.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,6 +145,78 @@ public class World : Spatial
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private bool IsColorEqualApprox(Color colorA, Color colorB)
|
||||||
|
{
|
||||||
|
var colorDifference = new Vector3(colorA.r - colorB.r, colorA.g - colorB.g, colorA.b - colorB.b);
|
||||||
|
return colorDifference.LengthSquared() < 0.1 * 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Spatial SelectAsset(Vector2 offsetCoord, Array<Spatial> assets, Random randomGenerator, double probability)
|
||||||
|
{
|
||||||
|
if (randomGenerator.NextDouble() < 1.0 - probability) return null;
|
||||||
|
|
||||||
|
var assetIndex = randomGenerator.Next(assets.Count);
|
||||||
|
var assetInstance = (Spatial)assets[assetIndex].Duplicate();
|
||||||
|
var assetTransform = Transform.Identity;
|
||||||
|
assetTransform.origin = HexGrid.GetHexCenterVec3FromOffset(offsetCoord);
|
||||||
|
// TODO: assetTransform.origin.y = GetHeightAtOffset(offsetCoord);
|
||||||
|
assetTransform.origin.y = 0;
|
||||||
|
assetTransform.basis =
|
||||||
|
assetTransform.basis.Rotated(Vector3.Up, (float)(randomGenerator.NextDouble() * Mathf.Pi * 2));
|
||||||
|
assetInstance.Transform = assetTransform;
|
||||||
|
|
||||||
|
return assetInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PopulateChunk(WorldChunk chunk)
|
||||||
|
{
|
||||||
|
var environmentRandom = new Random(Seed);
|
||||||
|
|
||||||
|
var tileTypeImage = chunk.TileTypeOffscreenViewport.GetTexture().GetData();
|
||||||
|
tileTypeImage.Lock();
|
||||||
|
|
||||||
|
foreach (var textureCoordU in Enumerable.Range(0, chunk.Size))
|
||||||
|
foreach (var textureCoordV in Enumerable.Range(0, chunk.Size))
|
||||||
|
{
|
||||||
|
var colorValue = tileTypeImage.GetPixel(textureCoordU, textureCoordV);
|
||||||
|
var textureCoord = new Vector2(textureCoordU, textureCoordV);
|
||||||
|
var offsetCoord = chunk.ChunkIndex * ChunkSize + textureCoord;
|
||||||
|
|
||||||
|
if (IsColorEqualApprox(colorValue, RockColor))
|
||||||
|
{
|
||||||
|
var rockAsset = SelectAsset(offsetCoord, _rockAssets, environmentRandom, 0.15);
|
||||||
|
if (rockAsset != null) chunk.Entities.AddChild(rockAsset);
|
||||||
|
// TODO: MarkCellUnwalkable(cell);
|
||||||
|
}
|
||||||
|
else if (IsColorEqualApprox(colorValue, GrassColor) || IsColorEqualApprox(colorValue, DarkGrassColor))
|
||||||
|
{
|
||||||
|
var grassAsset = SelectAsset(offsetCoord, _grassAssets, environmentRandom, 0.15);
|
||||||
|
if (grassAsset != null) chunk.Entities.AddChild(grassAsset);
|
||||||
|
|
||||||
|
var treeAsset = SelectAsset(offsetCoord, _treeAssets, environmentRandom, 0.05);
|
||||||
|
if (treeAsset != null) chunk.Entities.AddChild(treeAsset);
|
||||||
|
// TODO: MarkCellUnwalkable(cell);
|
||||||
|
// else if (environmentRandom.NextDouble() < 0.01)
|
||||||
|
// {
|
||||||
|
// var chestAsset = (Chest)_chestScene.Instance();
|
||||||
|
// var assetTransform = Transform.Identity;
|
||||||
|
// assetTransform.origin = GetHexCenterFromOffset(offsetCoord);
|
||||||
|
// assetTransform.origin.y = GetHeightAtOffset(offsetCoord);
|
||||||
|
// chestAsset.Transform = assetTransform;
|
||||||
|
// Entities.AddChild(chestAsset);
|
||||||
|
// MarkCellUnwalkable(cell);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
// else if (IsColorWater(colorValue))
|
||||||
|
// {
|
||||||
|
// MarkCellUnwalkable(cell);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
tileTypeImage.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateCenterChunkFromPlaneCoord(Vector2 planeCoord)
|
public void UpdateCenterChunkFromPlaneCoord(Vector2 planeCoord)
|
||||||
{
|
{
|
||||||
if (State != GenerationState.Done)
|
if (State != GenerationState.Done)
|
||||||
|
@ -338,6 +426,8 @@ public class World : Spatial
|
||||||
else if (State == GenerationState.Objects)
|
else if (State == GenerationState.Objects)
|
||||||
{
|
{
|
||||||
// generate objects
|
// generate objects
|
||||||
|
foreach (var chunkIndex in _addedChunkIndices) PopulateChunk(_cachedWorldChunks[chunkIndex]);
|
||||||
|
|
||||||
State = GenerationState.Done;
|
State = GenerationState.Done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,16 @@ using Godot;
|
||||||
|
|
||||||
public class WorldChunk : Spatial
|
public class WorldChunk : Spatial
|
||||||
{
|
{
|
||||||
|
private readonly SpatialMaterial _rectMaterial = new();
|
||||||
private Sprite _heightmapSprite;
|
private Sprite _heightmapSprite;
|
||||||
private TextureRect _heightmapTextureRect;
|
private TextureRect _heightmapTextureRect;
|
||||||
private Sprite _noiseMask;
|
private Sprite _noiseMask;
|
||||||
|
|
||||||
private Sprite _noiseSprite;
|
private Sprite _noiseSprite;
|
||||||
|
|
||||||
private readonly SpatialMaterial _rectMaterial = new();
|
|
||||||
private bool _showTextureOverlay;
|
private bool _showTextureOverlay;
|
||||||
[Export] public Vector2 ChunkIndex;
|
[Export] public Vector2 ChunkIndex;
|
||||||
public Color DebugColor = Colors.White;
|
public Color DebugColor = Colors.White;
|
||||||
|
[Export] public Spatial Entities;
|
||||||
[Export] public Texture HeightMap;
|
[Export] public Texture HeightMap;
|
||||||
public int HeightMapFrameCount;
|
public int HeightMapFrameCount;
|
||||||
|
|
||||||
|
@ -91,6 +91,9 @@ public class WorldChunk : Spatial
|
||||||
TileTypeOffscreenViewport.Size = Vector2.One * Size;
|
TileTypeOffscreenViewport.Size = Vector2.One * Size;
|
||||||
Debug.Assert(TileTypeOffscreenViewport != null);
|
Debug.Assert(TileTypeOffscreenViewport != null);
|
||||||
|
|
||||||
|
Entities = (Spatial)FindNode("Entities");
|
||||||
|
Debug.Assert(Entities != null);
|
||||||
|
|
||||||
SetSize(World.ChunkSize);
|
SetSize(World.ChunkSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue