Refactoring now functional
parent
fcc2fdb8d3
commit
a37b028b39
|
@ -36,7 +36,6 @@ public class Game : Spatial
|
||||||
|
|
||||||
// Resources
|
// Resources
|
||||||
private PackedScene _tileHighlightScene;
|
private PackedScene _tileHighlightScene;
|
||||||
private TileInstanceManager _tileInstanceManager;
|
|
||||||
private ShaderMaterial _tileMaterial;
|
private ShaderMaterial _tileMaterial;
|
||||||
private Label _tileOffsetLabel;
|
private Label _tileOffsetLabel;
|
||||||
private World _world;
|
private World _world;
|
||||||
|
@ -46,7 +45,7 @@ public class Game : Spatial
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
// debugStatsContainer
|
// debugStatsContainer
|
||||||
var 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");
|
||||||
|
@ -60,7 +59,7 @@ public class Game : Spatial
|
||||||
_numCoordsRemovedLabel = debugStatsContainer.GetNode<Label>("num_coords_removed_label");
|
_numCoordsRemovedLabel = debugStatsContainer.GetNode<Label>("num_coords_removed_label");
|
||||||
|
|
||||||
// UI elements
|
// UI elements
|
||||||
var worldGeneratorContainer = (Container)FindNode("WorldGeneratorContainer");
|
Container worldGeneratorContainer = (Container)FindNode("WorldGeneratorContainer");
|
||||||
_worldTextureRect = worldGeneratorContainer.GetNode<TextureRect>("WorldTextureRect");
|
_worldTextureRect = worldGeneratorContainer.GetNode<TextureRect>("WorldTextureRect");
|
||||||
_heightTextureRect = worldGeneratorContainer.GetNode<TextureRect>("HeightTextureRect");
|
_heightTextureRect = worldGeneratorContainer.GetNode<TextureRect>("HeightTextureRect");
|
||||||
_generateWorldButton = worldGeneratorContainer.GetNode<Button>("WorldGenerateButton");
|
_generateWorldButton = worldGeneratorContainer.GetNode<Button>("WorldGenerateButton");
|
||||||
|
@ -77,10 +76,9 @@ public class Game : Spatial
|
||||||
_cameraOffset = _camera.GlobalTranslation - _player.GlobalTranslation;
|
_cameraOffset = _camera.GlobalTranslation - _player.GlobalTranslation;
|
||||||
|
|
||||||
_world = (World)FindNode("World");
|
_world = (World)FindNode("World");
|
||||||
_tileInstanceManager = (TileInstanceManager)FindNode("TileInstanceManager");
|
|
||||||
|
|
||||||
// populate UI values
|
// populate UI values
|
||||||
var generatorWorldSizeSlider = worldGeneratorContainer.GetNode<Slider>("HBoxContainer/WorldSizeSlider");
|
Slider generatorWorldSizeSlider = worldGeneratorContainer.GetNode<Slider>("HBoxContainer/WorldSizeSlider");
|
||||||
|
|
||||||
// resources
|
// resources
|
||||||
_tileHighlightScene = GD.Load<PackedScene>("utils/TileHighlight.tscn");
|
_tileHighlightScene = GD.Load<PackedScene>("utils/TileHighlight.tscn");
|
||||||
|
@ -88,7 +86,7 @@ public class Game : Spatial
|
||||||
Debug.Assert(_tileMaterial != null);
|
Debug.Assert(_tileMaterial != null);
|
||||||
|
|
||||||
_blackWhitePatternTexture = new ImageTexture();
|
_blackWhitePatternTexture = new ImageTexture();
|
||||||
var image = new Image();
|
Image image = new Image();
|
||||||
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));
|
||||||
|
|
||||||
|
@ -104,8 +102,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));
|
||||||
_tileInstanceManager.Connect("TileClicked", this, nameof(OnTileClicked));
|
_world.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||||
_tileInstanceManager.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));
|
||||||
|
|
||||||
|
@ -118,7 +116,7 @@ public class Game : Spatial
|
||||||
|
|
||||||
// perform dependency injection
|
// perform dependency injection
|
||||||
//_streamContainer.SetWorld(_tileWorld);Clicked
|
//_streamContainer.SetWorld(_tileWorld);Clicked
|
||||||
var worldInfoComponent = _player.GetNode<WorldInfoComponent>("WorldInfo");
|
WorldInfoComponent worldInfoComponent = _player.GetNode<WorldInfoComponent>("WorldInfo");
|
||||||
|
|
||||||
UpdateCurrentTile();
|
UpdateCurrentTile();
|
||||||
}
|
}
|
||||||
|
@ -134,9 +132,9 @@ public class Game : Spatial
|
||||||
public void UpdateCurrentTile()
|
public void UpdateCurrentTile()
|
||||||
{
|
{
|
||||||
// cast a ray from the camera to center
|
// cast a ray from the camera to center
|
||||||
var cameraNormal = _camera.ProjectRayNormal(_camera.GetViewport().Size * 0.5f);
|
Vector3 cameraNormal = _camera.ProjectRayNormal(_camera.GetViewport().Size * 0.5f);
|
||||||
var cameraPosition = _camera.ProjectRayOrigin(_camera.GetViewport().Size * 0.5f);
|
Vector3 cameraPosition = _camera.ProjectRayOrigin(_camera.GetViewport().Size * 0.5f);
|
||||||
var cameraDir = cameraNormal - cameraPosition;
|
Vector3 cameraDir = cameraNormal - cameraPosition;
|
||||||
|
|
||||||
Vector3 centerCoord;
|
Vector3 centerCoord;
|
||||||
|
|
||||||
|
@ -166,13 +164,13 @@ public class Game : Spatial
|
||||||
|
|
||||||
UpdateCurrentTile();
|
UpdateCurrentTile();
|
||||||
|
|
||||||
var tileHighlightTransform = Transform.Identity;
|
Transform tileHighlightTransform = Transform.Identity;
|
||||||
var currentTileCenter = _hexGrid.GetHexCenter(_currentTile);
|
Vector2 currentTileCenter = _hexGrid.GetHexCenter(_currentTile);
|
||||||
tileHighlightTransform.origin.x = currentTileCenter.x;
|
tileHighlightTransform.origin.x = currentTileCenter.x;
|
||||||
tileHighlightTransform.origin.z = currentTileCenter.y;
|
tileHighlightTransform.origin.z = currentTileCenter.y;
|
||||||
_tileHighlight.Transform = tileHighlightTransform;
|
_tileHighlight.Transform = tileHighlightTransform;
|
||||||
|
|
||||||
var cameraTransform = _camera.Transform;
|
Transform cameraTransform = _camera.Transform;
|
||||||
cameraTransform.origin = _player.GlobalTranslation + _cameraOffset;
|
cameraTransform.origin = _player.GlobalTranslation + _cameraOffset;
|
||||||
_camera.Transform = cameraTransform;
|
_camera.Transform = cameraTransform;
|
||||||
}
|
}
|
||||||
|
@ -181,7 +179,7 @@ public class Game : Spatial
|
||||||
public void OnGenerateButton()
|
public void OnGenerateButton()
|
||||||
{
|
{
|
||||||
GD.Print("Generating");
|
GD.Print("Generating");
|
||||||
var worldSizeSlider = (Slider)FindNode("WorldSizeSlider");
|
Slider worldSizeSlider = (Slider)FindNode("WorldSizeSlider");
|
||||||
if (worldSizeSlider == null) GD.PrintErr("Could not find WorldSizeSlider!");
|
if (worldSizeSlider == null) GD.PrintErr("Could not find WorldSizeSlider!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,8 +187,8 @@ public class Game : 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)
|
||||||
{
|
{
|
||||||
var cellAtCursor = _hexGrid.GetHexAt(new Vector2(position.x, position.z));
|
HexCell cellAtCursor = _hexGrid.GetHexAt(new Vector2(position.x, position.z));
|
||||||
var highlightTransform = Transform.Identity;
|
Transform highlightTransform = Transform.Identity;
|
||||||
|
|
||||||
_mouseWorldLabel.Text = position.ToString("F3");
|
_mouseWorldLabel.Text = position.ToString("F3");
|
||||||
_mouseTileOffsetLabel.Text = cellAtCursor.OffsetCoords.ToString("N");
|
_mouseTileOffsetLabel.Text = cellAtCursor.OffsetCoords.ToString("N");
|
||||||
|
@ -213,7 +211,7 @@ public class Game : Spatial
|
||||||
|
|
||||||
public void OnTileHovered(HexTile3D tile)
|
public void OnTileHovered(HexTile3D tile)
|
||||||
{
|
{
|
||||||
var 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");
|
||||||
_mouseTileOffsetLabel.Text = tile.OffsetCoords.ToString("N");
|
_mouseTileOffsetLabel.Text = tile.OffsetCoords.ToString("N");
|
||||||
|
@ -226,7 +224,7 @@ public class Game : Spatial
|
||||||
{
|
{
|
||||||
GD.Print("Clicked on entity at " + entity.GlobalTranslation);
|
GD.Print("Clicked on entity at " + entity.GlobalTranslation);
|
||||||
|
|
||||||
var mountPoint = (Spatial)entity.FindNode("MountPoint");
|
Spatial mountPoint = (Spatial)entity.FindNode("MountPoint");
|
||||||
if (mountPoint != null)
|
if (mountPoint != null)
|
||||||
{
|
{
|
||||||
_player.TaskQueueComponent.Reset();
|
_player.TaskQueueComponent.Reset();
|
||||||
|
@ -239,7 +237,7 @@ public class Game : Spatial
|
||||||
|
|
||||||
public void ResetGameState()
|
public void ResetGameState()
|
||||||
{
|
{
|
||||||
var playerStartTransform = Transform.Identity;
|
Transform playerStartTransform = Transform.Identity;
|
||||||
playerStartTransform.origin.y = 0;
|
playerStartTransform.origin.y = 0;
|
||||||
_player.Transform = playerStartTransform;
|
_player.Transform = playerStartTransform;
|
||||||
_player.TaskQueueComponent.Reset();
|
_player.TaskQueueComponent.Reset();
|
||||||
|
@ -250,9 +248,9 @@ public class Game : Spatial
|
||||||
|
|
||||||
foreach (Spatial entity in GetNode("Entities").GetChildren())
|
foreach (Spatial entity in GetNode("Entities").GetChildren())
|
||||||
{
|
{
|
||||||
var entityTransform = entity.Transform;
|
Transform entityTransform = entity.Transform;
|
||||||
var entityPlanePos = new Vector2(entityTransform.origin.x, entityTransform.origin.z);
|
Vector2 entityPlanePos = new Vector2(entityTransform.origin.x, entityTransform.origin.z);
|
||||||
var 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;
|
||||||
}
|
}
|
||||||
|
@ -260,7 +258,7 @@ public class Game : Spatial
|
||||||
|
|
||||||
private void OnHeightmapImageChanged(Image heightmapImage)
|
private void OnHeightmapImageChanged(Image heightmapImage)
|
||||||
{
|
{
|
||||||
var newHeightmapTexture = new ImageTexture();
|
ImageTexture newHeightmapTexture = new ImageTexture();
|
||||||
newHeightmapTexture.CreateFromImage(heightmapImage,
|
newHeightmapTexture.CreateFromImage(heightmapImage,
|
||||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||||
|
|
||||||
|
@ -269,7 +267,7 @@ public class Game : Spatial
|
||||||
|
|
||||||
private void OnWorldViewTileTypeImageChanged(Image viewTileTypeImage)
|
private void OnWorldViewTileTypeImageChanged(Image viewTileTypeImage)
|
||||||
{
|
{
|
||||||
var newWorldTexture = new ImageTexture();
|
ImageTexture newWorldTexture = new ImageTexture();
|
||||||
newWorldTexture.CreateFromImage(viewTileTypeImage,
|
newWorldTexture.CreateFromImage(viewTileTypeImage,
|
||||||
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
|
||||||
|
|
||||||
|
@ -283,7 +281,7 @@ public class Game : Spatial
|
||||||
|
|
||||||
public void OnGoldCountChanged(int goldCount)
|
public void OnGoldCountChanged(int goldCount)
|
||||||
{
|
{
|
||||||
var animationPlayer = _gameUi.GetNode<AnimationPlayer>("AnimationPlayer");
|
AnimationPlayer animationPlayer = _gameUi.GetNode<AnimationPlayer>("AnimationPlayer");
|
||||||
_goldCountLabel.Text = goldCount.ToString();
|
_goldCountLabel.Text = goldCount.ToString();
|
||||||
animationPlayer.CurrentAnimation = "FlashLabel";
|
animationPlayer.CurrentAnimation = "FlashLabel";
|
||||||
animationPlayer.Seek(0);
|
animationPlayer.Seek(0);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=22 format=2]
|
[gd_scene load_steps=21 format=2]
|
||||||
|
|
||||||
[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]
|
||||||
|
@ -7,7 +7,6 @@
|
||||||
[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.cs" type="Script" id=7]
|
||||||
[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://scenes/TileInstanceManager.cs" type="Script" 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/WorldGeneratorUI.gd" type="Script" id=12]
|
||||||
[ext_resource path="res://assets/Environment/HexTileMesh.tres" type="CylinderMesh" id=13]
|
[ext_resource path="res://assets/Environment/HexTileMesh.tres" type="CylinderMesh" id=13]
|
||||||
|
@ -358,6 +357,7 @@ flip_v = true
|
||||||
visible = false
|
visible = false
|
||||||
|
|
||||||
[node name="Camera" parent="." instance=ExtResource( 3 )]
|
[node name="Camera" parent="." instance=ExtResource( 3 )]
|
||||||
|
transform = Transform( 1, 0, 0, 0, 0.60042, 0.799685, 0, -0.799685, 0.60042, -4.76837e-07, 5.16505, 3.1696 )
|
||||||
|
|
||||||
[node name="InteractionSystem" type="Node" parent="."]
|
[node name="InteractionSystem" type="Node" parent="."]
|
||||||
script = ExtResource( 15 )
|
script = ExtResource( 15 )
|
||||||
|
@ -370,33 +370,27 @@ 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/Armature/Skeleton" index="5"]
|
[node name="ToolAttachement" parent="Player/Geometry/PirateAsset/Armature/Skeleton" index="5"]
|
||||||
transform = Transform( 1, 8.68458e-08, -1.04308e-07, 1.74623e-07, -1, -1.30385e-07, 1.41561e-07, 1.50874e-07, -1, -0.72, 0.45, 3.28113e-08 )
|
transform = Transform( 1, 7.13626e-08, -4.47035e-08, 1.64262e-07, -1, -1.00583e-07, 1.19209e-07, 1.18278e-07, -1, -0.72, 0.45, 1.78362e-08 )
|
||||||
|
|
||||||
[node name="AnimationTree" parent="Player/Geometry" index="2"]
|
[node name="AnimationTree" parent="Player/Geometry" index="2"]
|
||||||
parameters/playback = SubResource( 26 )
|
parameters/playback = SubResource( 26 )
|
||||||
|
|
||||||
[node name="Entities" type="Spatial" parent="."]
|
[node name="Entities" type="Spatial" parent="."]
|
||||||
visible = false
|
|
||||||
|
|
||||||
[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.79762, 0, 0 )
|
||||||
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( 1, 0, 0, 0, 1, 0, 0, 0, 1, -3.27709, 0, 1.02593 )
|
transform = Transform( -0.825665, 0, 0.56416, 0, 1, 0, -0.56416, 0, -0.825665, -3.27709, 0, 1.02593 )
|
||||||
|
|
||||||
[node name="World" type="Spatial" parent="."]
|
[node name="World" type="Spatial" parent="."]
|
||||||
script = ExtResource( 7 )
|
script = ExtResource( 7 )
|
||||||
|
|
||||||
[node name="Chunks" type="Spatial" parent="World"]
|
[node name="Chunks" type="Spatial" parent="World"]
|
||||||
|
|
||||||
[node name="TileInstanceManager" type="Spatial" parent="World"]
|
[node name="TileMultiMeshInstance" type="MultiMeshInstance" parent="World"]
|
||||||
script = ExtResource( 10 )
|
|
||||||
ShowHexTiles = true
|
|
||||||
World = NodePath("..")
|
|
||||||
|
|
||||||
[node name="TileMultiMeshInstance" type="MultiMeshInstance" parent="World/TileInstanceManager"]
|
|
||||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -2.5, 0 )
|
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -2.5, 0 )
|
||||||
multimesh = SubResource( 27 )
|
multimesh = SubResource( 27 )
|
||||||
|
|
||||||
|
@ -430,4 +424,4 @@ directional_shadow_mode = 0
|
||||||
[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"]
|
||||||
|
|
||||||
[editable path="Player"]
|
[editable path="Player"]
|
||||||
[editable path="Player/Geometry"]
|
[editable path="Player/Geometry/PirateAsset"]
|
||||||
|
|
|
@ -1,202 +0,0 @@
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using Godot;
|
|
||||||
using Godot.Collections;
|
|
||||||
|
|
||||||
public class TileInstanceManager : Spatial
|
|
||||||
{
|
|
||||||
// exports
|
|
||||||
[Export] public NodePath World;
|
|
||||||
[Export] public bool ShowHexTiles;
|
|
||||||
[Export] public Vector2 ViewCenterPlaneCoord;
|
|
||||||
|
|
||||||
// scene nodes
|
|
||||||
public MultiMeshInstance TileMultiMeshInstance;
|
|
||||||
|
|
||||||
// other members
|
|
||||||
private readonly Array<SceneTileChunk> _sceneTileChunks = new();
|
|
||||||
private int _usedTileInstanceIndices;
|
|
||||||
private ImageTexture _viewTileTypeTexture;
|
|
||||||
private World _world;
|
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
|
||||||
public override void _Ready()
|
|
||||||
{
|
|
||||||
_world = GetNode<World>(World);
|
|
||||||
|
|
||||||
_world.Connect("OnTilesChanged", this, nameof(HandleWorldTileChange));
|
|
||||||
|
|
||||||
TileMultiMeshInstance = (MultiMeshInstance)FindNode("TileMultiMeshInstance");
|
|
||||||
Debug.Assert(TileMultiMeshInstance != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override void _Process(float delta)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private SceneTileChunk CreateSceneTileChunk(Vector2 chunkIndex)
|
|
||||||
{
|
|
||||||
var sceneTileChunk =
|
|
||||||
new SceneTileChunk(chunkIndex, TileMultiMeshInstance, _usedTileInstanceIndices, ShowHexTiles);
|
|
||||||
_usedTileInstanceIndices += sceneTileChunk.TileNodes.Count;
|
|
||||||
|
|
||||||
foreach (var hexTile3D in sceneTileChunk.TileNodes)
|
|
||||||
{
|
|
||||||
hexTile3D.Connect("TileClicked", this, nameof(OnTileClicked));
|
|
||||||
hexTile3D.Connect("TileHovered", this, nameof(OnTileHovered));
|
|
||||||
}
|
|
||||||
|
|
||||||
return sceneTileChunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SceneTileChunk FindSceneTileChunkAtIndex(Vector2 chunkIndex)
|
|
||||||
{
|
|
||||||
foreach (Spatial child in GetChildren())
|
|
||||||
{
|
|
||||||
var sceneTileChunk = child as SceneTileChunk;
|
|
||||||
if (sceneTileChunk == null) continue;
|
|
||||||
|
|
||||||
if (sceneTileChunk.ChunkIndex == chunkIndex) return sceneTileChunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void HandleWorldTileChange(Array<Vector2> removedChunkIndices, Array<Vector2> addedChunkIndices)
|
|
||||||
{
|
|
||||||
Array<SceneTileChunk> removedChunks = new();
|
|
||||||
foreach (var chunkIndex in removedChunkIndices)
|
|
||||||
{
|
|
||||||
var chunk = FindSceneTileChunkAtIndex(chunkIndex);
|
|
||||||
if (chunk != null) removedChunks.Add(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var chunkIndex in addedChunkIndices)
|
|
||||||
{
|
|
||||||
SceneTileChunk sceneTileChunk = null;
|
|
||||||
if (removedChunks.Count > 0)
|
|
||||||
{
|
|
||||||
sceneTileChunk = removedChunks[^1];
|
|
||||||
sceneTileChunk.ChunkIndex = chunkIndex;
|
|
||||||
removedChunks.RemoveAt(removedChunks.Count - 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sceneTileChunk = CreateSceneTileChunk(chunkIndex);
|
|
||||||
AddChild(sceneTileChunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
_sceneTileChunks.Add(sceneTileChunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
GD.Print("Removed Chunks " + removedChunkIndices.Count);
|
|
||||||
GD.Print("Added Chunks " + addedChunkIndices.Count);
|
|
||||||
GD.Print("Removed chunk count: " + removedChunks.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnTileClicked(HexTile3D tile)
|
|
||||||
{
|
|
||||||
EmitSignal("TileClicked", tile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnTileHovered(HexTile3D tile)
|
|
||||||
{
|
|
||||||
EmitSignal("TileHovered", tile);
|
|
||||||
}
|
|
||||||
|
|
||||||
// signals
|
|
||||||
[Signal]
|
|
||||||
private delegate void TileClicked(HexTile3D tile3d);
|
|
||||||
|
|
||||||
[Signal]
|
|
||||||
private delegate void TileHovered(HexTile3D tile3d);
|
|
||||||
|
|
||||||
private class SceneTileChunk : Spatial
|
|
||||||
{
|
|
||||||
private readonly PackedScene _hexTile3DScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
|
||||||
private readonly MultiMeshInstance _multiMeshInstance;
|
|
||||||
private readonly Array<int> _tileInstanceIndices = new();
|
|
||||||
private readonly HexGrid _hexGrid = new();
|
|
||||||
private readonly bool _showHexTiles;
|
|
||||||
|
|
||||||
public readonly Array<HexTile3D> TileNodes = new();
|
|
||||||
private Vector2 _chunkIndex = Vector2.Inf;
|
|
||||||
|
|
||||||
|
|
||||||
public SceneTileChunk(Vector2 chunkIndex, MultiMeshInstance multiMeshInstance, int tileInstanceIndexStart,
|
|
||||||
bool showHexTiles)
|
|
||||||
{
|
|
||||||
_showHexTiles = showHexTiles;
|
|
||||||
|
|
||||||
var tileInstanceIndexStart1 = tileInstanceIndexStart;
|
|
||||||
var chunkSize = global::World.ChunkSize;
|
|
||||||
|
|
||||||
foreach (var i in Enumerable.Range(0, chunkSize))
|
|
||||||
foreach (var j in Enumerable.Range(0, chunkSize))
|
|
||||||
{
|
|
||||||
var tile3D = (HexTile3D)_hexTile3DScene.Instance();
|
|
||||||
tile3D.Cell.OffsetCoords = new Vector2(chunkIndex * global::World.ChunkSize + new Vector2(i, j));
|
|
||||||
|
|
||||||
var tileTransform = Transform.Identity;
|
|
||||||
var centerPlaneCoord = _hexGrid.GetHexCenterFromOffset(new Vector2(i, j));
|
|
||||||
tileTransform.origin = new Vector3(centerPlaneCoord.x, 0, centerPlaneCoord.y);
|
|
||||||
tile3D.Transform = tileTransform;
|
|
||||||
|
|
||||||
TileNodes.Add(tile3D);
|
|
||||||
AddChild(tile3D);
|
|
||||||
}
|
|
||||||
|
|
||||||
_multiMeshInstance = multiMeshInstance;
|
|
||||||
|
|
||||||
var chunkTileCount = global::World.ChunkSize * global::World.ChunkSize;
|
|
||||||
|
|
||||||
Debug.Assert(tileInstanceIndexStart1 + chunkTileCount <= _multiMeshInstance.Multimesh.InstanceCount);
|
|
||||||
|
|
||||||
foreach (var i in Enumerable.Range(0, chunkTileCount))
|
|
||||||
_tileInstanceIndices.Add(tileInstanceIndexStart1 + i);
|
|
||||||
|
|
||||||
// _multiMeshInstance.Multimesh.InstanceCount += chunkTileCount;
|
|
||||||
_multiMeshInstance.Multimesh.VisibleInstanceCount = _multiMeshInstance.Multimesh.InstanceCount;
|
|
||||||
|
|
||||||
ChunkIndex = chunkIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 ChunkIndex
|
|
||||||
{
|
|
||||||
get => _chunkIndex;
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
var chunkTransform = Transform.Identity;
|
|
||||||
var chunkOriginPlaneCoord = _hexGrid.GetHexCenterFromOffset(value * global::World.ChunkSize);
|
|
||||||
chunkTransform.origin = new Vector3(chunkOriginPlaneCoord.x, 0, chunkOriginPlaneCoord.y);
|
|
||||||
Transform = chunkTransform;
|
|
||||||
_chunkIndex = value;
|
|
||||||
|
|
||||||
var tileOrientation = new Basis(Vector3.Up, 90f * Mathf.Pi / 180f);
|
|
||||||
|
|
||||||
GD.Print("Updating transforms for instances of chunk " + value + " origin: " + chunkTransform.origin);
|
|
||||||
|
|
||||||
foreach (var i in Enumerable.Range(0, _tileInstanceIndices.Count))
|
|
||||||
{
|
|
||||||
var column = i % global::World.ChunkSize;
|
|
||||||
var row = i / global::World.ChunkSize;
|
|
||||||
|
|
||||||
var tilePlaneCoord =
|
|
||||||
_hexGrid.GetHexCenterFromOffset(new Vector2(column, row));
|
|
||||||
|
|
||||||
var hexTransform = new Transform(tileOrientation,
|
|
||||||
chunkTransform.origin + new Vector3(tilePlaneCoord.x, 0, tilePlaneCoord.y));
|
|
||||||
|
|
||||||
if (_showHexTiles)
|
|
||||||
hexTransform = new Transform(tileOrientation.Scaled(Vector3.One * 0.95f),
|
|
||||||
hexTransform.origin);
|
|
||||||
|
|
||||||
_multiMeshInstance.Multimesh.SetInstanceTransform(_tileInstanceIndices[i], hexTransform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
296
scenes/World.cs
296
scenes/World.cs
|
@ -17,7 +17,7 @@ public class World : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
public const int ChunkSize = 18;
|
public const int ChunkSize = 12;
|
||||||
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 RockColor = new(0.5f, 0.5f, 0.4f);
|
||||||
|
@ -25,11 +25,13 @@ public class World : Spatial
|
||||||
private static readonly Color DarkGrassColor = new(0.05882353f, 0.5411765f, 0.05882353f);
|
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 static readonly Color LightWaterColor = new(0.05882353f, 0.05882353f, 0.8627451f);
|
||||||
|
|
||||||
private readonly List<Vector2> _addedChunkIndices = new();
|
|
||||||
private readonly Godot.Collections.Dictionary<Vector2, WorldChunk> _cachedWorldChunks;
|
private readonly Godot.Collections.Dictionary<Vector2, WorldChunk> _cachedWorldChunks;
|
||||||
|
private readonly List<Vector2> _addedChunkIndices = new();
|
||||||
|
private readonly List<WorldChunk> _unusedWorldChunks = 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");
|
||||||
|
@ -48,7 +50,8 @@ public class World : Spatial
|
||||||
|
|
||||||
private OpenSimplexNoise _noiseGenerator = new();
|
private OpenSimplexNoise _noiseGenerator = new();
|
||||||
private Array<Spatial> _rockAssets;
|
private Array<Spatial> _rockAssets;
|
||||||
private TileInstanceManager _tileInstanceManager;
|
private MultiMeshInstance _tileMultiMeshInstance;
|
||||||
|
private int _usedTileMeshInstances;
|
||||||
private Array<Spatial> _treeAssets;
|
private Array<Spatial> _treeAssets;
|
||||||
private ImageTexture _viewTileTypeTexture;
|
private ImageTexture _viewTileTypeTexture;
|
||||||
public Vector2 CenterChunkIndex = Vector2.Zero;
|
public Vector2 CenterChunkIndex = Vector2.Zero;
|
||||||
|
@ -83,6 +86,13 @@ public class World : Spatial
|
||||||
[Signal]
|
[Signal]
|
||||||
public delegate void EntityClicked(Entity entity);
|
public delegate void EntityClicked(Entity entity);
|
||||||
|
|
||||||
|
// signals
|
||||||
|
[Signal]
|
||||||
|
private delegate void TileClicked(HexTile3D tile3d);
|
||||||
|
|
||||||
|
[Signal]
|
||||||
|
private delegate void TileHovered(HexTile3D tile3d);
|
||||||
|
|
||||||
public World()
|
public World()
|
||||||
{
|
{
|
||||||
Debug.Assert(ChunkSize % 2 == 0);
|
Debug.Assert(ChunkSize % 2 == 0);
|
||||||
|
@ -96,10 +106,11 @@ public class World : Spatial
|
||||||
Chunks = (Spatial)FindNode("Chunks");
|
Chunks = (Spatial)FindNode("Chunks");
|
||||||
Debug.Assert(Chunks != null);
|
Debug.Assert(Chunks != null);
|
||||||
|
|
||||||
_tileInstanceManager = (TileInstanceManager)FindNode("TileInstanceManager");
|
_tileMultiMeshInstance = (MultiMeshInstance)FindNode("TileMultiMeshInstance");
|
||||||
Debug.Assert(_tileInstanceManager != null);
|
Debug.Assert(_tileMultiMeshInstance != null);
|
||||||
_tileInstanceManager.TileMultiMeshInstance.Multimesh.InstanceCount =
|
_tileMultiMeshInstance.Multimesh.InstanceCount =
|
||||||
ChunkSize * ChunkSize * NumChunkColumns * NumChunkRows;
|
ChunkSize * ChunkSize * NumChunkColumns * NumChunkRows;
|
||||||
|
_usedTileMeshInstances = 0;
|
||||||
|
|
||||||
InitNoiseGenerator();
|
InitNoiseGenerator();
|
||||||
|
|
||||||
|
@ -128,65 +139,72 @@ public class World : Spatial
|
||||||
_noiseGenerator.Lacunarity = 2;
|
_noiseGenerator.Lacunarity = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorldChunk GetOrCreateWorldChunk(int xIndex, int yIndex, Color debugColor)
|
public WorldChunk GetOrCreateWorldChunk(Vector2 chunkIndex, Color debugColor)
|
||||||
{
|
{
|
||||||
if (IsChunkCached(xIndex, yIndex))
|
WorldChunk chunk;
|
||||||
|
|
||||||
|
if (IsChunkCached(chunkIndex))
|
||||||
|
return _cachedWorldChunks[chunkIndex];
|
||||||
|
|
||||||
|
if (_unusedWorldChunks.Count > 0)
|
||||||
{
|
{
|
||||||
var cachedChunk = _cachedWorldChunks[new Vector2(xIndex, yIndex)];
|
chunk = _unusedWorldChunks.First();
|
||||||
return cachedChunk;
|
_unusedWorldChunks.RemoveAt(0);
|
||||||
|
|
||||||
|
GD.Print("Reusing chunk from former index " + chunk.ChunkIndex + " at new index " + chunkIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chunk = CreateWorldChunk(chunkIndex, debugColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateWorldChunk(xIndex, yIndex, debugColor);
|
_cachedWorldChunks[chunkIndex] = chunk;
|
||||||
|
|
||||||
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsChunkCached(int xIndex, int yIndex)
|
private bool IsChunkCached(Vector2 chunkIndex)
|
||||||
{
|
{
|
||||||
return _cachedWorldChunks.ContainsKey(new Vector2(xIndex, yIndex));
|
return _cachedWorldChunks.ContainsKey(chunkIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private WorldChunk CreateWorldChunk(int xIndex, int yIndex, Color debugColor)
|
|
||||||
|
private WorldChunk CreateWorldChunk(Vector2 chunkIndex, Color debugColor)
|
||||||
{
|
{
|
||||||
var result = (WorldChunk)_worldChunkScene.Instance();
|
WorldChunk result = (WorldChunk)_worldChunkScene.Instance();
|
||||||
|
Chunks.AddChild(result);
|
||||||
|
result.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||||
|
result.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||||
|
|
||||||
result.SetSize(ChunkSize);
|
result.SetSize(ChunkSize);
|
||||||
|
result.InitializeTileInstances(chunkIndex, _tileMultiMeshInstance, _usedTileMeshInstances);
|
||||||
|
_usedTileMeshInstances += result.Tiles.GetChildCount();
|
||||||
|
|
||||||
var offsetCoordSouthWest = new Vector2(xIndex, yIndex) * ChunkSize;
|
result.SetChunkIndex(chunkIndex, HexGrid);
|
||||||
var offsetCoordNorthEast = offsetCoordSouthWest + new Vector2(1, 1) * (ChunkSize - 1);
|
result.UpdateTileTransforms();
|
||||||
|
|
||||||
var planeCoordSouthWest = HexGrid.GetHexCenterFromOffset(offsetCoordSouthWest) +
|
|
||||||
new Vector2(-HexGrid.HexSize.x, HexGrid.HexSize.y) * 0.5f;
|
|
||||||
var planeCoordNorthEast = HexGrid.GetHexCenterFromOffset(offsetCoordNorthEast) +
|
|
||||||
new Vector2(HexGrid.HexSize.x, -HexGrid.HexSize.y) * 0.5f;
|
|
||||||
|
|
||||||
result.ChunkIndex = new Vector2(xIndex, yIndex);
|
|
||||||
result.PlaneRect = new Rect2(
|
|
||||||
new Vector2(planeCoordSouthWest.x, planeCoordNorthEast.y),
|
|
||||||
new Vector2(planeCoordNorthEast.x - planeCoordSouthWest.x, planeCoordSouthWest.y - planeCoordNorthEast.y));
|
|
||||||
|
|
||||||
result.DebugColor = debugColor;
|
result.DebugColor = debugColor;
|
||||||
result.DebugColor.a = 0.6f;
|
result.DebugColor.a = 0.6f;
|
||||||
|
|
||||||
Chunks.AddChild(result);
|
|
||||||
var chunkIndex = new Vector2(xIndex, yIndex);
|
|
||||||
_cachedWorldChunks.Add(chunkIndex, result);
|
_cachedWorldChunks.Add(chunkIndex, result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private bool IsColorEqualApprox(Color colorA, Color colorB)
|
private bool IsColorEqualApprox(Color colorA, Color colorB)
|
||||||
{
|
{
|
||||||
var colorDifference = new Vector3(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 offsetCoord, 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;
|
||||||
|
|
||||||
var assetIndex = randomGenerator.Next(assets.Count);
|
int assetIndex = randomGenerator.Next(assets.Count);
|
||||||
var assetInstance = (Spatial)assets[assetIndex].Duplicate();
|
Spatial assetInstance = (Spatial)assets[assetIndex].Duplicate();
|
||||||
var assetTransform = Transform.Identity;
|
Transform assetTransform = Transform.Identity;
|
||||||
assetTransform.origin = HexGrid.GetHexCenterVec3FromOffset(offsetCoord);
|
assetTransform.origin = HexGrid.GetHexCenterVec3FromOffset(textureCoord);
|
||||||
// TODO: assetTransform.origin.y = GetHeightAtOffset(offsetCoord);
|
// TODO: assetTransform.origin.y = GetHeightAtOffset(offsetCoord);
|
||||||
assetTransform.origin.y = 0;
|
assetTransform.origin.y = 0;
|
||||||
assetTransform.basis =
|
assetTransform.basis =
|
||||||
|
@ -198,30 +216,30 @@ public class World : Spatial
|
||||||
|
|
||||||
private void PopulateChunk(WorldChunk chunk)
|
private void PopulateChunk(WorldChunk chunk)
|
||||||
{
|
{
|
||||||
var environmentRandom = new Random(Seed);
|
Random environmentRandom = new(Seed);
|
||||||
|
|
||||||
var tileTypeImage = chunk.TileTypeOffscreenViewport.GetTexture().GetData();
|
Image tileTypeImage = chunk.TileTypeOffscreenViewport.GetTexture().GetData();
|
||||||
tileTypeImage.Lock();
|
tileTypeImage.Lock();
|
||||||
|
|
||||||
foreach (var textureCoordU in Enumerable.Range(0, chunk.Size))
|
foreach (int textureCoordU in Enumerable.Range(0, chunk.Size))
|
||||||
foreach (var textureCoordV in Enumerable.Range(0, chunk.Size))
|
foreach (int textureCoordV in Enumerable.Range(0, chunk.Size))
|
||||||
{
|
{
|
||||||
var colorValue = tileTypeImage.GetPixel(textureCoordU, textureCoordV);
|
Color colorValue = tileTypeImage.GetPixel(textureCoordU, textureCoordV);
|
||||||
var textureCoord = new Vector2(textureCoordU, textureCoordV);
|
Vector2 textureCoord = new(textureCoordU, textureCoordV);
|
||||||
var offsetCoord = chunk.ChunkIndex * ChunkSize + textureCoord;
|
Vector2 offsetCoord = chunk.ChunkIndex * ChunkSize + textureCoord;
|
||||||
|
|
||||||
if (IsColorEqualApprox(colorValue, RockColor))
|
if (IsColorEqualApprox(colorValue, RockColor))
|
||||||
{
|
{
|
||||||
var rockAsset = SelectAsset(offsetCoord, _rockAssets, environmentRandom, 0.15);
|
Spatial rockAsset = SelectAsset(textureCoord, _rockAssets, environmentRandom, 0.15);
|
||||||
if (rockAsset != null) chunk.Entities.AddChild(rockAsset);
|
if (rockAsset != null) chunk.Entities.AddChild(rockAsset);
|
||||||
// TODO: MarkCellUnwalkable(cell);
|
// TODO: MarkCellUnwalkable(cell);
|
||||||
}
|
}
|
||||||
else if (IsColorEqualApprox(colorValue, GrassColor) || IsColorEqualApprox(colorValue, DarkGrassColor))
|
else if (IsColorEqualApprox(colorValue, GrassColor) || IsColorEqualApprox(colorValue, DarkGrassColor))
|
||||||
{
|
{
|
||||||
var grassAsset = SelectAsset(offsetCoord, _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(offsetCoord, _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);
|
||||||
|
@ -268,83 +286,89 @@ public class World : Spatial
|
||||||
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
|
||||||
var chunkIndex = GetChunkTupleFromPlaneCoord(planeCoord);
|
CenterChunkIndex = GetChunkTupleFromPlaneCoord(planeCoord);
|
||||||
CenterChunkIndex = new Vector2(chunkIndex.Item1, chunkIndex.Item2);
|
|
||||||
|
|
||||||
var currentChunk = GetOrCreateWorldChunk(chunkIndex.Item1, chunkIndex.Item2,
|
WorldChunk currentChunk = GetOrCreateWorldChunk(CenterChunkIndex,
|
||||||
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
|
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
|
||||||
_centerChunkRect = currentChunk.PlaneRect;
|
|
||||||
|
|
||||||
|
_centerChunkRect = new Rect2(
|
||||||
|
new Vector2(currentChunk.Transform.origin.x, currentChunk.Transform.origin.z)
|
||||||
|
+ currentChunk.PlaneRect.Position,
|
||||||
|
currentChunk.PlaneRect.Size);
|
||||||
|
GD.Print("Center Chunk Rect: " + _centerChunkRect.Position + " size: " + _centerChunkRect.Size);
|
||||||
|
|
||||||
// load or create adjacent chunks
|
// load or create adjacent chunks
|
||||||
_activeChunkIndices = new List<Vector2>();
|
_activeChunkIndices = new List<Vector2>();
|
||||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1 - 1, chunkIndex.Item2 - 1));
|
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(-1, -1));
|
||||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1, chunkIndex.Item2 - 1));
|
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(0, -1));
|
||||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1 + 1, chunkIndex.Item2 - 1));
|
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(1, -1));
|
||||||
|
|
||||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1 - 1, chunkIndex.Item2));
|
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(-1, 0));
|
||||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1, chunkIndex.Item2));
|
_activeChunkIndices.Add(CenterChunkIndex);
|
||||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1 + 1, chunkIndex.Item2));
|
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(+1, 0));
|
||||||
|
|
||||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1 - 1, chunkIndex.Item2 + 1));
|
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(-1, +1));
|
||||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1, chunkIndex.Item2 + 1));
|
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(0, +1));
|
||||||
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1 + 1, chunkIndex.Item2 + 1));
|
_activeChunkIndices.Add(CenterChunkIndex + new Vector2(+1, +1));
|
||||||
|
|
||||||
|
// clear unused chunks
|
||||||
|
_unusedWorldChunks.Clear();
|
||||||
|
_addedChunkIndices.Clear();
|
||||||
|
|
||||||
|
foreach (Vector2 oldChunkIndex in oldCachedChunks.Keys)
|
||||||
|
if (!_activeChunkIndices.Contains(oldChunkIndex))
|
||||||
|
DeactivateChunk(oldCachedChunks[oldChunkIndex]);
|
||||||
|
|
||||||
|
foreach (Vector2 activeChunkIndex in _activeChunkIndices)
|
||||||
|
{
|
||||||
|
WorldChunk chunk = GetOrCreateWorldChunk(activeChunkIndex,
|
||||||
|
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
|
||||||
|
_cachedWorldChunks[activeChunkIndex] = chunk;
|
||||||
|
}
|
||||||
|
|
||||||
Debug.Assert(_activeChunkIndices.Count == NumChunkRows * NumChunkColumns);
|
Debug.Assert(_activeChunkIndices.Count == NumChunkRows * NumChunkColumns);
|
||||||
|
|
||||||
foreach (var activeChunkIndex in _activeChunkIndices)
|
foreach (Vector2 chunkKey in _activeChunkIndices)
|
||||||
GetOrCreateWorldChunk((int)activeChunkIndex.x, (int)activeChunkIndex.y,
|
|
||||||
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
|
|
||||||
|
|
||||||
// unload retired chunks
|
|
||||||
_removedChunkIndices.Clear();
|
|
||||||
_addedChunkIndices.Clear();
|
|
||||||
|
|
||||||
foreach (var cachedChunkKey in oldCachedChunks.Keys)
|
|
||||||
if (!_activeChunkIndices.Contains(cachedChunkKey))
|
|
||||||
RemoveChunk(cachedChunkKey);
|
|
||||||
|
|
||||||
foreach (var chunkKey in _activeChunkIndices)
|
|
||||||
if (!oldCachedChunks.ContainsKey(chunkKey))
|
if (!oldCachedChunks.ContainsKey(chunkKey))
|
||||||
{
|
{
|
||||||
_addedChunkIndices.Add(chunkKey);
|
ActivateChunk(_cachedWorldChunks[chunkKey], chunkKey);
|
||||||
|
|
||||||
var chunk = _cachedWorldChunks[chunkKey];
|
|
||||||
GenerateChunkNoiseMap(chunk);
|
|
||||||
|
|
||||||
State = GenerationState.Heightmap;
|
State = GenerationState.Heightmap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ActivateChunk(WorldChunk chunk, Vector2 chunkIndex)
|
||||||
|
{
|
||||||
|
chunk.SetChunkIndex(chunkIndex, HexGrid);
|
||||||
|
chunk.UpdateTileTransforms();
|
||||||
|
|
||||||
|
_addedChunkIndices.Add(chunk.ChunkIndex);
|
||||||
|
GD.Print("Generating noise for chunk " + chunk.ChunkIndex);
|
||||||
|
GenerateChunkNoiseMap(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeactivateChunk(WorldChunk chunk)
|
||||||
|
{
|
||||||
|
GD.Print("Clearing chunk index: " + chunk.ChunkIndex);
|
||||||
|
_cachedWorldChunks.Remove(chunk.ChunkIndex);
|
||||||
|
chunk.ClearContent();
|
||||||
|
_unusedWorldChunks.Add(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
private void GenerateChunkNoiseMap(WorldChunk chunk)
|
private void GenerateChunkNoiseMap(WorldChunk chunk)
|
||||||
{
|
{
|
||||||
var chunkIndex = chunk.ChunkIndex;
|
Vector2 chunkIndex = chunk.ChunkIndex;
|
||||||
|
|
||||||
var debugChunkColor = new Color(Mathf.Abs(chunkIndex.x) / 5, Mathf.Abs(chunkIndex.y) / 5,
|
ImageTexture noiseImageTexture = new();
|
||||||
Mathf.RoundToInt(Mathf.Abs(chunkIndex.x + chunkIndex.y)) % 2);
|
|
||||||
|
|
||||||
var noiseImageTexture = new ImageTexture();
|
|
||||||
noiseImageTexture.CreateFromImage(_noiseGenerator.GetImage(ChunkSize, ChunkSize, chunkIndex * ChunkSize),
|
noiseImageTexture.CreateFromImage(_noiseGenerator.GetImage(ChunkSize, ChunkSize, chunkIndex * ChunkSize),
|
||||||
0);
|
0);
|
||||||
|
|
||||||
// Debug Texture
|
|
||||||
var simpleImage = new Image();
|
|
||||||
simpleImage.Create(ChunkSize, ChunkSize, false, Image.Format.Rgb8);
|
|
||||||
simpleImage.Lock();
|
|
||||||
|
|
||||||
foreach (var i in Enumerable.Range(0, ChunkSize))
|
|
||||||
foreach (var j in Enumerable.Range(0, ChunkSize))
|
|
||||||
if ((i + j) % 2 == 0)
|
|
||||||
simpleImage.SetPixelv(new Vector2(i, j), Colors.Aqua);
|
|
||||||
else
|
|
||||||
simpleImage.SetPixelv(new Vector2(i, j), debugChunkColor);
|
|
||||||
|
|
||||||
simpleImage.Unlock();
|
|
||||||
// noiseImageTexture.CreateFromImage(simpleImage, 0);
|
|
||||||
|
|
||||||
chunk.SetNoisemap(noiseImageTexture);
|
chunk.SetNoisemap(noiseImageTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,12 +383,10 @@ public class World : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Tuple<int, int> GetChunkTupleFromPlaneCoord(Vector2 planeCoord)
|
private Vector2 GetChunkTupleFromPlaneCoord(Vector2 planeCoord)
|
||||||
{
|
{
|
||||||
var centerOffsetCoord = HexGrid.GetHexAt(planeCoord);
|
HexCell centerOffsetCoord = HexGrid.GetHexAt(planeCoord);
|
||||||
var chunkIndexFloat = (centerOffsetCoord.OffsetCoords / ChunkSize).Floor();
|
return (centerOffsetCoord.OffsetCoords / ChunkSize).Floor();
|
||||||
var chunkIndex = new Tuple<int, int>((int)chunkIndexFloat.x, (int)chunkIndexFloat.y);
|
|
||||||
return chunkIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCenterPlaneCoord(Vector2 centerPlaneCoord)
|
public void SetCenterPlaneCoord(Vector2 centerPlaneCoord)
|
||||||
|
@ -381,18 +403,18 @@ public class World : Spatial
|
||||||
|
|
||||||
private void UpdateWorldViewTexture()
|
private void UpdateWorldViewTexture()
|
||||||
{
|
{
|
||||||
var worldChunkSize = ChunkSize;
|
int worldChunkSize = ChunkSize;
|
||||||
var numWorldChunkRows = NumChunkRows;
|
int numWorldChunkRows = NumChunkRows;
|
||||||
var numWorldChunkColumns = NumChunkColumns;
|
int numWorldChunkColumns = NumChunkColumns;
|
||||||
|
|
||||||
_heightmapImage.Create(worldChunkSize * numWorldChunkColumns, worldChunkSize * numWorldChunkRows, false,
|
_heightmapImage.Create(worldChunkSize * numWorldChunkColumns, worldChunkSize * numWorldChunkRows, false,
|
||||||
Image.Format.Rgba8);
|
Image.Format.Rgba8);
|
||||||
_tileTypeMapImage.Create(worldChunkSize * numWorldChunkColumns, worldChunkSize * numWorldChunkRows, false,
|
_tileTypeMapImage.Create(worldChunkSize * numWorldChunkColumns, worldChunkSize * numWorldChunkRows, false,
|
||||||
Image.Format.Rgba8);
|
Image.Format.Rgba8);
|
||||||
|
|
||||||
foreach (var chunkIndex in _activeChunkIndices)
|
foreach (Vector2 chunkIndex in _activeChunkIndices)
|
||||||
{
|
{
|
||||||
var worldChunk = GetOrCreateWorldChunk((int)chunkIndex.x, (int)chunkIndex.y, Colors.White);
|
WorldChunk worldChunk = GetOrCreateWorldChunk(chunkIndex, Colors.White);
|
||||||
|
|
||||||
_heightmapImage.BlendRect(
|
_heightmapImage.BlendRect(
|
||||||
worldChunk.HeightmapOffscreenViewport.GetTexture().GetData(),
|
worldChunk.HeightmapOffscreenViewport.GetTexture().GetData(),
|
||||||
|
@ -422,9 +444,9 @@ public class World : Spatial
|
||||||
_chunkIndexSouthWest = Vector2.Inf;
|
_chunkIndexSouthWest = Vector2.Inf;
|
||||||
_chunkIndexNorthEast = -Vector2.Inf;
|
_chunkIndexNorthEast = -Vector2.Inf;
|
||||||
|
|
||||||
foreach (var chunkIndex in _activeChunkIndices)
|
foreach (Vector2 chunkIndex in _activeChunkIndices)
|
||||||
{
|
{
|
||||||
var worldChunk = GetOrCreateWorldChunk((int)chunkIndex.x, (int)chunkIndex.y, Colors.White);
|
WorldChunk worldChunk = GetOrCreateWorldChunk(chunkIndex, Colors.White);
|
||||||
|
|
||||||
if (chunkIndex.x <= _chunkIndexSouthWest.x && chunkIndex.y <= _chunkIndexSouthWest.y)
|
if (chunkIndex.x <= _chunkIndexSouthWest.x && chunkIndex.y <= _chunkIndexSouthWest.y)
|
||||||
_chunkIndexSouthWest = chunkIndex;
|
_chunkIndexSouthWest = chunkIndex;
|
||||||
|
@ -435,71 +457,79 @@ public class World : Spatial
|
||||||
|
|
||||||
private void UpdateNavigationBounds()
|
private void UpdateNavigationBounds()
|
||||||
{
|
{
|
||||||
var 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
|
// 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.
|
// north east cell we have to add the chunk size to get to the actual corner cell.
|
||||||
var cellNorthEast = HexGrid.GetHexAtOffset(_chunkIndexNorthEast * ChunkSize + Vector2.One * (ChunkSize - 1));
|
HexCell cellNorthEast =
|
||||||
|
HexGrid.GetHexAtOffset(_chunkIndexNorthEast * ChunkSize + Vector2.One * (ChunkSize - 1));
|
||||||
|
|
||||||
var centerCell =
|
HexCell centerCell =
|
||||||
HexGrid.GetHexAtOffset(((cellNorthEast.OffsetCoords - cellSouthWest.OffsetCoords) / 2).Round());
|
HexGrid.GetHexAtOffset(((cellNorthEast.OffsetCoords - cellSouthWest.OffsetCoords) / 2).Round());
|
||||||
var numCells = ChunkSize * Math.Max(NumChunkColumns, NumChunkRows);
|
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 override void _Process(float delta)
|
||||||
{
|
{
|
||||||
var oldState = State;
|
GenerationState oldState = State;
|
||||||
|
|
||||||
UpdateGenerationState();
|
UpdateGenerationState();
|
||||||
|
|
||||||
if (oldState != GenerationState.Done && State == GenerationState.Done)
|
if (oldState != GenerationState.Done && State == GenerationState.Done)
|
||||||
{
|
|
||||||
UpdateWorldViewTexture();
|
UpdateWorldViewTexture();
|
||||||
|
|
||||||
EmitSignal("OnTilesChanged", _removedChunkIndices.ToArray(), _addedChunkIndices.ToArray());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateGenerationState()
|
private void UpdateGenerationState()
|
||||||
{
|
{
|
||||||
|
FrameCounter++;
|
||||||
|
|
||||||
if (State == GenerationState.Heightmap)
|
if (State == GenerationState.Heightmap)
|
||||||
{
|
{
|
||||||
var numChunksGeneratingHeightmap = 0;
|
int numChunksGeneratingHeightmap = 0;
|
||||||
foreach (var chunkIndex in _addedChunkIndices)
|
foreach (Vector2 chunkIndex in _addedChunkIndices)
|
||||||
{
|
{
|
||||||
var chunk = _cachedWorldChunks[chunkIndex];
|
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
||||||
if (chunk.HeightMapFrameCount > 0) numChunksGeneratingHeightmap++;
|
if (chunk.HeightMapFrameCount > 0) numChunksGeneratingHeightmap++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numChunksGeneratingHeightmap == 0)
|
if (numChunksGeneratingHeightmap == 0)
|
||||||
{
|
{
|
||||||
// assign height map images
|
// assign height map images
|
||||||
foreach (var chunkIndex in _addedChunkIndices)
|
foreach (Vector2 chunkIndex in _addedChunkIndices)
|
||||||
{
|
{
|
||||||
var 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)
|
||||||
{
|
{
|
||||||
var numChunksGeneratingTileType = 0;
|
int numChunksGeneratingTileType = 0;
|
||||||
foreach (var chunkIndex in _addedChunkIndices)
|
foreach (Vector2 chunkIndex in _addedChunkIndices)
|
||||||
{
|
{
|
||||||
var chunk = _cachedWorldChunks[chunkIndex];
|
WorldChunk chunk = _cachedWorldChunks[chunkIndex];
|
||||||
if (chunk.TileTypeMapFrameCount > 0) numChunksGeneratingTileType++;
|
if (chunk.TileTypeMapFrameCount > 0) numChunksGeneratingTileType++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numChunksGeneratingTileType == 0) State = GenerationState.Objects;
|
if (numChunksGeneratingTileType == 0)
|
||||||
|
{
|
||||||
|
GD.Print("Switching to Object Generation: " + FrameCounter);
|
||||||
|
State = GenerationState.Objects;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (State == GenerationState.Objects)
|
else if (State == GenerationState.Objects)
|
||||||
{
|
{
|
||||||
// generate objects
|
// generate objects
|
||||||
foreach (var chunkIndex in _addedChunkIndices) PopulateChunk(_cachedWorldChunks[chunkIndex]);
|
foreach (Vector2 chunkIndex in _addedChunkIndices)
|
||||||
|
PopulateChunk(_cachedWorldChunks[chunkIndex]);
|
||||||
|
|
||||||
|
_addedChunkIndices.Clear();
|
||||||
|
|
||||||
|
GD.Print("Generation done: " + FrameCounter);
|
||||||
State = GenerationState.Done;
|
State = GenerationState.Done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -508,4 +538,14 @@ public class World : Spatial
|
||||||
{
|
{
|
||||||
EmitSignal("EntityClicked", entity);
|
EmitSignal("EntityClicked", entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnTileClicked(HexTile3D tile)
|
||||||
|
{
|
||||||
|
EmitSignal("TileClicked", tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnTileHovered(HexTile3D tile)
|
||||||
|
{
|
||||||
|
EmitSignal("TileHovered", tile);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,14 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
using Godot.Collections;
|
||||||
|
|
||||||
public class WorldChunk : Spatial
|
public class WorldChunk : Spatial
|
||||||
{
|
{
|
||||||
|
private readonly PackedScene _hexTile3DScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
||||||
|
private MultiMeshInstance _multiMeshInstance;
|
||||||
|
private readonly Array<int> _tileInstanceIndices = new();
|
||||||
|
|
||||||
private readonly SpatialMaterial _rectMaterial = new();
|
private readonly SpatialMaterial _rectMaterial = new();
|
||||||
private Sprite _heightmapSprite;
|
private Sprite _heightmapSprite;
|
||||||
private TextureRect _heightmapTextureRect;
|
private TextureRect _heightmapTextureRect;
|
||||||
|
@ -11,9 +16,15 @@ public class WorldChunk : Spatial
|
||||||
|
|
||||||
private Sprite _noiseSprite;
|
private Sprite _noiseSprite;
|
||||||
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;
|
public Spatial Entities;
|
||||||
|
public Spatial Tiles;
|
||||||
|
private readonly HexGrid _hexGrid = new();
|
||||||
|
private readonly bool _showHexTiles;
|
||||||
|
|
||||||
[Export] public Texture HeightMap;
|
[Export] public Texture HeightMap;
|
||||||
public int HeightMapFrameCount;
|
public int HeightMapFrameCount;
|
||||||
|
|
||||||
|
@ -23,10 +34,15 @@ public class WorldChunk : Spatial
|
||||||
public bool NoiseTextureCheckerboardOverlay = true;
|
public bool NoiseTextureCheckerboardOverlay = true;
|
||||||
|
|
||||||
// signals
|
// signals
|
||||||
// delegate void OnCoordClicked(Vector2 world_pos);
|
[Signal]
|
||||||
|
private delegate void TileClicked(HexTile3D tile3d);
|
||||||
|
|
||||||
|
[Signal]
|
||||||
|
private delegate void TileHovered(HexTile3D tile3d);
|
||||||
|
|
||||||
// other members
|
// other members
|
||||||
public Rect2 PlaneRect;
|
public Rect2 PlaneRect;
|
||||||
|
|
||||||
// ui elements
|
// ui elements
|
||||||
|
|
||||||
// scene nodes
|
// scene nodes
|
||||||
|
@ -67,7 +83,7 @@ public class WorldChunk : Spatial
|
||||||
Debug.Assert(PlaneRectMesh != null);
|
Debug.Assert(PlaneRectMesh != null);
|
||||||
if (PlaneRectMesh.Visible) _showTextureOverlay = true;
|
if (PlaneRectMesh.Visible) _showTextureOverlay = true;
|
||||||
|
|
||||||
var planeRectTransform = Transform.Identity;
|
Transform planeRectTransform = Transform.Identity;
|
||||||
planeRectTransform =
|
planeRectTransform =
|
||||||
planeRectTransform.Scaled(new Vector3(PlaneRect.Size.x, 0.125f, PlaneRect.Size.y));
|
planeRectTransform.Scaled(new Vector3(PlaneRect.Size.x, 0.125f, PlaneRect.Size.y));
|
||||||
planeRectTransform.origin.x = PlaneRect.GetCenter().x;
|
planeRectTransform.origin.x = PlaneRect.GetCenter().x;
|
||||||
|
@ -94,6 +110,9 @@ public class WorldChunk : Spatial
|
||||||
Entities = (Spatial)FindNode("Entities");
|
Entities = (Spatial)FindNode("Entities");
|
||||||
Debug.Assert(Entities != null);
|
Debug.Assert(Entities != null);
|
||||||
|
|
||||||
|
Tiles = (Spatial)FindNode("Tiles");
|
||||||
|
Debug.Assert(Tiles != null);
|
||||||
|
|
||||||
SetSize(World.ChunkSize);
|
SetSize(World.ChunkSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,10 +131,98 @@ public class WorldChunk : Spatial
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetChunkIndex(Vector2 chunkIndex, HexGrid hexGrid)
|
||||||
|
{
|
||||||
|
ChunkIndex = chunkIndex;
|
||||||
|
float chunkSize = World.ChunkSize;
|
||||||
|
|
||||||
|
Vector2 planeCoordSouthWest = hexGrid.GetHexCenterFromOffset(chunkIndex * chunkSize);
|
||||||
|
|
||||||
|
Transform = new Transform(Basis.Identity, new Vector3(planeCoordSouthWest.x, 0, planeCoordSouthWest.y));
|
||||||
|
|
||||||
|
Vector2 localPlaneCoordSouthWest = new Vector2(-hexGrid.HexSize.x, hexGrid.HexSize.y) * 0.5f;
|
||||||
|
Vector2 localPlaneCoordNorthEast = hexGrid.GetHexCenterFromOffset(Vector2.One * chunkSize) +
|
||||||
|
new Vector2(hexGrid.HexSize.x, -hexGrid.HexSize.y) * 0.5f;
|
||||||
|
|
||||||
|
PlaneRect = new Rect2(
|
||||||
|
new Vector2(localPlaneCoordSouthWest.x, localPlaneCoordNorthEast.y),
|
||||||
|
new Vector2(localPlaneCoordNorthEast.x - localPlaneCoordSouthWest.x,
|
||||||
|
localPlaneCoordSouthWest.y - localPlaneCoordNorthEast.y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitializeTileInstances(Vector2 chunkIndex, MultiMeshInstance multiMeshInstance,
|
||||||
|
int tileInstanceIndexStart)
|
||||||
|
{
|
||||||
|
_multiMeshInstance = multiMeshInstance;
|
||||||
|
_tileInstanceIndices.Clear();
|
||||||
|
|
||||||
|
int chunkSize = World.ChunkSize;
|
||||||
|
|
||||||
|
foreach (Spatial node in Tiles.GetChildren())
|
||||||
|
node.QueueFree();
|
||||||
|
|
||||||
|
foreach (int i in Enumerable.Range(0, chunkSize))
|
||||||
|
foreach (int j in Enumerable.Range(0, chunkSize))
|
||||||
|
{
|
||||||
|
HexTile3D tile3D = (HexTile3D)_hexTile3DScene.Instance();
|
||||||
|
tile3D.Connect("TileClicked", this, nameof(OnTileClicked));
|
||||||
|
tile3D.Connect("TileHovered", this, nameof(OnTileHovered));
|
||||||
|
|
||||||
|
tile3D.Cell.OffsetCoords = new Vector2(chunkIndex * World.ChunkSize + new Vector2(i, j));
|
||||||
|
_tileInstanceIndices.Add(tileInstanceIndexStart + _tileInstanceIndices.Count);
|
||||||
|
|
||||||
|
Transform tileTransform = Transform.Identity;
|
||||||
|
Vector2 centerPlaneCoord = _hexGrid.GetHexCenterFromOffset(new Vector2(i, j));
|
||||||
|
tileTransform.origin = new Vector3(centerPlaneCoord.x, 0, centerPlaneCoord.y);
|
||||||
|
tile3D.Transform = tileTransform;
|
||||||
|
|
||||||
|
Tiles.AddChild(tile3D);
|
||||||
|
}
|
||||||
|
|
||||||
|
_multiMeshInstance.Multimesh.VisibleInstanceCount = _multiMeshInstance.Multimesh.InstanceCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearContent()
|
||||||
|
{
|
||||||
|
foreach (Spatial child in Entities.GetChildren())
|
||||||
|
child.QueueFree();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateTileTransforms()
|
||||||
|
{
|
||||||
|
Transform chunkTransform = Transform.Identity;
|
||||||
|
Vector2 chunkOriginPlaneCoord = _hexGrid.GetHexCenterFromOffset(ChunkIndex * World.ChunkSize);
|
||||||
|
chunkTransform.origin = new Vector3(chunkOriginPlaneCoord.x, 0, chunkOriginPlaneCoord.y);
|
||||||
|
Transform = chunkTransform;
|
||||||
|
|
||||||
|
Basis tileOrientation = new(Vector3.Up, 90f * Mathf.Pi / 180f);
|
||||||
|
|
||||||
|
GD.Print("Updating transforms for instances of chunk " + ChunkIndex + " origin: " + chunkTransform.origin);
|
||||||
|
|
||||||
|
foreach (int i in Enumerable.Range(0, _tileInstanceIndices.Count))
|
||||||
|
{
|
||||||
|
int column = i % World.ChunkSize;
|
||||||
|
int row = i / World.ChunkSize;
|
||||||
|
|
||||||
|
Vector2 tilePlaneCoord =
|
||||||
|
_hexGrid.GetHexCenterFromOffset(new Vector2(column, row));
|
||||||
|
|
||||||
|
Transform hexTransform = new(tileOrientation,
|
||||||
|
chunkTransform.origin + new Vector3(tilePlaneCoord.x, 0, tilePlaneCoord.y));
|
||||||
|
|
||||||
|
if (_showHexTiles)
|
||||||
|
hexTransform = new Transform(tileOrientation.Scaled(Vector3.One * 0.95f),
|
||||||
|
hexTransform.origin);
|
||||||
|
|
||||||
|
_multiMeshInstance.Multimesh.SetInstanceTransform(_tileInstanceIndices[i], hexTransform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// other members
|
// other members
|
||||||
public void SaveToFile(string chunkName)
|
public void SaveToFile(string chunkName)
|
||||||
{
|
{
|
||||||
var image = new Image();
|
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());
|
||||||
image.SavePng(chunkName + "_tileType.png");
|
image.SavePng(chunkName + "_tileType.png");
|
||||||
|
@ -157,14 +264,14 @@ public class WorldChunk : Spatial
|
||||||
|
|
||||||
if (NoiseTextureCheckerboardOverlay)
|
if (NoiseTextureCheckerboardOverlay)
|
||||||
{
|
{
|
||||||
var tileTypeImage = tileTypeTexture.GetData();
|
Image tileTypeImage = tileTypeTexture.GetData();
|
||||||
tileTypeImage.Lock();
|
tileTypeImage.Lock();
|
||||||
|
|
||||||
foreach (var i in Enumerable.Range(0, Size))
|
foreach (int i in Enumerable.Range(0, Size))
|
||||||
foreach (var j in Enumerable.Range(0, Size))
|
foreach (int j in Enumerable.Range(0, Size))
|
||||||
{
|
{
|
||||||
var textureCoord = new Vector2(i, j);
|
Vector2 textureCoord = new(i, j);
|
||||||
var 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);
|
||||||
|
@ -173,7 +280,7 @@ public class WorldChunk : Spatial
|
||||||
}
|
}
|
||||||
|
|
||||||
tileTypeImage.Unlock();
|
tileTypeImage.Unlock();
|
||||||
var imageTexture = new ImageTexture();
|
ImageTexture imageTexture = new();
|
||||||
imageTexture.CreateFromImage(tileTypeImage, 0);
|
imageTexture.CreateFromImage(tileTypeImage, 0);
|
||||||
tileTypeTexture = imageTexture;
|
tileTypeTexture = imageTexture;
|
||||||
}
|
}
|
||||||
|
@ -198,4 +305,14 @@ public class WorldChunk : Spatial
|
||||||
|
|
||||||
PlaneRectMesh.MaterialOverride = null;
|
PlaneRectMesh.MaterialOverride = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnTileClicked(HexTile3D tile)
|
||||||
|
{
|
||||||
|
EmitSignal("TileClicked", tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnTileHovered(HexTile3D tile)
|
||||||
|
{
|
||||||
|
EmitSignal("TileHovered", tile);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -24,6 +24,8 @@ blend_mode = 3
|
||||||
[node name="WorldChunk" type="Spatial"]
|
[node name="WorldChunk" type="Spatial"]
|
||||||
script = ExtResource( 1 )
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="Tiles" type="Spatial" parent="."]
|
||||||
|
|
||||||
[node name="Entities" type="Spatial" parent="."]
|
[node name="Entities" type="Spatial" parent="."]
|
||||||
|
|
||||||
[node name="PlaneRectMesh" type="MeshInstance" parent="."]
|
[node name="PlaneRectMesh" type="MeshInstance" parent="."]
|
||||||
|
|
Loading…
Reference in New Issue