2022-12-28 16:22:53 +01:00
|
|
|
using Godot;
|
|
|
|
using System;
|
|
|
|
using System.Linq;
|
2023-05-05 16:26:33 +02:00
|
|
|
using System.Numerics;
|
|
|
|
using System.Diagnostics;
|
|
|
|
using GoDotLog;
|
|
|
|
using Vector2 = Godot.Vector2;
|
|
|
|
using Vector3 = Godot.Vector3;
|
2022-12-28 16:22:53 +01:00
|
|
|
|
|
|
|
public class TileWorld : Spatial
|
|
|
|
{
|
|
|
|
// signals
|
|
|
|
[Signal]
|
|
|
|
delegate void WorldGenerated();
|
|
|
|
|
|
|
|
// public members
|
2023-05-20 21:36:32 +02:00
|
|
|
public float Size = 5;
|
|
|
|
public float HeightScale = 10.0f;
|
2023-05-05 16:26:33 +02:00
|
|
|
public Image Heightmap;
|
|
|
|
public Image Colormap;
|
|
|
|
public int Seed = 0;
|
2022-12-28 16:22:53 +01:00
|
|
|
|
|
|
|
// private members
|
|
|
|
private HexGrid _hexGrid;
|
|
|
|
private Random _tileTypeRandom;
|
2023-05-05 16:26:33 +02:00
|
|
|
private Viewport _offscreenViewport;
|
|
|
|
private TextureRect _offscreenTextureRect;
|
2022-12-28 16:22:53 +01:00
|
|
|
|
|
|
|
// Called when the node enters the scene tree for the first time.
|
|
|
|
public override void _Ready()
|
|
|
|
{
|
|
|
|
_hexGrid = new HexGrid();
|
|
|
|
_tileTypeRandom = new Random();
|
2023-05-05 16:26:33 +02:00
|
|
|
|
|
|
|
_offscreenViewport = (Viewport)GetNode("OffscreenViewport");
|
|
|
|
Debug.Assert(_offscreenViewport != null);
|
2023-05-20 12:27:30 +02:00
|
|
|
_offscreenViewport.Size = new Vector2(Size, Size);
|
2023-05-05 16:26:33 +02:00
|
|
|
_offscreenTextureRect = (TextureRect)GetNode("OffscreenViewport/TextureRect");
|
|
|
|
Debug.Assert(_offscreenTextureRect != null);
|
2023-05-20 12:27:30 +02:00
|
|
|
_offscreenTextureRect.SetSize(new Vector2(Size, Size));
|
2023-05-05 16:26:33 +02:00
|
|
|
|
|
|
|
//VisualServer.Singleton.Connect("frame_post_draw", this, nameof(GenerateNoiseColorMap));
|
2022-12-28 16:22:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void Generate()
|
|
|
|
{
|
2023-05-13 09:29:54 +02:00
|
|
|
//GenerateSimpleMap();
|
2023-05-20 12:27:30 +02:00
|
|
|
//GenerateNoiseMap();
|
|
|
|
|
2022-12-28 16:22:53 +01:00
|
|
|
|
2023-05-05 16:26:33 +02:00
|
|
|
GenerateNoiseColorMap();
|
2023-05-20 12:27:30 +02:00
|
|
|
//GenerateDebugMap();
|
2023-05-05 16:26:33 +02:00
|
|
|
|
2022-12-28 16:22:53 +01:00
|
|
|
EmitSignal("WorldGenerated");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
private void GenerateDebugMap()
|
|
|
|
{
|
|
|
|
Colormap = new Image();
|
|
|
|
Colormap.Create((int)Size, (int)Size, false, Image.Format.Rgba8);
|
|
|
|
|
|
|
|
Heightmap = new Image();
|
|
|
|
Heightmap.Create((int)Size, (int)Size, false, Image.Format.Rf);
|
2023-05-20 21:36:32 +02:00
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
Heightmap.Lock();
|
|
|
|
Colormap.Lock();
|
|
|
|
foreach (int coord_x in Enumerable.Range(0, (int)Size))
|
|
|
|
{
|
|
|
|
foreach (int coord_y in Enumerable.Range(0, (int)Size))
|
|
|
|
{
|
2023-05-20 21:36:32 +02:00
|
|
|
// Colormap.SetPixel(coord_x, coord_y, new Color((float) coord_x, (float) coord_y, 0, 1));
|
2023-05-20 12:27:30 +02:00
|
|
|
float coord_to_height =
|
|
|
|
(float)coord_y / Size * 0f;
|
|
|
|
|
2023-05-20 21:36:32 +02:00
|
|
|
if (coord_x == 1 && coord_y == 4)
|
2023-05-20 12:27:30 +02:00
|
|
|
{
|
|
|
|
coord_to_height = 1;
|
|
|
|
}
|
|
|
|
SetHeightAtOffset(new Vector2(coord_x, coord_y), coord_to_height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Colormap.Unlock();
|
2023-05-20 21:36:32 +02:00
|
|
|
|
|
|
|
ImageTexture imageTexture = new ImageTexture();
|
|
|
|
imageTexture.CreateFromImage(Heightmap);
|
|
|
|
imageTexture.Flags = 0;
|
|
|
|
_offscreenTextureRect.Texture = imageTexture;
|
|
|
|
Colormap.CopyFrom(imageTexture.GetData());
|
2023-05-20 12:27:30 +02:00
|
|
|
}
|
|
|
|
|
2022-12-28 16:22:53 +01:00
|
|
|
private void GenerateSimpleMap()
|
|
|
|
{
|
|
|
|
Heightmap = new Image();
|
2023-05-20 12:27:30 +02:00
|
|
|
Heightmap.Create((int)Size, (int)Size, false, Image.Format.Rf);
|
2022-12-28 16:22:53 +01:00
|
|
|
Heightmap.Lock();
|
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
foreach (int coord_x in Enumerable.Range(-(int) Size / 2, (int)Size))
|
2022-12-28 16:22:53 +01:00
|
|
|
{
|
2023-05-20 12:27:30 +02:00
|
|
|
foreach (int coord_y in Enumerable.Range(-(int) Size / 2, (int)Size))
|
2022-12-28 16:22:53 +01:00
|
|
|
{
|
2023-01-04 22:49:00 +01:00
|
|
|
SetHeightAtOffset(new Vector2(coord_x, coord_y), 5f);
|
2022-12-28 16:22:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void GenerateNoiseMap()
|
|
|
|
{
|
|
|
|
Heightmap = new Image();
|
2023-05-20 12:27:30 +02:00
|
|
|
Heightmap.Create((int)Size, (int)Size, false, Image.Format.Rf);
|
2022-12-28 16:22:53 +01:00
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
NoiseTexture noiseTexture = new NoiseTexture();
|
|
|
|
OpenSimplexNoise noiseGenerator = new OpenSimplexNoise();
|
|
|
|
|
|
|
|
noiseGenerator.Seed = Seed;
|
|
|
|
noiseGenerator.Octaves = 4;
|
|
|
|
noiseGenerator.Period = 20;
|
|
|
|
noiseGenerator.Persistence = 0.1f;
|
|
|
|
noiseGenerator.Lacunarity = 2;
|
2022-12-28 16:22:53 +01:00
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
Heightmap.CopyFrom(noiseGenerator.GetImage((int)Size, (int)Size, null));
|
2022-12-28 16:22:53 +01:00
|
|
|
}
|
2023-05-05 16:26:33 +02:00
|
|
|
|
|
|
|
|
|
|
|
private void GenerateNoiseColorMap()
|
|
|
|
{
|
|
|
|
Colormap = new Image();
|
2023-05-20 12:27:30 +02:00
|
|
|
Colormap.Create((int)Size, (int)Size, false, Image.Format.Rgba8);
|
2023-05-05 16:26:33 +02:00
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
NoiseTexture noiseTexture = new NoiseTexture();
|
|
|
|
OpenSimplexNoise noiseGenerator = new OpenSimplexNoise();
|
2023-05-05 16:26:33 +02:00
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
noiseGenerator.Seed = Seed;
|
|
|
|
noiseGenerator.Octaves = 4;
|
|
|
|
noiseGenerator.Period = 20;
|
|
|
|
noiseGenerator.Persistence = 0.2f;
|
|
|
|
noiseGenerator.Lacunarity = 4;
|
2023-05-11 22:26:06 +02:00
|
|
|
|
2023-05-05 16:26:33 +02:00
|
|
|
ImageTexture imageTexture = new ImageTexture();
|
2023-05-20 12:27:30 +02:00
|
|
|
Heightmap = noiseGenerator.GetSeamlessImage((int)Size);
|
2023-05-11 22:26:06 +02:00
|
|
|
imageTexture.CreateFromImage(Heightmap);
|
2023-05-05 16:26:33 +02:00
|
|
|
imageTexture.Flags = 0;
|
|
|
|
_offscreenTextureRect.Texture = imageTexture;
|
|
|
|
Colormap.CopyFrom(_offscreenViewport.GetTexture().GetData());
|
2023-05-11 22:26:06 +02:00
|
|
|
Heightmap.Lock();
|
2023-05-05 16:26:33 +02:00
|
|
|
}
|
2022-12-28 16:22:53 +01:00
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
|
|
|
|
public void ApplyHeightmap(Image heightmap)
|
|
|
|
{
|
|
|
|
foreach (int coord_x in Enumerable.Range(-(int) Size / 2, (int)Size))
|
|
|
|
{
|
|
|
|
foreach (int coord_y in Enumerable.Range(-(int) Size / 2, (int)Size))
|
|
|
|
{
|
|
|
|
Vector2 textureCoord = OffsetToTextureCoord(new Vector2(coord_x, coord_y));
|
|
|
|
float height = heightmap.GetPixel((int) textureCoord.x, (int) textureCoord.y).r;
|
|
|
|
SetHeightAtOffset(new Vector2(coord_x, coord_y), height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-13 09:29:54 +02:00
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
public bool IsOffsetCoordValid(Vector2 offsetCoord)
|
2022-12-28 16:22:53 +01:00
|
|
|
{
|
2023-05-20 12:27:30 +02:00
|
|
|
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);
|
2022-12-28 16:22:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
public HexTile3D.TileType GetTileTypeAtOffset(Vector2 offsetCoord)
|
2022-12-28 16:22:53 +01:00
|
|
|
{
|
2023-05-20 12:27:30 +02:00
|
|
|
if (!IsOffsetCoordValid(offsetCoord))
|
2022-12-28 16:22:53 +01:00
|
|
|
{
|
|
|
|
return HexTile3D.TileType.Undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
return HexTile3D.ValidTileTypes[_tileTypeRandom.Next(HexTile3D.ValidTileTypes.Length)];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
public Vector2 OffsetToTextureCoord(Vector2 offsetCoord)
|
2022-12-28 16:22:53 +01:00
|
|
|
{
|
2023-05-20 21:36:32 +02:00
|
|
|
Vector2 textureCoord = (offsetCoord - Vector2.One * (Mathf.Floor(Size / 2) + 1)) % (Vector2.One * Size);
|
2023-05-20 12:27:30 +02:00
|
|
|
if (textureCoord[0] < 0)
|
2022-12-28 16:22:53 +01:00
|
|
|
{
|
2023-05-20 12:27:30 +02:00
|
|
|
textureCoord[0] += Size;
|
2022-12-28 16:22:53 +01:00
|
|
|
}
|
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
if (textureCoord[1] < 0)
|
2022-12-28 16:22:53 +01:00
|
|
|
{
|
2023-05-20 12:27:30 +02:00
|
|
|
textureCoord[1] += Size;
|
2022-12-28 16:22:53 +01:00
|
|
|
}
|
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
return textureCoord;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetHeightAtOffset(Vector2 offsetCoord, float height)
|
|
|
|
{
|
|
|
|
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
|
|
|
|
|
|
|
|
Heightmap.SetPixel((int) textureCoord.x, (int) textureCoord.y, new Color(height, 0f, 0f));
|
|
|
|
}
|
|
|
|
|
|
|
|
public float GetHeightAtOffset(Vector2 offsetCoord)
|
|
|
|
{
|
|
|
|
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
|
2023-04-30 15:33:46 +02:00
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
return Heightmap.GetPixel((int)textureCoord.x, (int)(textureCoord.y)).r * HeightScale;
|
2022-12-28 16:22:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
public Vector2 WorldToOffsetCoords(Vector3 worldCoord)
|
2022-12-28 16:22:53 +01:00
|
|
|
{
|
2023-05-20 12:27:30 +02:00
|
|
|
return _hexGrid.GetHexAt(new Vector2(worldCoord.x, worldCoord.z)).OffsetCoords;
|
2022-12-28 16:22:53 +01:00
|
|
|
}
|
|
|
|
|
2023-01-03 17:46:55 +01:00
|
|
|
|
2023-05-20 12:27:30 +02:00
|
|
|
public Vector3 GetTileWorldCenterFromOffset(Vector2 offsetCoord)
|
2023-01-03 17:46:55 +01:00
|
|
|
{
|
2023-05-20 12:27:30 +02:00
|
|
|
Vector2 tileCenter = _hexGrid.GetHexCenterFromOffset(offsetCoord);
|
2023-01-03 17:46:55 +01:00
|
|
|
|
|
|
|
return new Vector3(
|
|
|
|
tileCenter.x,
|
2023-05-20 12:27:30 +02:00
|
|
|
GetHeightAtOffset(offsetCoord),
|
2023-01-03 17:46:55 +01:00
|
|
|
tileCenter.y);
|
|
|
|
}
|
2022-12-28 16:22:53 +01:00
|
|
|
}
|