Compare commits

...

6 Commits

Author SHA1 Message Date
Martin Felis a0a3fea598 Chunk based world generation works.
Still missing:
- world population (trees, grass, rocks)
- chunk saving/loading
2023-10-30 22:20:32 +01:00
Martin Felis d918da6fd6 Somewhat improved GroundMotionComponent. Still buggy, though. 2023-10-27 23:00:54 +02:00
Martin Felis aaa286bf77 WorldView: make rendering of hex tile borders optional. 2023-10-27 22:58:37 +02:00
Martin Felis c808739b78 Hide WorldChunk Texture overlays by default. 2023-10-27 22:56:49 +02:00
Martin Felis d70d9cd682 For planned paths use the current position as the first NavigationPoint. 2023-10-27 22:11:45 +02:00
Martin Felis 01fde34276 Setting better bounds when performing Path search. 2023-10-27 21:49:37 +02:00
15 changed files with 243 additions and 83 deletions

View File

@ -1,7 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using Godot;
using GodotComponentTest.utils;
using Priority_Queue;
using AxialCoordDirectionPair = System.Tuple<Godot.Vector2, Godot.Vector3>;
@ -22,7 +21,7 @@ public class HexGrid : Resource
public float PathCostDefault = 1;
public int FindPathCheckedCells = 0;
public int FindPathCheckedCellCount;
public Vector2 HexSize
{
@ -76,11 +75,6 @@ public class HexGrid : Resource
return result;
}
public void SetBoundsOffset(Vector2 minOffset, Vector2 maxOffset)
{
SetBounds(HexCell.FromOffsetCoords(minOffset), HexCell.FromOffsetCoords(maxOffset));
}
public void SetBounds(Vector2 minAxial, Vector2 maxAxial)
{
SetBounds(new HexCell(minAxial), new HexCell(maxAxial));
@ -94,6 +88,13 @@ public class HexGrid : Resource
(_maxCoords.AxialCoords - _minCoords.AxialCoords) + Vector2.One);
}
public void SetBounds(HexCell center, int size)
{
Vector2 centerOffset = center.OffsetCoords;
SetBounds(GetHexAtOffset(centerOffset - Vector2.One * size / 2),
GetHexAtOffset(centerOffset + Vector2.One * size / 2));
}
public void AddObstacle(Vector2 axialCoords, float cost = 0)
{
AddObstacle(new HexCell(axialCoords), cost);
@ -221,11 +222,11 @@ public class HexGrid : Resource
cameFrom.Add(startHex.AxialCoords, startHex.AxialCoords);
costSoFar.Add(startHex.AxialCoords, 0);
FindPathCheckedCells = 0;
FindPathCheckedCellCount = 0;
while (frontier.Any())
{
FindPathCheckedCells++;
FindPathCheckedCellCount++;
HexCell currentHex = new HexCell(frontier.Dequeue());
Vector2 currentAxial = currentHex.AxialCoords;
@ -264,7 +265,7 @@ public class HexGrid : Resource
}
}
// GD.Print("Checked Cell Count: " + FindPathCheckedCells);
// GD.Print("Checked Cell Count: " + FindPathCheckedCellCount);
List<HexCell> result = new List<HexCell>();
if (!cameFrom.ContainsKey(goalHex.AxialCoords))
@ -293,7 +294,6 @@ public class HexGrid : Resource
{
List<HexCell> result = new List<HexCell>();
HexCell toCell = GetHexAt(toPlane);
float distance = (toPlane - fromPlane).Length();
Vector2 direction = (toPlane - fromPlane) / distance;

View File

@ -11,35 +11,58 @@ public class GroundMotionComponent : Component
public float Accel = 50;
public float Damping = 0.2f;
public float MaxSpeed = 8;
public float RotationSpeedRadPerSecond = 270 * Mathf.Pi / 180;
public Vector3 DirectionToTarget = Vector3.Zero;
public float DistanceToTarget = 0;
public float TargetAngle = 0;
public float TargetDeltaAngle = 0;
private void CalcAndApplyOrientation(float delta, Entity entity, Vector3 targetPosition, Quat targetOrientation)
{
float deltaAngleAbsolute = Mathf.Abs(TargetDeltaAngle);
if (deltaAngleAbsolute > 0.001)
{
Transform entityTransform = entity.Transform;
if (RotationSpeedRadPerSecond * delta + 0.001 >= deltaAngleAbsolute)
{
GD.Print("Target Angle " + TargetAngle + " reached! Current Angle: " + entity.PlaneAngle);
entity.PlaneAngle = TargetAngle;
TargetDeltaAngle = 0;
}
else
{
entity.PlaneAngle += Mathf.Sign(TargetDeltaAngle) * RotationSpeedRadPerSecond * delta;
}
}
else
{
TargetDeltaAngle = 0;
}
}
private void CalcPlaneVelocity(float delta, Entity entity, Vector3 targetPosition)
{
Vector2 planeTargetVector = new Vector2(targetPosition.x - entity.GlobalTranslation.x,
targetPosition.z - entity.GlobalTranslation.z);
float targetDistance = planeTargetVector.Length();
Vector2 planeTargetDirection = planeTargetVector / targetDistance;
Vector2 planeOrientation = new Vector2(entity.GlobalTransform.basis.z[0], entity.GlobalTransform.basis.z[2]);
Vector2 planeTargetDirection = new Vector2(DirectionToTarget.x, DirectionToTarget.z);
Vector2 planeVelocity = new Vector2(entity.Velocity.x, entity.Velocity.z);
// GD.Print("-- Step: distance: " + targetDistance + " dir: " + planeTargetDirection + " speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
planeVelocity -= planeVelocity * Damping;
// GD.Print(" damp : speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
if (targetDistance < 0.01 || planeOrientation.Dot(planeTargetDirection) < 0.9)
if (DistanceToTarget < 0.01)
{
planeVelocity = Vector2.Zero;
} else {
} else if (TargetDeltaAngle == 0.0) {
planeVelocity = planeVelocity.Length() * planeTargetDirection + planeTargetDirection * Accel * delta;
// GD.Print(" accel: speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
float projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
// GD.Print(" Projected step: " + projectedStep + " Speed: " + planeVelocity.Length() + " delta: " + delta);
if (projectedStep > targetDistance)
if (projectedStep > DistanceToTarget)
{
planeVelocity *= targetDistance / projectedStep;
planeVelocity *= DistanceToTarget / projectedStep;
projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
// GD.Print(" corr speed: " + planeVelocity.Length() + " step: " + projectedStep);
}
@ -50,6 +73,10 @@ public class GroundMotionComponent : Component
planeVelocity *= MaxSpeed / planeSpeed;
}
}
else
{
planeVelocity = Vector2.Zero;
}
entity.Velocity = new Vector3(planeVelocity.x, entity.Velocity.y, planeVelocity.y);
}
@ -88,9 +115,30 @@ public class GroundMotionComponent : Component
public void PhysicsProcess(float delta, Entity entity, Vector3 targetPosition, Quat targetOrientation, TileWorld tileWorld)
{
DirectionToTarget = (targetPosition - entity.GlobalTranslation);
DirectionToTarget.y = 0;
DistanceToTarget = DirectionToTarget.Length();
if (DistanceToTarget >= Globals.EpsPosition)
{
DirectionToTarget = DirectionToTarget.Normalized();
TargetAngle = Vector3.Right.SignedAngleTo(DirectionToTarget, Vector3.Up);
TargetDeltaAngle = entity.CalcShortestPlaneRotationToTarget(targetPosition);
}
else
{
GD.Print("Target Position reached!");
DirectionToTarget = Vector3.Right;
TargetAngle = entity.PlaneAngle;
TargetDeltaAngle = 0;
entity.GlobalTranslation = targetPosition;
entity.Velocity = new Vector3(0, entity.Velocity.y, 0);
return;
}
CalcAndApplyOrientation(delta, entity, targetPosition, targetOrientation);
CalcPlaneVelocity(delta, entity, targetPosition);
CalcVerticalVelocity(delta, entity, tileWorld);
// CalcVerticalVelocity(delta, entity, tileWorld);
entity.Velocity = entity.MoveAndSlide(entity.Velocity);
@ -98,38 +146,4 @@ public class GroundMotionComponent : Component
//GD.Print("Post: speed: " + entity.Velocity.Length() + " Velocity: " + entity.Velocity);
}
private void CalcAndApplyOrientation(float delta, Entity entity, Vector3 targetPosition, Quat targetOrientation)
{
Vector3 direction_to_target = targetPosition - entity.GlobalTranslation;
if (direction_to_target.LengthSquared() > Globals.EpsPositionSquared)
{
direction_to_target = direction_to_target.Normalized();
Vector3 localXAxis = Vector3.Up.Cross(direction_to_target);
targetOrientation = new Basis(localXAxis, Vector3.Up, direction_to_target).Quat().Normalized();
}
float orientationErrorRadians = entity.GlobalTransform.basis.Quat().AngleTo(targetOrientation);
if (Mathf.Abs(orientationErrorRadians) > Mathf.Pi * 1.1)
{
GD.Print("moep");
}
if (orientationErrorRadians > 0)
{
Transform entityTransform = entity.Transform;
if (orientationErrorRadians < RotationSpeedRadPerSecond * delta)
{
entityTransform.basis = new Basis(targetOrientation);
}
else if (orientationErrorRadians > 0f)
{
Quat entityRotation = new Quat(entityTransform.basis);
float slerpWeight = RotationSpeedRadPerSecond / (orientationErrorRadians / delta);
entityRotation = entityRotation.Slerp(targetOrientation, slerpWeight).Normalized();
entityTransform.basis = new Basis(entityRotation);
}
entity.Transform = entityTransform;
}
}
}

View File

@ -79,6 +79,7 @@ public class NavigationComponent : Spatial
private NavigationPoint _currentGoal;
private Vector3 _currentGoalPositionWorld = Vector3.Zero;
private float _currentGoalAngleWorld = 0;
private Quat _currentGoalOrientationWorld = Quat.Identity;
private List<NavigationPoint> _planningPathWorldNavigationPoints = new List<NavigationPoint>();
@ -140,6 +141,7 @@ public class NavigationComponent : Spatial
return;
}
TileWorld.HexGrid.SetBounds(fromCell, 40);
List<HexCell> path = TileWorld.HexGrid.FindPath(fromCell, toCell);
// Generate grid navigation points
@ -151,7 +153,7 @@ public class NavigationComponent : Spatial
}
// Ensure the last point coincides with the target position
if ((_planningPathWorldNavigationPoints.Last().WorldPosition - toPositionWorld).LengthSquared() <
if (_planningPathWorldNavigationPoints.Count > 0 && (_planningPathWorldNavigationPoints.Last().WorldPosition - toPositionWorld).LengthSquared() <
0.5f * 0.5f)
{
_planningPathWorldNavigationPoints[_planningPathWorldNavigationPoints.Count - 1].WorldPosition = toPositionWorld;
@ -159,6 +161,7 @@ public class NavigationComponent : Spatial
// Perform smoothing
_planningPathSmoothedWorldNavigationPoints = SmoothPath(body, _planningPathWorldNavigationPoints);
_planningPathSmoothedWorldNavigationPoints[0] = new NavigationPoint(fromPositionWorld);
}
public void FindPath(KinematicBody body, Vector3 fromPositionWorld, NavigationPoint navigationPoint)
@ -398,7 +401,7 @@ public class NavigationComponent : Spatial
_currentGoal = _pathWorldNavigationPoints[0];
_currentGoalPositionWorld = _pathWorldNavigationPoints[0].WorldPosition;
_currentGoalOrientationWorld = _pathWorldNavigationPoints[0].WorldOrientation;
//_currentGoalOrientationWorld = Vector3.Right.SignedAngleTo(_pathWorldNavigationPoints[0].WorldOrientation);
// GD.Print("Navigation Goal: pos " + _currentGoal.WorldPosition + " " + " rot: " + _currentGoal.WorldOrientation +
// " flags: " + _currentGoal.Flags + " path length: " +

View File

@ -6,6 +6,23 @@ public class Entity : KinematicBody
public Vector3 Velocity { get; set; } = Vector3.Zero;
public float RotationalVelocity { get; set; } = 0;
/** Defines the angle in plane coordinates, 0 => pointing to the right/east, pi/2 pointing up/north, range [-pi,pi]. */
public float PlaneAngle
{
get => GlobalTransform.basis.x.SignedAngleTo(Vector3.Right.Rotated(Vector3.Up, Mathf.Pi * 0.5f), -Vector3.Up);
set => GlobalTransform = new Transform(new Basis(Vector3.Up, value + Mathf.Pi * 0.5f), GlobalTranslation);
}
public float CalcShortestPlaneRotationToTarget(Vector3 globalTargetPosition)
{
float angleToTarget = Vector3.Right.SignedAngleTo(globalTargetPosition - GlobalTranslation, Vector3.Up);
float currentAngle = PlaneAngle;
float delta = angleToTarget - currentAngle;
delta += (delta > Mathf.Pi) ? -Mathf.Pi * 2 : (delta < -Mathf.Pi) ? Mathf.Pi * 2 : 0;
return delta;
}
public override void _Ready()
{
}

View File

@ -6,4 +6,6 @@
[resource]
shader = ExtResource( 2 )
shader_param/TextureSize = 4
shader_param/CoordinateOffsetU = null
shader_param/CoordinateOffsetV = null
shader_param/MapAlbedoTexture = ExtResource( 1 )

View File

@ -4,3 +4,11 @@
[resource]
shader = ExtResource( 1 )
shader_param/DeepWaterColor = Color( 0, 0, 0.6, 1 )
shader_param/WaterColor = Color( 0, 0, 0.7, 1 )
shader_param/LightWaterColor = Color( 0, 0, 1, 1 )
shader_param/SandColor = Color( 0.8, 0.8, 0.1, 1 )
shader_param/GrassColor = Color( 0, 0.6, 0, 1 )
shader_param/ForestColor = Color( 0, 0.4, 0, 1 )
shader_param/RockColor = Color( 0.5, 0.5, 0.4, 1 )
shader_param/SnowColor = Color( 1, 1, 1, 1 )

View File

@ -3,4 +3,5 @@
[ext_resource path="res://materials/shader/IslandHeightmapFalloffShader.gdshader" type="Shader" id=1]
[resource]
render_priority = -1
shader = ExtResource( 1 )

View File

@ -3,6 +3,8 @@ render_mode specular_schlick_ggx, async_visible;
uniform sampler2D MapAlbedoTexture : hint_black_albedo;
uniform int TextureSize: hint_range(0, 1024, 4);
uniform int CoordinateOffsetU: hint_range(-32000, 32000);
uniform int CoordinateOffsetV: hint_range(-32000, 32000);
varying vec2 map_coord;
const mat2 _HexAffineInverse = mat2(vec2(1.333333, -0.6666667), vec2(0, -1.154701));
@ -41,13 +43,12 @@ void vertex() {
vec3 origin = vec4(WORLD_MATRIX * vec4(0, 0, 0, 1)).xyz;
vec3 axial_coords = vec3(_HexAffineInverse * origin.xz, 0);
map_coord = axial_to_offset(axial_coords.xy);
map_coord = axial_to_offset(axial_coords.xy) - vec2(ivec2(CoordinateOffsetU, CoordinateOffsetV));
}
void fragment() {
float size = float(TextureSize);
vec2 texel_offset = vec2(ceil(size / 2.0));
ivec2 texel_coord = ivec2(mod(map_coord.xy - texel_offset, vec2(size)));
ivec2 texel_coord = ivec2(mod(map_coord.xy, vec2(size)));
vec4 texel_value = texelFetch(MapAlbedoTexture, texel_coord, 0);
ALBEDO = texelFetch(MapAlbedoTexture, texel_coord, 0).rgb;

View File

@ -1,28 +1,38 @@
shader_type canvas_item;
render_mode skip_vertex_transform;
uniform vec4 DeepWaterColor : hint_color = vec4(0, 0, 0.6, 1);
uniform vec4 WaterColor : hint_color = vec4(0, 0, 0.7, 1);
uniform vec4 LightWaterColor : hint_color = vec4(0, 0, 1, 1);
uniform vec4 SandColor : hint_color = vec4(0.8, 0.8, 0.1, 1);
uniform vec4 GrassColor : hint_color = vec4(0, 0.6, 0, 1);
uniform vec4 ForestColor : hint_color = vec4(0, 0.4, 0, 1);
uniform vec4 RockColor : hint_color = vec4(0.5, 0.5, 0.4, 1);
uniform vec4 SnowColor : hint_color = vec4(1);
uniform sampler2D TextureMask : hint_albedo;
void vertex() {
VERTEX = (WORLD_MATRIX * (EXTRA_MATRIX * vec4(VERTEX, 0.0, 1.0))).xy;
}
vec3 color_ramp(float h) {
if (h < 0.4f) {
return vec3(0, 0, 0.6);
if (h < 0.1f) {
return DeepWaterColor.rgb;
} else if (h < 0.12f) {
return WaterColor.rgb;
} else if (h < 0.45f) {
return vec3(0, 0, 0.7);
} else if (h < 0.5f) {
return vec3(0, 0, 1);
} else if (h < 0.55){
return vec3(0.8, 0.8, 0.1);
} else if (h < 0.6){
return vec3(0, 0.6, 0);
} else if (h < 0.78){
return vec3(0, 0.4, 0);
return LightWaterColor.rgb;
// } else if (h < 0.25){
// return SandColor.rgb;
} else if (h < 0.75){
return GrassColor.rgb;
// } else if (h < 0.78){
// return ForestColor.rgb;
} else if (h < 1.0){
return vec3(0.5, 0.5, 0.4);
return RockColor.rgb;
}
return vec3(1.0);
return SnowColor.rgb;
}
vec3 rgbToGrayscale(vec3 color) {
@ -42,9 +52,11 @@ float borderFalloffCircle(vec2 uv) {
void fragment() {
vec4 texture_color = texture(TEXTURE, UV);
COLOR.rgb = vec3(abs(UV.x - 0.5) * 2.0);
//COLOR.rgb = color_ramp(texture_color.r * borderFalloffCircle(UV) * 1.8);
COLOR.rgb = color_ramp(texture_color.r);
// COLOR.rgb = color_ramp(texture_color.r * borderFalloffCircle(UV) * 1.8);
COLOR.rgb = color_ramp(texture_color.r * texture(TextureMask, UV).r);
COLOR.a = 0.8;
// COLOR.rgb = vec3(1, 0, 0);
}

View File

@ -124,6 +124,7 @@ public class Game : Spatial
_player.Connect("GoldCountChanged", this, nameof(OnGoldCountChanged));
_worldView.Connect("TileClicked", this, nameof(OnTileClicked));
_worldView.Connect("TileHovered", this, nameof(OnTileHovered));
_worldView.Connect("OnWorldViewTileTypeImageChanged", this, nameof(OnWorldViewTileTypeImageChanged));
// register entity events
foreach (Node node in GetNode("Entities").GetChildren())
@ -356,6 +357,20 @@ public class Game : Spatial
_heightTextureRect.Texture = newHeightTexture;
}
private void OnWorldViewTileTypeImageChanged(Image viewTileTypeImage)
{
ImageTexture newWorldTexture = new ImageTexture();
newWorldTexture.CreateFromImage(viewTileTypeImage,
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
_worldTextureRect.Texture = newWorldTexture;
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
_tileMaterial.SetShaderParam("TextureSize", (int)newWorldTexture.GetSize().x);
_tileMaterial.SetShaderParam("CoordinateOffsetU", (int) _worldView.WorldTextureCoordinateOffset.x);
_tileMaterial.SetShaderParam("CoordinateOffsetV", (int) _worldView.WorldTextureCoordinateOffset.y);
}
public void OnGoldCountChanged(int goldCount)
{
AnimationPlayer animationPlayer = _gameUi.GetNode<AnimationPlayer>("AnimationPlayer");

View File

@ -10,6 +10,7 @@
[ext_resource path="res://scenes/TileWorld.tscn" type="PackedScene" id=8]
[ext_resource path="res://scenes/Game.cs" type="Script" id=9]
[ext_resource path="res://scenes/WorldView.cs" type="Script" id=10]
[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://entities/Axe.tscn" type="PackedScene" id=14]
[ext_resource path="res://systems/InteractionSystem.cs" type="Script" id=15]
@ -355,9 +356,13 @@ parameters/playback = SubResource( 26 )
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.79762, 0, 0 )
input_ray_pickable = false
[node name="Chest" parent="Entities" instance=ExtResource( 11 )]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -3.27709, 0, 1.02593 )
[node name="WorldView" type="Spatial" parent="."]
script = ExtResource( 10 )
World = NodePath("../World")
ShowHexTiles = true
[node name="World" type="Spatial" parent="."]
script = ExtResource( 7 )

View File

@ -16,12 +16,15 @@ public class World : Spatial
Done
}
public GenerationState State = GenerationState.Done;
public Vector2 CenterChunkIndex = Vector2.Zero;
// referenced scenes
private PackedScene _worldChunkScene = GD.Load<PackedScene>("res://scenes/WorldChunk.tscn");
// constants
public const int ChunkSize = 16;
public const int NumChunkRows = 3;
public const int NumChunkColumns = NumChunkRows;
public int Seed = 0;
public HexGrid HexGrid = new HexGrid();
public Spatial Chunks;
@ -44,10 +47,7 @@ public class World : Spatial
// other members
private Vector2 _centerPlaneCoord;
private int[] _centerChunkCoord = { 0, 0 };
private int[] _previousCenterChunkCoord = { 0, 0 };
private Rect2 _centerChunkRect = new Rect2();
private Random _debugColorRandom = new Random();
private Godot.Collections.Dictionary<Vector2, WorldChunk> _cachedWorldChunks;
private List<Vector2> _activeChunkIndices = new();
private List<Vector2> _addedChunkIndices = new();
@ -141,6 +141,8 @@ public class World : Spatial
// set new center chunk
var chunkIndex = GetChunkTupleFromPlaneCoord(planeCoord);
CenterChunkIndex = new Vector2(chunkIndex.Item1, chunkIndex.Item2);
WorldChunk currentChunk = GetOrCreateWorldChunk(chunkIndex.Item1, chunkIndex.Item2,
new Color(GD.Randf(), GD.Randf(), GD.Randf()));
_centerChunkRect = currentChunk.PlaneRect;
@ -159,6 +161,8 @@ public class World : Spatial
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1, chunkIndex.Item2 + 1));
_activeChunkIndices.Add(new Vector2(chunkIndex.Item1 + 1, chunkIndex.Item2 + 1));
Debug.Assert(_activeChunkIndices.Count == NumChunkRows * NumChunkColumns);
foreach(Vector2 activeChunkIndex in _activeChunkIndices)
{
GetOrCreateWorldChunk((int) activeChunkIndex.x, (int) activeChunkIndex.y, new Color(GD.Randf(), GD.Randf(), GD.Randf()));

View File

@ -19,10 +19,25 @@ public class WorldChunk : Spatial
[Export] public Texture NavigationMap;
[Export] public Texture HeightMap;
[Export] public int Size = 32;
[Export] public Vector2 ChunkAddress;
// [Export] public Vector2 Size = new Vector2(1, 1);
[Export]
public bool ShowTextureOverlay
{
get
{
return _showTextureOverlay;
}
set
{
if (PlaneRectMesh != null)
{
PlaneRectMesh.Visible = value;
}
}
}
// signals
// delegate void OnCoordClicked(Vector2 world_pos);
@ -34,6 +49,7 @@ public class WorldChunk : Spatial
private TextureRect _heightmapRect;
private SpatialMaterial _rectMaterial = new SpatialMaterial();
private bool _showTextureOverlay = false;
public WorldChunk()
{
@ -78,6 +94,10 @@ public class WorldChunk : Spatial
{
PlaneRectMesh = (MeshInstance)FindNode("PlaneRectMesh");
Debug.Assert(PlaneRectMesh != null);
if (PlaneRectMesh.Visible)
{
_showTextureOverlay = true;
}
Transform planeRectTransform = Transform.Identity;
planeRectTransform =

View File

@ -32,6 +32,7 @@ script = ExtResource( 1 )
[node name="PlaneRectMesh" type="MeshInstance" parent="."]
transform = Transform( 2, 0, 0, 0, 0.125, 0, 0, 0, 2, 0, -0.1, 0 )
visible = false
mesh = SubResource( 27 )
material/0 = SubResource( 28 )

View File

@ -1,6 +1,8 @@
using System.Linq;
using Godot;
using Godot.Collections;
using Vector2 = Godot.Vector2;
using Vector3 = Godot.Vector3;
public class WorldView : Spatial
{
@ -13,15 +15,22 @@ public class WorldView : Spatial
// exports
[Export] public NodePath World;
[Export] public Vector2 ViewCenterPlaneCoord;
[Export] public bool ShowHexTiles = false;
// signals
[Signal]
delegate void TileClicked(HexTile3D tile3d);
[Signal]
delegate void TileHovered(HexTile3D tile3d);
[Signal]
delegate void OnWorldViewTileTypeImageChanged(Image viewTileTypeImage);
// other members
public Vector2 WorldTextureCoordinateOffset = Vector2.Zero;
private World _world;
private ImageTexture _viewTileTypeTexture;
private Image _viewTileTypeImage = new();
private class SceneTileChunk : Spatial
{
@ -118,6 +127,42 @@ public class WorldView : Spatial
return null;
}
private void UpdateWorldViewTexture()
{
int worldChunkSize = global::World.ChunkSize;
int numWorldChunkRows = global::World.NumChunkRows;
int numWorldChunkColumns = global::World.NumChunkColumns;
_viewTileTypeImage.Create(worldChunkSize * numWorldChunkColumns, worldChunkSize * numWorldChunkRows, false, Image.Format.Rgba8);
Vector2 chunkIndexSouthWest = Vector2.Inf;
Vector2 chunkIndexNorthEast = -Vector2.Inf;
foreach (SceneTileChunk chunk in _sceneTileChunks)
{
WorldChunk worldChunk = _world.GetOrCreateWorldChunk((int) chunk.ChunkIndex.x, (int)chunk.ChunkIndex.y, Colors.White);
if (chunk.ChunkIndex.x <= chunkIndexSouthWest.x && chunk.ChunkIndex.y <= chunkIndexSouthWest.y)
{
chunkIndexSouthWest = chunk.ChunkIndex;
} else if (chunk.ChunkIndex.x >= chunkIndexNorthEast.x && chunk.ChunkIndex.y >= chunkIndexNorthEast.y)
{
chunkIndexNorthEast = chunk.ChunkIndex;
}
_viewTileTypeImage.BlendRect(
worldChunk.TileTypeOffscreenViewport.GetTexture().GetData(),
new Rect2(Vector2.Zero, Vector2.One * worldChunkSize),
(chunk.ChunkIndex - _world.CenterChunkIndex + Vector2.One) * worldChunkSize);
}
_viewTileTypeTexture = new ImageTexture();
_viewTileTypeTexture.CreateFromImage(_viewTileTypeImage);
WorldTextureCoordinateOffset = chunkIndexSouthWest * worldChunkSize;
EmitSignal("OnWorldViewTileTypeImageChanged", _viewTileTypeImage);
}
private void HandleWorldTileChange(Array<Vector2> removedChunkIndices, Array<Vector2> addedChunkIndices)
{
Array<SceneTileChunk> removedChunks = new();
@ -147,9 +192,21 @@ public class WorldView : Spatial
}
sceneTileChunk.ChunkIndex = chunkIndex;
if (ShowHexTiles)
{
foreach (HexTile3D tile3D in sceneTileChunk.TileNodes)
{
tile3D.Transform = new Transform(Basis.Identity.Scaled(Vector3.One * 0.95f),
tile3D.Transform.origin);
}
}
_sceneTileChunks.Add(sceneTileChunk);
}
UpdateWorldViewTexture();
GD.Print("Removed Chunks " + removedChunkIndices.Count);
GD.Print("Added Chunks " + addedChunkIndices.Count);
GD.Print("Removed chunk count: " + removedChunks.Count);