Added SceneTileChunk that is used in WorldView to manage state needed for the visible part of a chunk.
parent
0ce8a0ddd6
commit
da09c66cb3
Binary file not shown.
After Width: | Height: | Size: 6.0 KiB |
|
@ -0,0 +1,37 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path.s3tc="res://.import/TestHeightmap.png-6cbcc94e211273dff5857931034e368e.s3tc.stex"
|
||||||
|
path.etc2="res://.import/TestHeightmap.png-6cbcc94e211273dff5857931034e368e.etc2.stex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": [ "s3tc", "etc2" ],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/TestHeightmap.png"
|
||||||
|
dest_files=[ "res://.import/TestHeightmap.png-6cbcc94e211273dff5857931034e368e.s3tc.stex", "res://.import/TestHeightmap.png-6cbcc94e211273dff5857931034e368e.etc2.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=2
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=true
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=true
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=1
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=false
|
||||||
|
svg/scale=1.0
|
|
@ -0,0 +1,5 @@
|
||||||
|
[gd_resource type="StreamTexture" format=2]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
flags = 20
|
||||||
|
load_path = "res://.import/TestHeightmap.png-6cbcc94e211273dff5857931034e368e.stex"
|
|
@ -25,7 +25,7 @@ flags/repeat=true
|
||||||
flags/filter=true
|
flags/filter=true
|
||||||
flags/mipmaps=true
|
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
|
||||||
|
|
|
@ -122,6 +122,8 @@ public class Game : Spatial
|
||||||
_player.TaskQueueComponent.Connect("StartInteraction", _interactionSystem,
|
_player.TaskQueueComponent.Connect("StartInteraction", _interactionSystem,
|
||||||
nameof(_interactionSystem.OnStartInteraction));
|
nameof(_interactionSystem.OnStartInteraction));
|
||||||
_player.Connect("GoldCountChanged", this, nameof(OnGoldCountChanged));
|
_player.Connect("GoldCountChanged", this, nameof(OnGoldCountChanged));
|
||||||
|
_worldView.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||||
|
_worldView.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||||
|
|
||||||
// register entity events
|
// register entity events
|
||||||
foreach (Node node in GetNode("Entities").GetChildren())
|
foreach (Node node in GetNode("Entities").GetChildren())
|
||||||
|
|
|
@ -329,6 +329,7 @@ flip_v = true
|
||||||
visible = false
|
visible = false
|
||||||
|
|
||||||
[node name="StreamContainer" parent="." instance=ExtResource( 1 )]
|
[node name="StreamContainer" parent="." instance=ExtResource( 1 )]
|
||||||
|
visible = false
|
||||||
ShowHexTiles = true
|
ShowHexTiles = true
|
||||||
|
|
||||||
[node name="Camera" parent="." instance=ExtResource( 3 )]
|
[node name="Camera" parent="." instance=ExtResource( 3 )]
|
||||||
|
@ -339,6 +340,9 @@ 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 )
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ script = ExtResource( 1 )
|
||||||
|
|
||||||
[node name="Mesh" type="MeshInstance" parent="." groups=["GameGeometry"]]
|
[node name="Mesh" type="MeshInstance" parent="." groups=["GameGeometry"]]
|
||||||
transform = Transform( -4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0, -2.5, 0 )
|
transform = Transform( -4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0, -2.5, 0 )
|
||||||
visible = false
|
|
||||||
mesh = ExtResource( 3 )
|
mesh = ExtResource( 3 )
|
||||||
material/0 = ExtResource( 2 )
|
material/0 = ExtResource( 2 )
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
[node name="Spatial" type="Spatial"]
|
[node name="Spatial" type="Spatial"]
|
||||||
|
|
||||||
[node name="HexTile3D1" parent="." instance=ExtResource( 1 )]
|
[node name="HexTile3D1" parent="." instance=ExtResource( 1 )]
|
||||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )
|
|
||||||
|
|
||||||
[node name="HexTile3D2" parent="." instance=ExtResource( 1 )]
|
[node name="HexTile3D2" parent="." instance=ExtResource( 1 )]
|
||||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.866 )
|
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.866 )
|
||||||
|
|
114
scenes/World.cs
114
scenes/World.cs
|
@ -2,15 +2,27 @@ using Godot;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using Godot.Collections;
|
using Godot.Collections;
|
||||||
|
|
||||||
public class World : Spatial
|
public class World : Spatial
|
||||||
{
|
{
|
||||||
|
public enum GenerationState
|
||||||
|
{
|
||||||
|
Undefined,
|
||||||
|
Heightmap,
|
||||||
|
TileType,
|
||||||
|
Objects,
|
||||||
|
Done
|
||||||
|
}
|
||||||
|
public GenerationState State = GenerationState.Done;
|
||||||
|
|
||||||
// referenced scenes
|
// referenced scenes
|
||||||
private PackedScene _worldChunkScene = GD.Load<PackedScene>("res://scenes/WorldChunk.tscn");
|
private PackedScene _worldChunkScene = GD.Load<PackedScene>("res://scenes/WorldChunk.tscn");
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
public const int ChunkSize = 16;
|
public const int ChunkSize = 16;
|
||||||
|
public int Seed = 0;
|
||||||
public HexGrid HexGrid = new HexGrid();
|
public HexGrid HexGrid = new HexGrid();
|
||||||
public Spatial Chunks;
|
public Spatial Chunks;
|
||||||
public Color DebugColor;
|
public Color DebugColor;
|
||||||
|
@ -34,13 +46,15 @@ public class World : Spatial
|
||||||
private Vector2 _centerPlaneCoord;
|
private Vector2 _centerPlaneCoord;
|
||||||
private int[] _centerChunkCoord = { 0, 0 };
|
private int[] _centerChunkCoord = { 0, 0 };
|
||||||
private int[] _previousCenterChunkCoord = { 0, 0 };
|
private int[] _previousCenterChunkCoord = { 0, 0 };
|
||||||
private Rect2 _centerChunkRect2 = new Rect2();
|
private Rect2 _centerChunkRect = new Rect2();
|
||||||
private Random _debugColorRandom = new Random();
|
private Random _debugColorRandom = new Random();
|
||||||
private Godot.Collections.Dictionary<Vector2, WorldChunk> _cachedWorldChunks;
|
private Godot.Collections.Dictionary<Vector2, WorldChunk> _cachedWorldChunks;
|
||||||
private List<Vector2> _activeChunkIndices = new();
|
private List<Vector2> _activeChunkIndices = new();
|
||||||
private List<Vector2> _addedChunkIndices = new();
|
private List<Vector2> _addedChunkIndices = new();
|
||||||
private List<Vector2> _removedChunkIndices = new();
|
private List<Vector2> _removedChunkIndices = new();
|
||||||
|
|
||||||
|
private OpenSimplexNoise noiseGenerator = new();
|
||||||
|
|
||||||
public World()
|
public World()
|
||||||
{
|
{
|
||||||
Debug.Assert(ChunkSize % 2 == 0);
|
Debug.Assert(ChunkSize % 2 == 0);
|
||||||
|
@ -53,10 +67,23 @@ public class World : Spatial
|
||||||
{
|
{
|
||||||
Chunks = (Spatial)FindNode("Chunks");
|
Chunks = (Spatial)FindNode("Chunks");
|
||||||
Debug.Assert(Chunks != null);
|
Debug.Assert(Chunks != null);
|
||||||
|
|
||||||
|
InitNoiseGenerator();
|
||||||
|
|
||||||
SetCenterPlaneCoord(Vector2.Zero);
|
SetCenterPlaneCoord(Vector2.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void InitNoiseGenerator()
|
||||||
|
{
|
||||||
|
noiseGenerator = new OpenSimplexNoise();
|
||||||
|
|
||||||
|
noiseGenerator.Seed = Seed;
|
||||||
|
noiseGenerator.Octaves = 1;
|
||||||
|
noiseGenerator.Period = 10;
|
||||||
|
noiseGenerator.Persistence = 0.5f;
|
||||||
|
noiseGenerator.Lacunarity = 2;
|
||||||
|
}
|
||||||
|
|
||||||
public WorldChunk GetOrCreateWorldChunk(int xIndex, int yIndex, Color debugColor)
|
public WorldChunk GetOrCreateWorldChunk(int xIndex, int yIndex, Color debugColor)
|
||||||
{
|
{
|
||||||
if (IsTileCached(xIndex, yIndex))
|
if (IsTileCached(xIndex, yIndex))
|
||||||
|
@ -76,6 +103,7 @@ public class World : Spatial
|
||||||
private WorldChunk CreateWorldChunk(int xIndex, int yIndex, Color debugColor)
|
private WorldChunk CreateWorldChunk(int xIndex, int yIndex, Color debugColor)
|
||||||
{
|
{
|
||||||
WorldChunk result = (WorldChunk)_worldChunkScene.Instance();
|
WorldChunk result = (WorldChunk)_worldChunkScene.Instance();
|
||||||
|
result.SetSize(ChunkSize);
|
||||||
|
|
||||||
Vector2 offsetCoordSouthWest = new Vector2(xIndex, yIndex) * ChunkSize;
|
Vector2 offsetCoordSouthWest = new Vector2(xIndex, yIndex) * ChunkSize;
|
||||||
Vector2 offsetCoordNorthEast = offsetCoordSouthWest + new Vector2(1, 1) * (ChunkSize - 1);
|
Vector2 offsetCoordNorthEast = offsetCoordSouthWest + new Vector2(1, 1) * (ChunkSize - 1);
|
||||||
|
@ -102,6 +130,12 @@ public class World : Spatial
|
||||||
|
|
||||||
public void UpdateCenterChunkFromPlaneCoord(Vector2 planeCoord)
|
public void UpdateCenterChunkFromPlaneCoord(Vector2 planeCoord)
|
||||||
{
|
{
|
||||||
|
if (State != GenerationState.Done)
|
||||||
|
{
|
||||||
|
GD.PrintErr("Cannot update chunk to new planeCoord " + planeCoord + ": Chunk generation not yet finished!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
|
@ -109,7 +143,7 @@ public class World : Spatial
|
||||||
var chunkIndex = GetChunkTupleFromPlaneCoord(planeCoord);
|
var chunkIndex = GetChunkTupleFromPlaneCoord(planeCoord);
|
||||||
WorldChunk currentChunk = GetOrCreateWorldChunk(chunkIndex.Item1, chunkIndex.Item2,
|
WorldChunk currentChunk = GetOrCreateWorldChunk(chunkIndex.Item1, chunkIndex.Item2,
|
||||||
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
|
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
|
||||||
_centerChunkRect2 = currentChunk.PlaneRect;
|
_centerChunkRect = currentChunk.PlaneRect;
|
||||||
|
|
||||||
// load or create adjacent chunks
|
// load or create adjacent chunks
|
||||||
_activeChunkIndices = new List<Vector2>();
|
_activeChunkIndices = new List<Vector2>();
|
||||||
|
@ -149,8 +183,11 @@ public class World : Spatial
|
||||||
_addedChunkIndices.Add(chunkKey);
|
_addedChunkIndices.Add(chunkKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitSignal("OnTilesChanged", _removedChunkIndices.ToArray(), _addedChunkIndices.ToArray());
|
if (_addedChunkIndices.Count > 0)
|
||||||
|
{
|
||||||
|
State = GenerationState.Heightmap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveChunk(Vector2 cachedChunkKey)
|
private void RemoveChunk(Vector2 cachedChunkKey)
|
||||||
|
@ -178,15 +215,72 @@ public class World : Spatial
|
||||||
|
|
||||||
public void SetCenterPlaneCoord(Vector2 centerPlaneCoord)
|
public void SetCenterPlaneCoord(Vector2 centerPlaneCoord)
|
||||||
{
|
{
|
||||||
if (!_centerChunkRect2.HasPoint(centerPlaneCoord))
|
if (!_centerChunkRect.HasPoint(centerPlaneCoord))
|
||||||
{
|
{
|
||||||
UpdateCenterChunkFromPlaneCoord(centerPlaneCoord);
|
UpdateCenterChunkFromPlaneCoord(centerPlaneCoord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Called every frame. 'delta' is the elapsed time since the previous frame.
|
public override void _Process(float delta)
|
||||||
// public override void _Process(float delta)
|
{
|
||||||
// {
|
GenerationState oldState = State;
|
||||||
//
|
|
||||||
// }
|
if (State == GenerationState.Heightmap)
|
||||||
|
{
|
||||||
|
// generate heightmap for all new chunks
|
||||||
|
foreach (Vector2 chunkIndex in _addedChunkIndices)
|
||||||
|
{
|
||||||
|
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
||||||
|
Color debugChunkColor = new Color(Mathf.Abs(chunkIndex.x) / 5, Mathf.Abs(chunkIndex.y) / 5, Mathf.RoundToInt(Mathf.Abs(chunkIndex.x + chunkIndex.y)) % 2);
|
||||||
|
|
||||||
|
GD.Print("Generating for offset " + chunkIndex + " chunk: " + chunk + " debugChunkColor: " + debugChunkColor);
|
||||||
|
|
||||||
|
ImageTexture noiseImageTexture = new ImageTexture();
|
||||||
|
noiseImageTexture.CreateFromImage(noiseGenerator.GetImage(ChunkSize, ChunkSize, chunkIndex * ChunkSize), (uint) 0);
|
||||||
|
|
||||||
|
// Debug Texture
|
||||||
|
Image simpleImage = new Image();
|
||||||
|
simpleImage.Create(ChunkSize, ChunkSize, false, Image.Format.Rgb8);
|
||||||
|
simpleImage.Lock();
|
||||||
|
|
||||||
|
foreach (int i in Enumerable.Range(0, ChunkSize))
|
||||||
|
{
|
||||||
|
foreach (int j in Enumerable.Range(0, ChunkSize))
|
||||||
|
{
|
||||||
|
if ((i + j) % 2 == 0)
|
||||||
|
{
|
||||||
|
simpleImage.SetPixelv(new Vector2(i, j), Colors.Aqua);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
simpleImage.SetPixelv(new Vector2(i, j), debugChunkColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simpleImage.Unlock();
|
||||||
|
// noiseImageTexture.CreateFromImage(simpleImage, 0);
|
||||||
|
chunk.SetHeightmap(noiseImageTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign height map images
|
||||||
|
|
||||||
|
State = GenerationState.TileType;
|
||||||
|
} else if (State == GenerationState.TileType)
|
||||||
|
{
|
||||||
|
// assign tile type images
|
||||||
|
|
||||||
|
State = GenerationState.Objects;
|
||||||
|
} else if (State == GenerationState.Objects)
|
||||||
|
{
|
||||||
|
// generate objects
|
||||||
|
|
||||||
|
State = GenerationState.Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldState != GenerationState.Done && State == GenerationState.Done)
|
||||||
|
{
|
||||||
|
EmitSignal("OnTilesChanged", _removedChunkIndices.ToArray(), _addedChunkIndices.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -3,21 +3,22 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
public class WorldChunk : Spatial
|
public class WorldChunk : Spatial
|
||||||
{
|
{
|
||||||
// ui elements
|
// ui elements
|
||||||
|
|
||||||
// scene nodes
|
// scene nodes
|
||||||
private MeshInstance PlaneRectMesh;
|
private MeshInstance PlaneRectMesh;
|
||||||
|
|
||||||
// resources
|
// resources
|
||||||
|
|
||||||
// exports
|
// exports
|
||||||
[Export] public Texture TileTypeMap;
|
[Export] public Texture TileTypeMap;
|
||||||
[Export] public Texture NavigationMap;
|
[Export] public Texture NavigationMap;
|
||||||
[Export] public Texture HeightMap;
|
[Export] public Texture HeightMap;
|
||||||
[Export] public readonly int size = 32;
|
[Export] public int Size = 32;
|
||||||
|
|
||||||
[Export] public Vector2 ChunkAddress;
|
[Export] public Vector2 ChunkAddress;
|
||||||
// [Export] public Vector2 Size = new Vector2(1, 1);
|
// [Export] public Vector2 Size = new Vector2(1, 1);
|
||||||
|
@ -28,58 +29,127 @@ public class WorldChunk : Spatial
|
||||||
// other members
|
// other members
|
||||||
public Rect2 PlaneRect;
|
public Rect2 PlaneRect;
|
||||||
public Color DebugColor = Colors.White;
|
public Color DebugColor = Colors.White;
|
||||||
|
public Viewport TileTypeOffscreenViewport;
|
||||||
|
public bool NoiseTextureCheckerboardOverlay = true;
|
||||||
|
|
||||||
|
private TextureRect _heightmapRect;
|
||||||
|
private SpatialMaterial _rectMaterial = new SpatialMaterial();
|
||||||
|
|
||||||
public WorldChunk()
|
public WorldChunk()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorldChunk(int size)
|
public WorldChunk(int size)
|
||||||
{
|
{
|
||||||
|
SetSize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetSize(int size)
|
||||||
|
{
|
||||||
|
Size = size;
|
||||||
|
|
||||||
|
if (TileTypeOffscreenViewport != null)
|
||||||
|
{
|
||||||
|
TileTypeOffscreenViewport.Size = Vector2.One * size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// other members
|
// other members
|
||||||
public void SaveToFile(String chunkName)
|
public void SaveToFile(String chunkName)
|
||||||
{
|
{
|
||||||
Image image = new Image();
|
Image image = new Image();
|
||||||
|
|
||||||
image.CreateFromData(size, size, false, Image.Format.Rgba8, TileTypeMap.GetData().GetData());
|
image.CreateFromData(Size, Size, false, Image.Format.Rgba8, TileTypeMap.GetData().GetData());
|
||||||
image.SavePng(chunkName + "_tileType.png");
|
image.SavePng(chunkName + "_tileType.png");
|
||||||
|
|
||||||
image.CreateFromData(size, size, false, Image.Format.Rgba8, NavigationMap.GetData().GetData());
|
image.CreateFromData(Size, Size, false, Image.Format.Rgba8, NavigationMap.GetData().GetData());
|
||||||
image.SavePng(chunkName + "_navigationMap.png");
|
image.SavePng(chunkName + "_navigationMap.png");
|
||||||
|
|
||||||
image.CreateFromData(size, size, false, Image.Format.Rgba8, HeightMap.GetData().GetData());
|
image.CreateFromData(Size, Size, false, Image.Format.Rgba8, HeightMap.GetData().GetData());
|
||||||
image.SavePng(chunkName + "_heightMap.png");
|
image.SavePng(chunkName + "_heightMap.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadFromFile(String chunkName)
|
public void LoadFromFile(String chunkName)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
Transform planeRectTransform = Transform.Identity;
|
Transform planeRectTransform = Transform.Identity;
|
||||||
planeRectTransform = planeRectTransform.Scaled(new Vector3(PlaneRect.Size.x * 0.5f, 1, PlaneRect.Size.y * 0.5f));
|
planeRectTransform =
|
||||||
|
planeRectTransform.Scaled(new Vector3(PlaneRect.Size.x, 0.125f, PlaneRect.Size.y));
|
||||||
planeRectTransform.origin.x = PlaneRect.GetCenter().x;
|
planeRectTransform.origin.x = PlaneRect.GetCenter().x;
|
||||||
planeRectTransform.origin.z = PlaneRect.GetCenter().y;
|
|
||||||
|
|
||||||
|
planeRectTransform.origin.z = PlaneRect.GetCenter().y;
|
||||||
|
|
||||||
PlaneRectMesh.Transform = planeRectTransform;
|
PlaneRectMesh.Transform = planeRectTransform;
|
||||||
|
|
||||||
PlaneRectMesh.MaterialOverride = new SpatialMaterial();
|
// PlaneRectMesh.MaterialOverride = new SpatialMaterial();
|
||||||
((SpatialMaterial)PlaneRectMesh.MaterialOverride).AlbedoColor = DebugColor;
|
// ((SpatialMaterial)PlaneRectMesh.MaterialOverride).AlbedoColor = DebugColor;
|
||||||
((SpatialMaterial)PlaneRectMesh.MaterialOverride).FlagsTransparent = true;
|
// ((SpatialMaterial)PlaneRectMesh.MaterialOverride).FlagsTransparent = true;
|
||||||
|
|
||||||
|
TileTypeOffscreenViewport = (Viewport)FindNode("TileTypeOffscreenViewport");
|
||||||
|
TileTypeOffscreenViewport.Size = Vector2.One * Size;
|
||||||
|
Debug.Assert(TileTypeOffscreenViewport != null);
|
||||||
|
|
||||||
|
_heightmapRect = (TextureRect)FindNode("HeightmapTexture");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetHeightmap(Texture texture)
|
||||||
|
{
|
||||||
|
GD.Print("Setting HeightmapRect Texture: " + _heightmapRect + " with size " + _heightmapRect.GetSize());
|
||||||
|
_heightmapRect.Texture = texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 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)
|
||||||
// {
|
{
|
||||||
//
|
Texture tileTypeTexture = TileTypeOffscreenViewport.GetTexture();
|
||||||
// }
|
|
||||||
}
|
if (NoiseTextureCheckerboardOverlay)
|
||||||
|
{
|
||||||
|
Image tileTypeImage = tileTypeTexture.GetData();
|
||||||
|
tileTypeImage.Lock();
|
||||||
|
|
||||||
|
foreach (int i in Enumerable.Range(0, Size))
|
||||||
|
{
|
||||||
|
foreach (int j in Enumerable.Range(0, Size))
|
||||||
|
{
|
||||||
|
Vector2 textureCoord = new Vector2(i, j);
|
||||||
|
Color baseColor = tileTypeImage.GetPixelv(textureCoord);
|
||||||
|
|
||||||
|
if ((i + j) % 2 == 0)
|
||||||
|
{
|
||||||
|
tileTypeImage.SetPixelv(textureCoord, baseColor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tileTypeImage.SetPixelv(textureCoord, baseColor * 0.6f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tileTypeImage.Unlock();
|
||||||
|
ImageTexture imageTexture = new ImageTexture();
|
||||||
|
imageTexture.CreateFromImage(tileTypeImage, (uint) 0);
|
||||||
|
tileTypeTexture = imageTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
_rectMaterial.AlbedoTexture = tileTypeTexture;
|
||||||
|
|
||||||
|
_rectMaterial.FlagsTransparent = true;
|
||||||
|
// _rectMaterial.AlbedoTexture = _heightmapRect.Texture;
|
||||||
|
_rectMaterial.Uv1Scale = new Vector3(-3, -2, 1);
|
||||||
|
_rectMaterial.Uv1Offset = Vector3.One * 2;
|
||||||
|
|
||||||
|
//RectMaterial.Uv1Triplanar = true;
|
||||||
|
PlaneRectMesh.SetSurfaceMaterial(0, _rectMaterial);
|
||||||
|
|
||||||
|
TileTypeOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once;
|
||||||
|
PlaneRectMesh.MaterialOverride = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,29 @@
|
||||||
[gd_scene load_steps=4 format=2]
|
[gd_scene load_steps=9 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://assets/TestHeightmap.tres" type="Texture" id=3]
|
||||||
|
[ext_resource path="res://assets/4x4checkerColor.png" type="Texture" id=4]
|
||||||
|
|
||||||
[sub_resource type="CubeMesh" id=27]
|
[sub_resource type="CubeMesh" id=27]
|
||||||
size = Vector3( 2, 0.5, 2 )
|
size = Vector3( 1, 1, 1 )
|
||||||
|
|
||||||
[sub_resource type="SpatialMaterial" id=28]
|
[sub_resource type="SpatialMaterial" id=28]
|
||||||
|
flags_transparent = true
|
||||||
|
albedo_color = Color( 1, 1, 1, 0.501961 )
|
||||||
|
albedo_texture = ExtResource( 4 )
|
||||||
|
uv1_scale = Vector3( -3, -2, 0 )
|
||||||
|
uv1_offset = Vector3( 2, 2, 0 )
|
||||||
|
|
||||||
|
[sub_resource type="OpenSimplexNoise" id=29]
|
||||||
|
octaves = 1
|
||||||
|
period = 9.0
|
||||||
|
persistence = 0.0
|
||||||
|
|
||||||
|
[sub_resource type="NoiseTexture" id=30]
|
||||||
|
width = 8
|
||||||
|
height = 8
|
||||||
|
noise = SubResource( 29 )
|
||||||
|
|
||||||
[node name="WorldChunk" type="Spatial"]
|
[node name="WorldChunk" type="Spatial"]
|
||||||
script = ExtResource( 1 )
|
script = ExtResource( 1 )
|
||||||
|
@ -13,5 +31,37 @@ script = ExtResource( 1 )
|
||||||
[node name="Entities" type="Spatial" parent="."]
|
[node name="Entities" type="Spatial" parent="."]
|
||||||
|
|
||||||
[node name="PlaneRectMesh" type="MeshInstance" parent="."]
|
[node name="PlaneRectMesh" type="MeshInstance" parent="."]
|
||||||
|
transform = Transform( 2, 0, 0, 0, 0.125, 0, 0, 0, 2, 0, -0.1, 0 )
|
||||||
mesh = SubResource( 27 )
|
mesh = SubResource( 27 )
|
||||||
material/0 = SubResource( 28 )
|
material/0 = SubResource( 28 )
|
||||||
|
|
||||||
|
[node name="TileTypeOffscreenViewport" type="Viewport" parent="."]
|
||||||
|
size = Vector2( 8, 8 )
|
||||||
|
transparent_bg = true
|
||||||
|
handle_input_locally = false
|
||||||
|
hdr = false
|
||||||
|
disable_3d = true
|
||||||
|
usage = 0
|
||||||
|
render_target_v_flip = true
|
||||||
|
render_target_update_mode = 3
|
||||||
|
shadow_atlas_quad_0 = 0
|
||||||
|
shadow_atlas_quad_1 = 0
|
||||||
|
shadow_atlas_quad_2 = 0
|
||||||
|
shadow_atlas_quad_3 = 0
|
||||||
|
|
||||||
|
[node name="NoiseTexture" type="TextureRect" parent="TileTypeOffscreenViewport"]
|
||||||
|
visible = false
|
||||||
|
margin_right = 40.0
|
||||||
|
margin_bottom = 40.0
|
||||||
|
texture = SubResource( 30 )
|
||||||
|
|
||||||
|
[node name="IslandShader" type="TextureRect" parent="TileTypeOffscreenViewport"]
|
||||||
|
material = ExtResource( 2 )
|
||||||
|
margin_right = 100.0
|
||||||
|
margin_bottom = 100.0
|
||||||
|
|
||||||
|
[node name="HeightmapTexture" type="TextureRect" parent="TileTypeOffscreenViewport/IslandShader"]
|
||||||
|
use_parent_material = true
|
||||||
|
margin_right = 100.0
|
||||||
|
margin_bottom = 100.0
|
||||||
|
texture = ExtResource( 3 )
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Linq;
|
||||||
using Godot;
|
using Godot;
|
||||||
using Godot.Collections;
|
using Godot.Collections;
|
||||||
|
|
||||||
|
@ -14,10 +15,62 @@ public class WorldView : Spatial
|
||||||
[Export] public Vector2 ViewCenterPlaneCoord;
|
[Export] public Vector2 ViewCenterPlaneCoord;
|
||||||
|
|
||||||
// signals
|
// signals
|
||||||
// delegate void OnCoordClicked(Vector2 world_pos);
|
[Signal]
|
||||||
|
delegate void TileClicked(HexTile3D tile3d);
|
||||||
|
[Signal]
|
||||||
|
delegate void TileHovered(HexTile3D tile3d);
|
||||||
|
|
||||||
// other members
|
// other members
|
||||||
private World _world;
|
private World _world;
|
||||||
|
|
||||||
|
private class SceneTileChunk : Spatial
|
||||||
|
{
|
||||||
|
private Vector2 _chunkIndex = Vector2.Inf;
|
||||||
|
public Vector2 ChunkIndex
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _chunkIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Transform chunkTransform = Transform.Identity;
|
||||||
|
Vector2 chunkOriginPlaneCoord = HexGrid.GetHexCenterFromOffset(value * global::World.ChunkSize);
|
||||||
|
chunkTransform.origin = new Vector3(chunkOriginPlaneCoord.x, 0, chunkOriginPlaneCoord.y);
|
||||||
|
Transform = chunkTransform;
|
||||||
|
_chunkIndex = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<HexTile3D> TileNodes = new();
|
||||||
|
|
||||||
|
private PackedScene _hexTile3DScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
||||||
|
private HexGrid HexGrid = new();
|
||||||
|
|
||||||
|
public SceneTileChunk(Vector2 chunkIndex, int size)
|
||||||
|
{
|
||||||
|
foreach (int i in Enumerable.Range(0, size))
|
||||||
|
{
|
||||||
|
foreach (int j in Enumerable.Range(0, size))
|
||||||
|
{
|
||||||
|
HexTile3D tile3D = (HexTile3D)_hexTile3DScene.Instance();
|
||||||
|
|
||||||
|
Transform tileTransform = Transform.Identity;
|
||||||
|
Vector2 centerPlaneCoord = HexGrid.GetHexCenterFromOffset(new Vector2(i, j));
|
||||||
|
tileTransform.origin = new Vector3(centerPlaneCoord.x, 0, centerPlaneCoord.y);
|
||||||
|
tile3D.Transform = tileTransform;
|
||||||
|
|
||||||
|
TileNodes.Add(tile3D);
|
||||||
|
AddChild(tile3D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChunkIndex = chunkIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Array<SceneTileChunk> _sceneTileChunks = new Array<SceneTileChunk>();
|
||||||
|
|
||||||
// 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()
|
||||||
|
@ -27,14 +80,88 @@ public class WorldView : Spatial
|
||||||
_world.Connect("OnTilesChanged", this, nameof(HandleWorldTileChange));
|
_world.Connect("OnTilesChanged", this, nameof(HandleWorldTileChange));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void _Process(float delta)
|
public override void _Process(float delta)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SceneTileChunk CreateSceneTileChunk(Vector2 chunkIndex)
|
||||||
|
{
|
||||||
|
SceneTileChunk sceneTileChunk = new SceneTileChunk(chunkIndex, global::World.ChunkSize);
|
||||||
|
|
||||||
|
foreach (HexTile3D hexTile3D in sceneTileChunk.TileNodes)
|
||||||
|
{
|
||||||
|
hexTile3D.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||||
|
hexTile3D.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sceneTileChunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneTileChunk RemoveChunkFromScene(Vector2 chunkIndex)
|
||||||
|
{
|
||||||
|
foreach (Spatial child in GetChildren())
|
||||||
|
{
|
||||||
|
SceneTileChunk sceneTileChunk = child as SceneTileChunk;
|
||||||
|
if (sceneTileChunk == null)
|
||||||
|
{
|
||||||
|
RemoveChild(child);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sceneTileChunk.ChunkIndex == chunkIndex)
|
||||||
|
{
|
||||||
|
return sceneTileChunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void HandleWorldTileChange(Array<Vector2> removedChunkIndices, Array<Vector2> addedChunkIndices)
|
private void HandleWorldTileChange(Array<Vector2> removedChunkIndices, Array<Vector2> addedChunkIndices)
|
||||||
{
|
{
|
||||||
|
Array<SceneTileChunk> removedChunks = new();
|
||||||
|
foreach (Vector2 chunkIndex in removedChunkIndices)
|
||||||
|
{
|
||||||
|
SceneTileChunk chunk = RemoveChunkFromScene(chunkIndex);
|
||||||
|
if (chunk != null)
|
||||||
|
{
|
||||||
|
removedChunks.Add(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Vector2 chunkIndex in addedChunkIndices)
|
||||||
|
{
|
||||||
|
SceneTileChunk sceneTileChunk = null;
|
||||||
|
if (removedChunks.Count > 0)
|
||||||
|
{
|
||||||
|
sceneTileChunk = removedChunks[^1];
|
||||||
|
removedChunks.RemoveAt(removedChunks.Count - 1);
|
||||||
|
GD.Print("Reused SceneTileChunk");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sceneTileChunk = CreateSceneTileChunk(chunkIndex);
|
||||||
|
AddChild(sceneTileChunk);
|
||||||
|
GD.Print("Created SceneTileChunk");
|
||||||
|
}
|
||||||
|
|
||||||
|
sceneTileChunk.ChunkIndex = chunkIndex;
|
||||||
|
_sceneTileChunks.Add(sceneTileChunk);
|
||||||
|
}
|
||||||
|
|
||||||
GD.Print("Removed Chunks " + removedChunkIndices.Count);
|
GD.Print("Removed Chunks " + removedChunkIndices.Count);
|
||||||
GD.Print("Added Chunks " + addedChunkIndices.Count);
|
GD.Print("Added Chunks " + addedChunkIndices.Count);
|
||||||
|
GD.Print("Removed chunk count: " + removedChunks.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnTileClicked(HexTile3D tile)
|
||||||
|
{
|
||||||
|
EmitSignal("TileClicked", tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnTileHovered(HexTile3D tile)
|
||||||
|
{
|
||||||
|
EmitSignal("TileHovered", tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue