Compare commits

...

2 Commits

Author SHA1 Message Date
Martin Felis e759d6d3d5 Fixed world generation artefacts after changing world size. 2023-07-28 22:23:41 +02:00
Martin Felis 87f7af88f8 Navigation: filtering out invalid start and end points. 2023-07-28 22:22:19 +02:00
7 changed files with 197 additions and 90 deletions

View File

@ -199,6 +199,26 @@ public class HexGrid : Resource
return cost;
}
public HexCell GetClosestWalkableCell(HexCell fromCell, HexCell toCell)
{
if (GetHexCost(toCell) == 0)
{
HexCell[] line = fromCell.LineTo(toCell);
foreach (int i in Enumerable.Range(1, line.Length))
{
if (GetHexCost(line[i]) == 0)
{
toCell = line[i - 1];
break;
}
}
}
return toCell;
}
public List<HexCell> FindPath(HexCell startHex, HexCell goalHex)
{
Vector2 startAxialCoords = startHex.AxialCoords;

View File

@ -104,7 +104,27 @@ public class NavigationComponent : Spatial
public void FindPath(KinematicBody body, Vector3 fromPositionWorld, Vector3 toPositionWorld)
{
HexCell fromCell = TileWorld.HexGrid.GetHexAt(new Vector2(fromPositionWorld.x, fromPositionWorld.z));
if (TileWorld.HexGrid.GetHexCost(fromCell) == 0)
{
GD.Print("Invalid starting point for FindPath(): returning empty path.");
_planningPathWorldNavigationPoints = new List<NavigationPoint>();
_planningPathWorldNavigationPoints.Add(new NavigationPoint(fromPositionWorld));
_planningPathSmoothedWorldNavigationPoints = _planningPathWorldNavigationPoints;
return;
}
HexCell toCell = TileWorld.HexGrid.GetHexAt(new Vector2(toPositionWorld.x, toPositionWorld.z));
toCell = TileWorld.HexGrid.GetClosestWalkableCell(fromCell, toCell);
if (TileWorld.HexGrid.GetHexCost(toCell) == 0)
{
GD.Print("Invalid target point for FindPath(): returning empty path.");
_planningPathWorldNavigationPoints = new List<NavigationPoint>();
_planningPathWorldNavigationPoints.Add(new NavigationPoint(fromPositionWorld));
_planningPathSmoothedWorldNavigationPoints = _planningPathWorldNavigationPoints;
return;
}
List<HexCell> path = TileWorld.HexGrid.FindPath(fromCell, toCell);
// GD.Print("Planning path and have " + TileWorld.HexGrid.Obstacles.Count + " obstacles:");

View File

@ -313,21 +313,11 @@ public class Game : Spatial
public void OnWorldGenerated()
{
GD.Print("Using new map. Size: " + (int)_tileWorld.Colormap.GetSize().x);
GD.Print("Using new map. Size: " + (int)_tileWorld.ColormapImage.GetSize().x);
_goldCountLabel.Text = "0";
ImageTexture newWorldTexture = new ImageTexture();
newWorldTexture.CreateFromImage(_tileWorld.Colormap,
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
_worldTextureRect.Texture = newWorldTexture;
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.Colormap.GetSize().x);
ImageTexture newHeightTexture = new ImageTexture();
newHeightTexture.CreateFromImage(_tileWorld.Heightmap,
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
_heightTextureRect.Texture = newHeightTexture;
UpdateWorldTextures();
_streamContainer.OnWorldGenerated();
@ -344,6 +334,23 @@ public class Game : Spatial
}
}
private void UpdateWorldTextures()
{
GD.Print("Updating World textures");
ImageTexture newWorldTexture = new ImageTexture();
newWorldTexture.CreateFromImage(_tileWorld.ColormapImage,
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
_worldTextureRect.Texture = newWorldTexture;
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.ColormapImage.GetSize().x);
GD.Print("Texture size: " + (int)_tileWorld.ColormapImage.GetSize().x);
ImageTexture newHeightTexture = new ImageTexture();
newHeightTexture.CreateFromImage(_tileWorld.HeightmapImage,
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
_heightTextureRect.Texture = newHeightTexture;
}
public void OnGoldCountChanged(int goldCount)
{

View File

@ -42,7 +42,7 @@ transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0 )
[node name="TileWorld" parent="." instance=ExtResource( 8 )]
GenerationMapType = 0
Size = 96
Size = 64
[node name="GameUI" type="HBoxContainer" parent="."]
anchor_left = 1.0
@ -259,21 +259,21 @@ margin_bottom = 84.0
text = "Textures"
[node name="WorldTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorContainer"]
visible = false
margin_top = 88.0
margin_right = 135.0
margin_right = 100.0
margin_bottom = 188.0
rect_min_size = Vector2( 100, 100 )
stretch_mode = 1
expand = true
stretch_mode = 5
flip_v = true
[node name="HeightTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorContainer"]
visible = false
margin_top = 88.0
margin_right = 135.0
margin_bottom = 188.0
margin_top = 192.0
margin_right = 100.0
margin_bottom = 292.0
rect_min_size = Vector2( 100, 100 )
stretch_mode = 1
expand = true
stretch_mode = 5
flip_v = true
[node name="EditorUI" parent="." instance=ExtResource( 4 )]

View File

@ -4,7 +4,6 @@ using System.Linq;
using System.Diagnostics;
using Godot.Collections;
using Namespace;
using Array = Godot.Collections.Array;
using Vector2 = Godot.Vector2;
using Vector3 = Godot.Vector3;
@ -19,8 +18,8 @@ public class TileWorld : Spatial
}
// constants
private static readonly Color RockColor = new Color(0.5f, 0.5f, 0.4f, 1f);
private static readonly Color GrassColor = new Color(0, 0.4f, 0, 1f);
private static readonly Color RockColor = new Color(0.5f, 0.5f, 0.4f);
private static readonly Color GrassColor = new Color(0, 0.4f, 0);
private GenerationState _currentGenerationState = GenerationState.Heightmap;
@ -39,11 +38,11 @@ public class TileWorld : Spatial
[ExportFlagsEnum(typeof(MapType))] public MapType GenerationMapType = MapType.Debug;
[Export] public int Size = 64;
[Export] public bool DebugMap = false;
[Export] public bool DebugMap;
public float HeightScale = 2.0f;
public Image Heightmap;
public Image Colormap;
public Image HeightmapImage;
public Image ColormapImage;
public int Seed = 0;
public Spatial Entities;
public HexGrid HexGrid;
@ -55,10 +54,12 @@ public class TileWorld : Spatial
private TextureRect _worldOffscreenTextureRect;
private Viewport _heightmapOffscreenViewport;
private TextureRect _heightmapOffscreenTextureRect;
private Array<Spatial> _rockAssets = new Array<Spatial>();
private Array<Spatial> _grassAssets = new Array<Spatial>();
private Array<Spatial> _treeAssets = new Array<Spatial>();
private Array<Spatial> _rockAssets = new();
private Array<Spatial> _grassAssets = new();
private Array<Spatial> _treeAssets = new();
private Spatial _environmentNode;
private bool _resizeTriggered;
private int _resizeExtraFrameCount = 0;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
@ -100,23 +101,57 @@ public class TileWorld : Spatial
_environmentNode = GetNode<Spatial>("Environment");
Entities = GetNode<Spatial>("Entities");
Generate(Size);
ResetWorldImages(Size);
}
public void ResetWorldImages(int size)
{
GD.Print("Resetting World Images to size " + size);
Vector2 sizeVector = new Vector2(size, size);
ColormapImage = new Image();
ColormapImage.Create(size, size, false, Image.Format.Rgba8);
ColormapImage.FillRect(new Rect2(0, 0, size, size), Colors.Black);
_worldOffscreenTextureRect.SetSize(sizeVector);
_worldOffscreenViewport.Size = sizeVector;
HeightmapImage = new Image();
HeightmapImage.Create(size, size, false, Image.Format.Rf);
HeightmapImage.FillRect(new Rect2(0, 0, size, size), Colors.ForestGreen);
_heightmapOffscreenTextureRect.SetSize(sizeVector);
_heightmapOffscreenViewport.Size = sizeVector;
}
public void PrintTextureSizes()
{
GD.Print("Color Viewport: " + _worldOffscreenViewport.Size);
GD.Print("Color TextureRect: " + _worldOffscreenTextureRect.Texture.GetSize());
GD.Print("Heightmap Viewport: " + _heightmapOffscreenViewport.Size);
GD.Print("Heightmap TextureRect: " + _heightmapOffscreenTextureRect.Texture.GetSize());
}
public void Generate(int size)
{
GD.Print("Triggering generation for size: " + size);
if (Size != size)
{
ResetWorldImages(size);
_resizeTriggered = true;
_resizeExtraFrameCount = 1;
}
Size = size;
_worldOffscreenViewport.Size = new Vector2(size, size);
_heightmapOffscreenViewport.Size = new Vector2(size, size);
_halfSize = Mathf.RoundToInt((float)size) / 2;
_halfSize = Mathf.RoundToInt(size) / 2;
HexGrid.SetBounds(
TextureCoordToCell(new Vector2(0, 0)),
TextureCoordToCell(new Vector2(size, size))
);
);
HexGrid.Obstacles.Clear();
HexGrid.Barriers.Clear();
@ -139,29 +174,29 @@ public class TileWorld : Spatial
private void GenerateDebugMap()
{
Colormap = new Image();
Colormap.Create(Size, Size, false, Image.Format.Rgba8);
ColormapImage = new Image();
ColormapImage.Create(Size, Size, false, Image.Format.Rgba8);
Heightmap = new Image();
Heightmap.Create(Size, Size, false, Image.Format.Rf);
HeightmapImage = new Image();
HeightmapImage.Create(Size, Size, false, Image.Format.Rf);
Heightmap.Lock();
Colormap.Lock();
HeightmapImage.Lock();
ColormapImage.Lock();
foreach (int coord_x in Enumerable.Range(0, Size))
foreach (int coordX in Enumerable.Range(0, Size))
{
foreach (int coord_y in Enumerable.Range(0, Size))
foreach (int coordY in Enumerable.Range(0, Size))
{
Colormap.SetPixel(coord_x, coord_y,
new Color((float)Mathf.Min(coord_x, coord_y) / Size, (float)0, 0, 1));
Heightmap.SetPixel(coord_x, coord_y,
new Color((float)Mathf.Min(coord_x, coord_y) / Size, (float)0, 0, 1));
ColormapImage.SetPixel(coordX, coordY,
new Color((float)Mathf.Min(coordX, coordY) / Size, 0, 0));
HeightmapImage.SetPixel(coordX, coordY,
new Color((float)Mathf.Min(coordX, coordY) / Size, 0, 0));
}
}
// Colormap.SetPixel(Size - 1, Size - 1, new Color(1, 1, 1, 1));
Colormap.Fill(Colors.ForestGreen);
Colormap.Unlock();
ColormapImage.Fill(Colors.ForestGreen);
ColormapImage.Unlock();
OnMapGenerationComplete();
}
@ -169,26 +204,26 @@ public class TileWorld : Spatial
private void GenerateFlatMap()
{
Colormap = new Image();
Colormap.Create(Size, Size, false, Image.Format.Rgba8);
ColormapImage = new Image();
ColormapImage.Create(Size, Size, false, Image.Format.Rgba8);
Heightmap = new Image();
Heightmap.Create(Size, Size, false, Image.Format.Rf);
HeightmapImage = new Image();
HeightmapImage.Create(Size, Size, false, Image.Format.Rf);
Heightmap.Lock();
Colormap.Lock();
HeightmapImage.Lock();
ColormapImage.Lock();
foreach (int coord_x in Enumerable.Range(0, Size))
foreach (int coordX in Enumerable.Range(0, Size))
{
foreach (int coord_y in Enumerable.Range(0, Size))
foreach (int coordY in Enumerable.Range(0, Size))
{
Heightmap.SetPixel(coord_x, coord_y,
new Color(0, 0, 0, 1));
HeightmapImage.SetPixel(coordX, coordY,
new Color(0, 0, 0));
}
}
Colormap.Fill(Colors.ForestGreen);
Colormap.Unlock();
ColormapImage.Fill(Colors.ForestGreen);
ColormapImage.Unlock();
OnMapGenerationComplete();
}
@ -196,8 +231,8 @@ public class TileWorld : Spatial
private void GenerateNoiseMap()
{
Heightmap = new Image();
Heightmap.Create(Size, Size, false, Image.Format.Rgba8);
HeightmapImage = new Image();
HeightmapImage.Create(Size, Size, false, Image.Format.Rgba8);
OpenSimplexNoise noiseGenerator = new OpenSimplexNoise();
@ -208,10 +243,9 @@ public class TileWorld : Spatial
noiseGenerator.Lacunarity = 4;
ImageTexture heightmapTexture = new ImageTexture();
heightmapTexture.CreateFromImage(noiseGenerator.GetSeamlessImage((int)Size));
heightmapTexture.CreateFromImage(noiseGenerator.GetSeamlessImage(Size));
heightmapTexture.Flags = 0;
_heightmapOffscreenTextureRect.Texture = heightmapTexture;
Heightmap.CopyFrom(_heightmapOffscreenViewport.GetTexture().GetData());
OnHeightMapChanged();
}
@ -231,6 +265,7 @@ public class TileWorld : Spatial
private void OnHeightMapChanged()
{
GD.Print("Triggering rendering of height map");
_currentGenerationState = GenerationState.Heightmap;
_heightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once;
}
@ -238,6 +273,11 @@ public class TileWorld : Spatial
private void OnMapGenerationComplete()
{
_currentGenerationState = GenerationState.Done;
_worldOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
_heightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
_resizeTriggered = false;
HeightmapImage.Lock();
EmitSignal("WorldGenerated");
}
@ -275,12 +315,14 @@ public class TileWorld : Spatial
{
Random environmentRandom = new Random(Seed);
Colormap.Lock();
ColormapImage.Lock();
HeightmapImage.Lock();
foreach (int textureCoordU in Enumerable.Range(0, Size))
{
foreach (int textureCoordV in Enumerable.Range(0, Size))
{
Color colorValue = Colormap.GetPixel(textureCoordU, textureCoordV);
Color colorValue = ColormapImage.GetPixel(textureCoordU, textureCoordV);
Vector2 textureCoord = new Vector2(textureCoordU, textureCoordV);
HexCell cell = TextureCoordToCell(textureCoord);
Vector2 offsetCoord = cell.OffsetCoords;
@ -316,39 +358,53 @@ public class TileWorld : Spatial
}
}
Colormap.Unlock();
HeightmapImage.Unlock();
ColormapImage.Unlock();
}
public override void _Process(float delta)
{
if (_resizeTriggered && _resizeExtraFrameCount > 0)
{
_resizeExtraFrameCount--;
return;
}
if (_currentGenerationState == GenerationState.Heightmap)
{
HeightmapImage.CopyFrom(_heightmapOffscreenViewport.GetTexture().GetData());
_currentGenerationState = GenerationState.Color;
ImageTexture imageTexture = new ImageTexture();
imageTexture.CreateFromImage(Heightmap);
imageTexture.CreateFromImage(HeightmapImage);
imageTexture.Flags = 0;
_worldOffscreenTextureRect.Texture = imageTexture;
GD.Print("Triggering rendering of color map");
_worldOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once;
_resizeExtraFrameCount = 1;
}
else if (_currentGenerationState == GenerationState.Color)
{
Colormap = new Image();
Colormap.Create(Size, Size, false, Image.Format.Rgb8);
Colormap.CopyFrom(_worldOffscreenViewport.GetTexture().GetData());
Heightmap.Lock();
ColormapImage = new Image();
ColormapImage.Create(Size, Size, false, Image.Format.Rgb8);
ColormapImage.CopyFrom(_worldOffscreenViewport.GetTexture().GetData());
_currentGenerationState = GenerationState.Objects;
PopulateEnvironment();
}
else if (_currentGenerationState == GenerationState.Objects)
{
OnMapGenerationComplete();
}
}
public bool IsOffsetCoordValid(Vector2 offsetCoord)
{
return ((int)Math.Clamp(offsetCoord.x, -Size / 2, Size / 2 - 1) == (int)offsetCoord.x
&& (int)Math.Clamp(offsetCoord.y, -Size / 2, Size / 2 - 1) == (int)offsetCoord.y);
return ((int)Math.Clamp(offsetCoord.x, -(float)Size / 2, (float)Size / 2 - 1) == (int)offsetCoord.x
&& (int)Math.Clamp(offsetCoord.y, -(float)Size / 2, (float)Size / 2 - 1) == (int)offsetCoord.y);
}
@ -365,7 +421,6 @@ public class TileWorld : Spatial
public Vector2 OffsetToTextureCoord(Vector2 offsetCoord)
{
// Vector2 textureCoord = (offsetCoord - Vector2.One * (Mathf.Floor(Size / 2))) % (Vector2.One * Size);
Vector2 mapSize = Vector2.One * Size;
Vector2 textureCoord = (offsetCoord + mapSize / 2).PosMod(mapSize);
return textureCoord;
@ -375,7 +430,7 @@ public class TileWorld : Spatial
{
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
Heightmap.SetPixel((int)textureCoord.x, (int)textureCoord.y, new Color(height, 0f, 0f));
HeightmapImage.SetPixel((int)textureCoord.x, (int)textureCoord.y, new Color(height, 0f, 0f));
}
public float GetHeightAtOffset(Vector2 offsetCoord)
@ -387,15 +442,12 @@ public class TileWorld : Spatial
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
float heightmapHeight = Heightmap.GetPixel((int)textureCoord.x, (int)(textureCoord.y)).r;
float heightmapHeight = HeightmapImage.GetPixel((int)textureCoord.x, (int)(textureCoord.y)).r;
if (heightmapHeight > 0.5)
{
heightmapHeight = 0.6f;
}
// heightmapHeight = Mathf.Floor(heightmapHeight);
// heightmapHeight = heightmapHeight * 10)
// heightmapHeight = Mathf.Clamp(heightmapHeight, -1f, 5);
return heightmapHeight * HeightScale;
}
@ -405,11 +457,11 @@ public class TileWorld : Spatial
{
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
Colormap.Lock();
Colormap.SetPixel((int)textureCoord.x, (int)textureCoord.y, color);
Colormap.Unlock();
ColormapImage.Lock();
ColormapImage.SetPixel((int)textureCoord.x, (int)textureCoord.y, color);
ColormapImage.Unlock();
EmitSignal("WorldGenerated");
OnMapGenerationComplete();
}
public Vector2 WorldToOffsetCoords(Vector3 worldCoord)

View File

@ -26,7 +26,11 @@ hdr = false
disable_3d = true
usage = 0
render_target_v_flip = true
render_target_update_mode = 1
render_target_update_mode = 0
shadow_atlas_quad_0 = 0
shadow_atlas_quad_1 = 0
shadow_atlas_quad_2 = 0
shadow_atlas_quad_3 = 0
[node name="TextureRect" type="TextureRect" parent="WorldOffscreenViewport"]
material = ExtResource( 3 )
@ -42,7 +46,11 @@ hdr = false
disable_3d = true
usage = 0
render_target_v_flip = true
render_target_update_mode = 1
render_target_update_mode = 0
shadow_atlas_quad_0 = 0
shadow_atlas_quad_1 = 0
shadow_atlas_quad_2 = 0
shadow_atlas_quad_3 = 0
[node name="TextureRect" type="TextureRect" parent="HeightmapOffscreenViewport"]
material = ExtResource( 4 )

View File

@ -81,10 +81,10 @@ public class NavigationTests : Spatial
_player.Transform = playerTransform;
ImageTexture newWorldTexture = new ImageTexture();
newWorldTexture.CreateFromImage(_tileWorld.Colormap,
newWorldTexture.CreateFromImage(_tileWorld.ColormapImage,
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.Colormap.GetSize().x);
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.ColormapImage.GetSize().x);
}