using Godot; using System; using System.Linq; using System.Numerics; using System.Diagnostics; using GoDotLog; using Vector2 = Godot.Vector2; using Vector3 = Godot.Vector3; public class TileWorld : Spatial { // signals [Signal] delegate void WorldGenerated(); // public members public Vector2 Size = new Vector2(100, 100); public float HeightScale = 2; public Image Heightmap; public Image Colormap; public int Seed = 0; // private members private HexGrid _hexGrid; private Random _tileTypeRandom; private Viewport _offscreenViewport; private TextureRect _offscreenTextureRect; // Called when the node enters the scene tree for the first time. public override void _Ready() { _hexGrid = new HexGrid(); _tileTypeRandom = new Random(); _offscreenViewport = (Viewport)GetNode("OffscreenViewport"); Debug.Assert(_offscreenViewport != null); _offscreenViewport.Size = Size; _offscreenTextureRect = (TextureRect)GetNode("OffscreenViewport/TextureRect"); Debug.Assert(_offscreenTextureRect != null); _offscreenTextureRect.SetSize(Size); //VisualServer.Singleton.Connect("frame_post_draw", this, nameof(GenerateNoiseColorMap)); } public void Generate() { GenerateSimpleMap(); // GenerateNoiseMap(); GenerateNoiseColorMap(); EmitSignal("WorldGenerated"); } private void GenerateSimpleMap() { Heightmap = new Image(); Heightmap.Create((int)Size.x, (int)Size.y, false, Image.Format.Rf); Heightmap.Lock(); foreach (int coord_x in Enumerable.Range(-(int) Size.x / 2, (int)Size.x)) { foreach (int coord_y in Enumerable.Range(-(int) Size.y / 2, (int)Size.y)) { SetHeightAtOffset(new Vector2(coord_x, coord_y), 5f); } } } private void GenerateNoiseMap() { Heightmap = new Image(); Heightmap.Create((int)Size.x, (int)Size.y, false, Image.Format.Rf); NoiseTexture noise_texture = new NoiseTexture(); OpenSimplexNoise noise_generator = new OpenSimplexNoise(); noise_generator.Seed = Seed; noise_generator.Octaves = 4; noise_generator.Period = 20; noise_generator.Persistence = 0.1f; noise_generator.Lacunarity = 2; Heightmap.CopyFrom(noise_generator.GetImage((int)Size.x, (int)Size.y, null)); } private void GenerateNoiseColorMap() { Colormap = new Image(); Colormap.Create((int)Size.x, (int)Size.y, false, Image.Format.Rgba8); NoiseTexture noise_texture = new NoiseTexture(); OpenSimplexNoise noise_generator = new OpenSimplexNoise(); noise_generator.Seed = Seed; noise_generator.Octaves = 4; noise_generator.Period = 20; noise_generator.Persistence = 0.2f; noise_generator.Lacunarity = 4; ImageTexture imageTexture = new ImageTexture(); Heightmap.Unlock(); Heightmap = noise_generator.GetSeamlessImage((int)Size.x); imageTexture.CreateFromImage(Heightmap); imageTexture.Flags = 0; _offscreenTextureRect.Texture = imageTexture; Colormap.CopyFrom(_offscreenViewport.GetTexture().GetData()); Heightmap.Lock(); } private void ApplyHeightMap() { } public bool IsOffsetCoordValid(Vector2 offset_coord) { return ((int)Math.Clamp(offset_coord.x, -Size.x / 2, Size.x / 2 - 1) == (int)offset_coord.x && (int)Math.Clamp(offset_coord.y, -Size.y / 2, Size.y / 2 - 1) == (int)offset_coord.y); } public HexTile3D.TileType GetTileTypeAtOffset(Vector2 offset_coord) { if (!IsOffsetCoordValid(offset_coord)) { return HexTile3D.TileType.Undefined; } return HexTile3D.ValidTileTypes[_tileTypeRandom.Next(HexTile3D.ValidTileTypes.Length)]; } public void SetHeightAtOffset(Vector2 offset_coord, float height) { if (!IsOffsetCoordValid(offset_coord)) { return; } Vector2 texture_coord = offset_coord + Size / 2; Heightmap.SetPixel((int) texture_coord.x, (int) texture_coord.y, new Color(height / HeightScale, 0f, 0f)); } public float GetHeightAtOffset(Vector2 offset_coord) { if (!IsOffsetCoordValid(offset_coord)) { return 0; } Vector2 texture_coord = offset_coord + Size / 2; return Heightmap.GetPixel((int)texture_coord.x, (int)(texture_coord.y)).r * HeightScale - HeightScale * 0.5f ; } public Vector2 WorldToOffsetCoords(Vector3 world_coord) { return _hexGrid.GetHexAt(new Vector2(world_coord.x, world_coord.z)).OffsetCoords; } public Vector3 GetTileWorldCenterFromOffset(Vector2 offset_coord) { Vector2 tileCenter = _hexGrid.GetHexCenterFromOffset(offset_coord); return new Vector3( tileCenter.x, GetHeightAtOffset(offset_coord), tileCenter.y); } }