diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..63295c3 Binary files /dev/null and b/.DS_Store differ diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f28239b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*] +charset = utf-8 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..5b0d1a4 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf +*.png filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0af181c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# Godot 4+ specific ignores +.godot/ +/android/ diff --git a/.idea/.idea.Frontiers/.idea/.gitignore b/.idea/.idea.Frontiers/.idea/.gitignore new file mode 100644 index 0000000..df64557 --- /dev/null +++ b/.idea/.idea.Frontiers/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/projectSettingsUpdater.xml +/.idea.Frontiers.iml +/modules.xml +/contentModel.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.Frontiers/.idea/.name b/.idea/.idea.Frontiers/.idea/.name new file mode 100644 index 0000000..ff0474e --- /dev/null +++ b/.idea/.idea.Frontiers/.idea/.name @@ -0,0 +1 @@ +Frontiers \ No newline at end of file diff --git a/.idea/.idea.Frontiers/.idea/encodings.xml b/.idea/.idea.Frontiers/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.Frontiers/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.Frontiers/.idea/indexLayout.xml b/.idea/.idea.Frontiers/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.Frontiers/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.Frontiers/.idea/libraries/GdSdk_Master.xml b/.idea/.idea.Frontiers/.idea/libraries/GdSdk_Master.xml new file mode 100644 index 0000000..6875f0b --- /dev/null +++ b/.idea/.idea.Frontiers/.idea/libraries/GdSdk_Master.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.Frontiers/.idea/vcs.xml b/.idea/.idea.Frontiers/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/.idea.Frontiers/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Frontiers.csproj b/Frontiers.csproj new file mode 100644 index 0000000..8eebc1d --- /dev/null +++ b/Frontiers.csproj @@ -0,0 +1,6 @@ + + + net8.0 + true + + \ No newline at end of file diff --git a/Frontiers.csproj.DotSettings b/Frontiers.csproj.DotSettings new file mode 100644 index 0000000..2d39c02 --- /dev/null +++ b/Frontiers.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/Frontiers.sln b/Frontiers.sln new file mode 100644 index 0000000..9140ce2 --- /dev/null +++ b/Frontiers.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Frontiers", "Frontiers.csproj", "{F33DFCC0-769F-49F6-9FEF-F64EF49FBEAD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + ExportDebug|Any CPU = ExportDebug|Any CPU + ExportRelease|Any CPU = ExportRelease|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F33DFCC0-769F-49F6-9FEF-F64EF49FBEAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F33DFCC0-769F-49F6-9FEF-F64EF49FBEAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F33DFCC0-769F-49F6-9FEF-F64EF49FBEAD}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU + {F33DFCC0-769F-49F6-9FEF-F64EF49FBEAD}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU + {F33DFCC0-769F-49F6-9FEF-F64EF49FBEAD}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU + {F33DFCC0-769F-49F6-9FEF-F64EF49FBEAD}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU + EndGlobalSection +EndGlobal diff --git a/Frontiers.sln.DotSettings.user b/Frontiers.sln.DotSettings.user new file mode 100644 index 0000000..8d1f46e --- /dev/null +++ b/Frontiers.sln.DotSettings.user @@ -0,0 +1,2 @@ + + ForceIncluded \ No newline at end of file diff --git a/Source/CameraController.cs b/Source/CameraController.cs new file mode 100644 index 0000000..e1efe4e --- /dev/null +++ b/Source/CameraController.cs @@ -0,0 +1,117 @@ +using Godot; + +public partial class CameraController : Camera2D +{ + [Export] public float ZoomSpeed = 1.1f; + [Export] public float MinZoom = 0.01f; + [Export] public float MaxZoom = 5.0f; + [Export] public bool EnableRotation = false; + [Export] public float RotationSpeed = 0.01f; + [Export] public float PanSmoothing = 0.1f; + + private bool _isDragging = false; + private Vector2 _dragStartMousePos; + private Vector2 _dragStartCameraPos; + private bool _isRotating = false; + private Vector2 _lastMousePosition; + + public override void _Ready() + { + Enabled = true; + } + + public override void _UnhandledInput(InputEvent @event) + { + HandleZoom(@event); + HandlePanning(@event); + HandleRotation(@event); + } + + private void HandleZoom(InputEvent @event) + { + if (@event is InputEventMouseButton mouseButton && mouseButton.Pressed) + { + Vector2 mouseWorldPos = GetGlobalMousePosition(); + + if (mouseButton.ButtonIndex == MouseButton.WheelUp) + { + var newZoom = Zoom * ZoomSpeed; + if (newZoom.X <= MaxZoom) + { + ZoomToPoint(newZoom, mouseWorldPos); + } + } + else if (mouseButton.ButtonIndex == MouseButton.WheelDown) + { + var newZoom = Zoom / ZoomSpeed; + if (newZoom.X >= MinZoom) + { + ZoomToPoint(newZoom, mouseWorldPos); + } + } + } + } + + private void ZoomToPoint(Vector2 newZoom, Vector2 worldPoint) + { + Vector2 viewportCenter = GetViewportRect().Size / 2; + Vector2 offsetFromCenter = (GetGlobalMousePosition() - GlobalPosition); + + Zoom = newZoom; + + Vector2 newOffsetFromCenter = offsetFromCenter / (newZoom.X / Zoom.X); + GlobalPosition += offsetFromCenter - newOffsetFromCenter; + } + + private void HandlePanning(InputEvent @event) + { + if (@event is InputEventMouseButton mouseButton) + { + if (mouseButton.ButtonIndex == MouseButton.Left) + { + if (mouseButton.Pressed) + { + _isDragging = true; + _dragStartMousePos = mouseButton.GlobalPosition; + _dragStartCameraPos = GlobalPosition; + } + else + { + _isDragging = false; + } + } + } + else if (@event is InputEventMouseMotion mouseMotion && _isDragging) + { + Vector2 mouseDelta = _dragStartMousePos - mouseMotion.GlobalPosition; + GlobalPosition = _dragStartCameraPos + mouseDelta / Zoom; + } + } + + private void HandleRotation(InputEvent @event) + { + if (!EnableRotation) return; + + if (@event is InputEventMouseButton mouseButton) + { + if (mouseButton.ButtonIndex == MouseButton.Right) + { + if (mouseButton.Pressed) + { + _isRotating = true; + _lastMousePosition = mouseButton.GlobalPosition; + } + else + { + _isRotating = false; + } + } + } + else if (@event is InputEventMouseMotion mouseMotion && _isRotating) + { + var delta = _lastMousePosition - mouseMotion.GlobalPosition; + Rotation += delta.X * RotationSpeed; + _lastMousePosition = mouseMotion.GlobalPosition; + } + } +} \ No newline at end of file diff --git a/Source/CameraController.cs.uid b/Source/CameraController.cs.uid new file mode 100644 index 0000000..02a2a2b --- /dev/null +++ b/Source/CameraController.cs.uid @@ -0,0 +1 @@ +uid://ceahximwi24jm diff --git a/Source/Tile.cs b/Source/Tile.cs new file mode 100644 index 0000000..7d71cb0 --- /dev/null +++ b/Source/Tile.cs @@ -0,0 +1,284 @@ +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Godot; + +public partial class Tile : Node2D +{ + private Vector2I _size; + private Vector2I _chunkId; + private World _world; + public CancellationToken CancellationToken { get; set; } + + public Tile(Vector2I size, Vector2I chunkId, World world) + { + _size = size; + _chunkId = chunkId; + _world = world; + } + + public override void _Ready() + { + loadTile(); + } + + void loadTile() + { + + Image image = Image.CreateEmpty(_size.X, _size.Y, false, Image.Format.Rgba8); + + Vector2I heightMapResolution = new Vector2I( + _world.HeightMapImage.GetWidth(), + _world.HeightMapImage.GetHeight() + ); + + Vector2I mapResolution = _world.ChunksPerAxis * _world.TileSize; + Vector2I tileOffset = new Vector2I( + _chunkId.X * _world.TileSize, + _chunkId.Y * _world.TileSize + ); + + // Store parameters locally to avoid changes during generation + float rockThreshold = _world.RockThreshold; + float snowHeightThreshold = _world.SnowHeightThreshold; + float waterThreshold = _world.WaterThreshold; + float desertMoistureThreshold = _world.DesertMoistureThreshold; + float desertTemperatureThreshold = _world.DesertTemperatureThreshold; + + DebugType debugType = _world.DebugType; + + // Run in thread + Task.Run(() => + { + try + { + for (int x = 0; x < _size.X; x++) + { + if (CancellationToken.IsCancellationRequested) return; + + for (int y = 0; y < _size.Y; y++) + { + if (CancellationToken.IsCancellationRequested) return; + + Vector2I pixelOffset = new Vector2I( + x + tileOffset.X, + y + tileOffset.Y + ); + + float heightValue = GetValueAtMapPosition(pixelOffset); + float heatValue = GetHeatAtMapPosition(pixelOffset); + float moistureValue = GetMoistureAtMapPosition(pixelOffset); + + // Get the max difference between the coord and its neighbors + float maxDiff = 0.0f; + float centerHeight = heightValue; + bool bordersSea = false; + for (int offsetX = -1; offsetX <= 1; offsetX++) + { + for (int offsetY = -1; offsetY <= 1; offsetY++) + { + if (offsetX == 0 && offsetY == 0) + continue; + + Vector2I neighborCoords = new Vector2I( + pixelOffset.X + offsetX, + pixelOffset.Y + offsetY + ); + + float neighborHeight = GetValueAtMapPosition(neighborCoords); + + if (IsSeaAtMapPosition(neighborCoords, waterThreshold)) + { + bordersSea = true; + } + + float diff = Mathf.Abs(centerHeight - neighborHeight); + if (diff > maxDiff) + { + maxDiff = diff; + } + } + } + + + + if (debugType == DebugType.None) + { + + // Grass (default) + image.SetPixel(x, y, Color.FromString("#bed58a", Colors.Purple)); + + if (IsSeaAtMapPosition(pixelOffset, waterThreshold)) + { + // Water + image.SetPixel(x, y, Color.FromString("#4380b0", Colors.Purple)); + continue; + } + + if (moistureValue < desertMoistureThreshold && heatValue > desertTemperatureThreshold) + { + // Desert + image.SetPixel(x, y, Color.FromString("#edc9af", Colors.Purple)); + } + + if (bordersSea) + { + // Beach + image.SetPixel(x, y, Color.FromString("#808080", Colors.Purple)); + continue; + } + + if (heightValue > snowHeightThreshold) + { + // Snow + image.SetPixel(x, y, Color.FromString("#f4f4f4", Colors.Purple)); + } + + // We want steep areas to be grey for rock. + if (maxDiff > rockThreshold) + { + // Steep area + image.SetPixel(x, y, Color.FromString("#e4d3a6", Colors.Purple)); + continue; + } + + } + else if (debugType == DebugType.Height) + { + float grayValue = heightValue; + image.SetPixel(x, y, new Color(grayValue, grayValue, grayValue)); + } + else if (debugType == DebugType.Slope) + { + float grayValue = maxDiff * 5.0f; + image.SetPixel(x, y, new Color(grayValue, grayValue, grayValue)); + } else if (debugType == DebugType.Temperature) + { + image.SetPixel(x, y, new Color(heatValue, heatValue, heatValue)); + } else if (debugType == DebugType.Moisture) + { + image.SetPixel(x, y, new Color(moistureValue, moistureValue, moistureValue)); + } + + + + + } + } + + if (!CancellationToken.IsCancellationRequested) + { + // Create a texture from the image and assign it to a Sprite2D + Texture2D texture = ImageTexture.CreateFromImage(image); + Sprite2D sprite = new Sprite2D(); + sprite.Texture = texture; + sprite.TextureFilter = TextureFilterEnum.Nearest; + CallDeferred("add_child", sprite); + } + } + catch (OperationCanceledException) + { + // Generation was cancelled, do nothing + } + }, CancellationToken); + + } + + // Terrain Query Methods + private float GetValueAtMapPosition(Vector2I position) + { + + // Clamp position to map bounds + position.X = Mathf.Clamp(position.X, 0, _world.ChunksPerAxis.X * _world.TileSize - 1); + position.Y = Mathf.Clamp(position.Y, 0, _world.ChunksPerAxis.Y * _world.TileSize - 1); + + Vector2I heightMapResolution = new Vector2I( + _world.HeightMapImage.GetWidth(), + _world.HeightMapImage.GetHeight() + ); + + Vector2I mapResolution = _world.ChunksPerAxis * _world.TileSize; + + Vector2 mapDelta = (Vector2) position / (Vector2) mapResolution; + + Vector2I heightMapCoords = new Vector2I( + (int)(mapDelta.X * heightMapResolution.X), + (int)(mapDelta.Y * heightMapResolution.Y) + ); + + Color hmColor = _world.HeightMapImage.GetPixel(heightMapCoords.X, heightMapCoords.Y); + + return hmColor.R; + } + + private bool isSeaAtMapPosition(Vector2I position) + { + float heightValue = GetValueAtMapPosition(position); + return heightValue <= _world.WaterThreshold; + } + + private bool IsSeaAtMapPosition(Vector2I position, float waterThreshold) + { + float heightValue = GetValueAtMapPosition(position); + return heightValue <= waterThreshold; + } + + private FastNoiseLite _heatNoise = null; + private float GetHeatAtMapPosition(Vector2I position) + { + + if (_heatNoise == null) + { + _heatNoise = new FastNoiseLite(); + _heatNoise.SetNoiseType(FastNoiseLite.NoiseTypeEnum.Perlin); + _heatNoise.SetFrequency(1/_world.TemperatureNoiseFrequency); + _heatNoise.SetSeed(1738); + } + + float heat = _heatNoise.GetNoise2D(position.X, position.Y); + heat *= 0.2f; + + // Fall off towards the poles. Use sine function for a globe effect. + float mapResolutionY = _world.ChunksPerAxis.Y * _world.TileSize; + float latitudeFactor = Mathf.Sin(Mathf.Pi * position.Y / mapResolutionY); + heat = latitudeFactor + heat; + heat = Mathf.Clamp( + heat, + 0.0f, + 1.0f + ); + + return heat; + } + + private FastNoiseLite _moistureNoise = null; + private float GetMoistureAtMapPosition(Vector2I position) + { + + if (_moistureNoise == null) + { + _moistureNoise = new FastNoiseLite(); + _moistureNoise.SetNoiseType(FastNoiseLite.NoiseTypeEnum.Perlin); + _moistureNoise.SetFrequency(1/_world.MoistureNoiseFrequency); + _moistureNoise.SetSeed(1337); + } + + float moisture = _moistureNoise.GetNoise2D(position.X, position.Y); + moisture *= 0.2f; + + // Fall off towards the poles. Use sine function for a globe effect. + float mapResolutionY = _world.ChunksPerAxis.Y * _world.TileSize; + float latitudeFactor = Mathf.Sin(Mathf.Pi * position.Y / mapResolutionY); + moisture = latitudeFactor + moisture; + moisture = Mathf.Clamp( + moisture, + 0.0f, + 1.0f + ); + + + return moisture; + } + +} diff --git a/Source/Tile.cs.uid b/Source/Tile.cs.uid new file mode 100644 index 0000000..d0412b8 --- /dev/null +++ b/Source/Tile.cs.uid @@ -0,0 +1 @@ +uid://d1af74387s3fk diff --git a/Source/World.cs b/Source/World.cs new file mode 100644 index 0000000..9f7b88a --- /dev/null +++ b/Source/World.cs @@ -0,0 +1,289 @@ +using Godot; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Godot.Collections; + +public enum DebugType +{ + None, + Slope, + Height, + Temperature, + Moisture +} + +[Tool] +public partial class World : Node2D +{ + + + private int _chunksX = 32; + [Export] + public int ChunkXCount + { + get => _chunksX; + set + { + _chunksX = value; + LoadTiles(); + } + } + + public Vector2I ChunksPerAxis + { + get + { + + if (HeightMapImage == null) + { + return new Vector2I(_chunksX, _chunksX); + } + + Vector2I heightMapResolution = new Vector2I(HeightMapImage.GetWidth(), HeightMapImage.GetHeight()); + int chunksY = (int)(heightMapResolution.Y / (heightMapResolution.X / _chunksX)); + return new Vector2I(_chunksX, chunksY); + } + } + + private int _tileSize = 96; + [Export] + public int TileSize + { + get => _tileSize; + set + { + _tileSize = value; + LoadTiles(); + } + } + + [Export] + public Texture2D HeightMapTexture; + + private float _rockThreshold = 0.05f; + [Export] + public float RockThreshold + { + get => _rockThreshold; + set + { + _rockThreshold = value; + LoadTiles(); + } + } + + private float _snowHeightThreshold = 0.8f; + [Export] + public float SnowHeightThreshold + { + get => _snowHeightThreshold; + set + { + _snowHeightThreshold = value; + LoadTiles(); + } + } + + private float _waterThreshold = 0.0f; + [Export] + public float WaterThreshold + { + get => _waterThreshold; + set + { + _waterThreshold = value; + LoadTiles(); + } + } + + private float _desertTemperatureThreshold = 0.7f; + [Export] + public float DesertTemperatureThreshold + { + get => _desertTemperatureThreshold; + set + { + _desertTemperatureThreshold = value; + LoadTiles(); + } + } + + private float _desertMoistureThreshold = 0.3f; + [Export] + public float DesertMoistureThreshold + { + get => _desertMoistureThreshold; + set + { + _desertMoistureThreshold = value; + LoadTiles(); + } + } + + private float _temperatureNoiseFrequency = 0.01f; + [Export] + public float TemperatureNoiseFrequency + { + get => _temperatureNoiseFrequency; + set + { + _temperatureNoiseFrequency = value; + LoadTiles(); + } + } + + private float _moistureNoiseFrequency = 0.01f; + [Export] + public float MoistureNoiseFrequency + { + get => _moistureNoiseFrequency; + set + { + _moistureNoiseFrequency = value; + LoadTiles(); + } + } + + private DebugType _debugType = DebugType.None; + [Export] + public DebugType DebugType + { + get => _debugType; + set + { + _debugType = value; + LoadTiles(); + } + } + + + + ConcurrentDictionary _tiles = new ConcurrentDictionary(); + private CancellationTokenSource _cancellationTokenSource; + + public World() + { + + } + + public override void _Ready() + { + + // If the height map image is not assigned, log an error and return + if (HeightMapTexture == null) + { + GD.PrintErr("Height map image is not assigned."); + return; + } + + LoadTiles(); + } + + private void LoadTiles() + { + // Check if HeightMapImage is available + if (HeightMapImage == null) + { + GD.PrintErr("Cannot load tiles: HeightMapImage is null"); + return; + } + + // Cancel any existing generation + _cancellationTokenSource?.Cancel(); + _cancellationTokenSource = new CancellationTokenSource(); + var cancellationToken = _cancellationTokenSource.Token; + + // Clear existing tiles + foreach (var tile in _tiles.Values) + { + tile.Visible = false; + + // Delete and delete its children + foreach (Node child in tile.GetChildren()) + { + child.QueueFree(); + } + tile.QueueFree(); + + } + _tiles.Clear(); + + int scale = 1; + + // Store local copies of parameters to avoid them changing mid-generation + int tileSize = TileSize; + int chunksX = _chunksX; + + // Get the resolution of the height map image + Vector2I heightMapResolution = new Vector2I(HeightMapImage.GetWidth(), HeightMapImage.GetHeight()); + + // Calculate the number of chunks in the Y direction based on the aspect ratio + int chunksY = (int)(heightMapResolution.Y / (heightMapResolution.X / _chunksX)); + + // Loop through each chunk position and create a Tile + Task.Run(() => + { + try + { + for (int x = 0; x < chunksX; x++) + { + if (cancellationToken.IsCancellationRequested) return; + + Parallel.For(0, chunksY, new ParallelOptions { CancellationToken = cancellationToken }, y => + { + if (cancellationToken.IsCancellationRequested) return; + + Vector2I chunkId = new Vector2I(x, y); + + Tile tile = new Tile(new Vector2I(tileSize, tileSize), chunkId, this); + tile.CancellationToken = cancellationToken; + tile.Position = new Vector2(chunkId.X * tileSize, chunkId.Y * tileSize) * scale; + tile.Scale = new Vector2(scale, scale); + + if (!cancellationToken.IsCancellationRequested) + { + CallDeferred("add_child", tile); + _tiles[chunkId] = tile; + GD.Print("Loaded tile at chunk " + chunkId); + } + }); + } + } + catch (OperationCanceledException) + { + GD.Print("Tile generation cancelled"); + } + }, cancellationToken); + + } + + private Image _heightMapCache; + public Image HeightMapImage + { + get + { + // If not cached, load and cache it + if (_heightMapCache == null && HeightMapTexture != null) + { + _heightMapCache = HeightMapTexture.GetImage(); + + // If GetImage() returns null, try loading directly from file + if (_heightMapCache == null && HeightMapTexture.ResourcePath != "") + { + _heightMapCache = Image.LoadFromFile(HeightMapTexture.ResourcePath); + + if (_heightMapCache == null) + { + GD.PushError($"Could not load heightmap from {HeightMapTexture.ResourcePath}"); + } + } + } + + return _heightMapCache; + } + } +} diff --git a/Source/World.cs.uid b/Source/World.cs.uid new file mode 100644 index 0000000..ac034fc --- /dev/null +++ b/Source/World.cs.uid @@ -0,0 +1 @@ +uid://btqabtn0awg6k diff --git a/assets/World_Elevation_Map_8_bit_(World_Height_map)_(alterative_version).png b/assets/World_Elevation_Map_8_bit_(World_Height_map)_(alterative_version).png new file mode 100644 index 0000000..b263a2a --- /dev/null +++ b/assets/World_Elevation_Map_8_bit_(World_Height_map)_(alterative_version).png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c8535a6e76f143a8c15595aa398a86753adf7193ee22b3c0a282c3b3d14f9aba +size 33849722 diff --git a/assets/World_Elevation_Map_8_bit_(World_Height_map)_(alterative_version).png.import b/assets/World_Elevation_Map_8_bit_(World_Height_map)_(alterative_version).png.import new file mode 100644 index 0000000..05edc0a --- /dev/null +++ b/assets/World_Elevation_Map_8_bit_(World_Height_map)_(alterative_version).png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dteqog3a5k8qx" +path="res://.godot/imported/World_Elevation_Map_8_bit_(World_Height_map)_(alterative_version).png-f039a3c89cf0c7ad5d067a47b56cbf8e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/World_Elevation_Map_8_bit_(World_Height_map)_(alterative_version).png" +dest_files=["res://.godot/imported/World_Elevation_Map_8_bit_(World_Height_map)_(alterative_version).png-f039a3c89cf0c7ad5d067a47b56cbf8e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/World_elevation_map.png b/assets/World_elevation_map.png new file mode 100644 index 0000000..d8e0e7a --- /dev/null +++ b/assets/World_elevation_map.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f91a66e40335d9d4315abee2c0ed0b155481f71c340fadca2486f3f761a06a23 +size 75282262 diff --git a/assets/World_elevation_map.png.import b/assets/World_elevation_map.png.import new file mode 100644 index 0000000..09da52a --- /dev/null +++ b/assets/World_elevation_map.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cthrxmyms6rxj" +path="res://.godot/imported/World_elevation_map.png-ffb15608784624fa8e00c287e76ba4a3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/World_elevation_map.png" +dest_files=["res://.godot/imported/World_elevation_map.png-ffb15608784624fa8e00c287e76ba4a3.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/gebco_08_rev_elev_21600x10800.png b/assets/gebco_08_rev_elev_21600x10800.png new file mode 100644 index 0000000..2adb2c9 --- /dev/null +++ b/assets/gebco_08_rev_elev_21600x10800.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a70590d40dd7b9c69b9ab359d1dc4475ce97c1d2d13625223b248364112c699 +size 18414843 diff --git a/assets/gebco_08_rev_elev_21600x10800.png.import b/assets/gebco_08_rev_elev_21600x10800.png.import new file mode 100644 index 0000000..b3662d1 --- /dev/null +++ b/assets/gebco_08_rev_elev_21600x10800.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cfq68ehcuvoya" +path="res://.godot/imported/gebco_08_rev_elev_21600x10800.png-f55daf6de01cca738c16dcab8f2b72f3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/gebco_08_rev_elev_21600x10800.png" +dest_files=["res://.godot/imported/gebco_08_rev_elev_21600x10800.png-f55daf6de01cca738c16dcab8f2b72f3.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..9d8b7fa --- /dev/null +++ b/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/icon.svg.import b/icon.svg.import new file mode 100644 index 0000000..ddc4a7c --- /dev/null +++ b/icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://coj5oieh63qxm" +path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/main.tscn b/main.tscn new file mode 100644 index 0000000..80adc4e --- /dev/null +++ b/main.tscn @@ -0,0 +1,21 @@ +[gd_scene load_steps=4 format=3 uid="uid://c10nqwr7qp0ai"] + +[ext_resource type="Script" uid="uid://btqabtn0awg6k" path="res://Source/World.cs" id="1_0xm2m"] +[ext_resource type="Script" uid="uid://ceahximwi24jm" path="res://Source/CameraController.cs" id="3_camera"] +[ext_resource type="Texture2D" uid="uid://dteqog3a5k8qx" path="res://assets/World_Elevation_Map_8_bit_(World_Height_map)_(alterative_version).png" id="3_h2yge"] + +[node name="Main" type="Node2D"] + +[node name="CameraController" type="Camera2D" parent="."] +script = ExtResource("3_camera") + +[node name="World" type="Node2D" parent="."] +script = ExtResource("1_0xm2m") +ChunkXCount = 16 +TileSize = 128 +HeightMapTexture = ExtResource("3_h2yge") +RockThreshold = 0.04 +SnowHeightThreshold = 0.32 +WaterThreshold = 0.24 +DesertTemperatureThreshold = 0.82 +DesertMoistureThreshold = 0.985 diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..13840c6 --- /dev/null +++ b/project.godot @@ -0,0 +1,20 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="Frontiers" +run/main_scene="uid://c10nqwr7qp0ai" +config/features=PackedStringArray("4.4", "C#", "Forward Plus") +config/icon="res://icon.svg" + +[dotnet] + +project/assembly_name="Frontiers"