extract logical tile grid to resource #6

This commit is contained in:
Cat Flynn 2022-12-10 15:47:44 +00:00 committed by ktyl
parent c44ab10712
commit cf03021c2a
9 changed files with 198 additions and 104 deletions

View File

@ -7,7 +7,7 @@
[ext_resource path="res://nodes/interaction_modes/interaction_mode.tscn" type="PackedScene" id=5] [ext_resource path="res://nodes/interaction_modes/interaction_mode.tscn" type="PackedScene" id=5]
[ext_resource path="res://nodes/ui/build_mode_ui.tscn" type="PackedScene" id=6] [ext_resource path="res://nodes/ui/build_mode_ui.tscn" type="PackedScene" id=6]
[ext_resource path="res://nodes/interaction_modes/build_mode.tscn" type="PackedScene" id=7] [ext_resource path="res://nodes/interaction_modes/build_mode.tscn" type="PackedScene" id=7]
[ext_resource path="res://resources/tile_types/wild.tres" type="Resource" id=8] [ext_resource path="res://resources/tiles/tiles.tres" type="Resource" id=8]
[ext_resource path="res://nodes/ui/mode_selection_ui.tscn" type="PackedScene" id=9] [ext_resource path="res://nodes/ui/mode_selection_ui.tscn" type="PackedScene" id=9]
[sub_resource type="Curve" id=1] [sub_resource type="Curve" id=1]
@ -20,7 +20,7 @@ _autoTick = true
[node name="Grid" parent="." instance=ExtResource( 1 )] [node name="Grid" parent="." instance=ExtResource( 1 )]
DiffusionCoefficient = 0.1 DiffusionCoefficient = 0.1
_startTileTypeResource = ExtResource( 8 ) _tileGridResource = ExtResource( 8 )
[node name="Cursor" parent="." instance=ExtResource( 2 )] [node name="Cursor" parent="." instance=ExtResource( 2 )]
Grid = NodePath("../Grid") Grid = NodePath("../Grid")

View File

@ -1,7 +1,7 @@
[gd_scene load_steps=3 format=2] [gd_scene load_steps=3 format=2]
[ext_resource path="res://scripts/interaction_modes/BuildMode.cs" type="Script" id=1] [ext_resource path="res://scripts/interaction_modes/BuildMode.cs" type="Script" id=1]
[ext_resource path="res://resources/tile_types/tile_type_collections/buildable_tiles.tres" type="Resource" id=2] [ext_resource path="res://resources/tiles/tile_types/tile_type_collections/buildable_tiles.tres" type="Resource" id=2]
[node name="Build Mode" type="Node"] [node name="Build Mode" type="Node"]
script = ExtResource( 1 ) script = ExtResource( 1 )

View File

@ -8,4 +8,4 @@ Name = "Developed"
BuildLabel = "[D]eveloped" BuildLabel = "[D]eveloped"
Key = 68 Key = 68
Color = Color( 0.372549, 0.372549, 0.372549, 1 ) Color = Color( 0.372549, 0.372549, 0.372549, 1 )
HeatGeneration = 0.1 HeatGeneration = 0.5

View File

@ -1,7 +1,7 @@
[gd_resource type="Resource" load_steps=3 format=2] [gd_resource type="Resource" load_steps=3 format=2]
[ext_resource path="res://scripts/tile/TileTypeCollection.cs" type="Script" id=1] [ext_resource path="res://scripts/tile/TileTypeCollection.cs" type="Script" id=1]
[ext_resource path="res://resources/tile_types/developed.tres" type="Resource" id=2] [ext_resource path="res://resources/tiles/tile_types/developed.tres" type="Resource" id=2]
[resource] [resource]
script = ExtResource( 1 ) script = ExtResource( 1 )

View File

@ -0,0 +1,9 @@
[gd_resource type="Resource" load_steps=3 format=2]
[ext_resource path="res://scripts/tile/TileGrid.cs" type="Script" id=1]
[ext_resource path="res://resources/tiles/tile_types/wild.tres" type="Resource" id=2]
[resource]
script = ExtResource( 1 )
Size = 10
_startTileTypeResource = ExtResource( 2 )

View File

@ -7,11 +7,8 @@ public class WorldGrid : Node2D
private PackedScene TileScene { get; set; } private PackedScene TileScene { get; set; }
[Export] [Export]
private Resource _startTileTypeResource; private Resource _tileGridResource;
private TileType _startTileType; private TileGrid _tileGrid;
[Export]
public int Size { get; set; }
[Export] [Export]
public int CellSize { get; set; } public int CellSize { get; set; }
@ -19,65 +16,65 @@ public class WorldGrid : Node2D
[Export] [Export]
public float DiffusionCoefficient { get; set; } = 0.01f; public float DiffusionCoefficient { get; set; } = 0.01f;
private Tile[,] _tiles; private float[] _nextValues = null;
private float[,] _nextValues = null;
private struct TileView
{
public ShaderMaterial material;
}
private TileView[] _tileViews;
// Called when the node enters the scene tree for the first time. // Called when the node enters the scene tree for the first time.
public override void _Ready() public override void _Ready()
{ {
_startTileType = (TileType)_startTileTypeResource; _tileGrid = (TileGrid)_tileGridResource;
GenerateGrid(Size); GenerateCanvasItems(_tileGrid);
} }
public override void _Process(float delta) public override void _Process(float delta)
{ {
base._Process(delta); base._Process(delta);
for (int x = 0; x < Size; x++) // TODO: this is a rendering concern that should be performed
// by the heat overlay
for (int i = 0; i < _tileGrid.Count; i++)
{ {
for (int y = 0; y < Size; y++) var tile = _tileGrid[i];
{ var view = _tileViews[i];
var tile = _tiles[x, y];
var material = tile.material; view.material.SetShaderParam("t", tile.temperature);
material.SetShaderParam("t", tile.temperature);
}
} }
} }
public bool IsInBounds(int x, int y) #region Positioning
{
return x >= 0 && x < Size && y >= 0 && y < Size;
}
public void ToggleTileHighlight(int x, int y)
{
if (!IsInBounds(x, y))
return;
_tiles[x, y].isHighlighted ^= true;
}
public void SetTileType(int x, int y, TileType tileType)
{
if (!IsInBounds(x, y))
return;
GD.Print($"set ({x}, {y}) to {tileType}");
_tiles[x, y].type = tileType;
_tiles[x, y].material.SetShaderParam("lowColor", tileType.Color);
}
public void GetGridPos(Vector2 position, out int x, out int y) public void GetGridPos(Vector2 position, out int x, out int y)
{ {
x = Mathf.FloorToInt(position.x / CellSize); x = Mathf.FloorToInt(position.x / CellSize);
y = Mathf.FloorToInt(position.y / CellSize); y = Mathf.FloorToInt(position.y / CellSize);
} }
public bool IsInBounds(int x, int y) => _tileGrid.IsInBounds(x, y);
#endregion
#region Interaction
public void SetTileType(int x, int y, TileType tileType)
{
if (!_tileGrid.IsInBounds(x, y))
return;
_tileGrid.MapPosition(x, y, out var idx);
var tile = _tileGrid[idx];
tile.type = tileType;
_tileGrid[x, y] = tile;
_tileViews[idx].material.SetShaderParam("lowColor", tileType.Color);
}
#endregion
private void Clear() private void Clear()
{ {
_tiles = null;
int children = this.GetChildCount(); int children = this.GetChildCount();
GD.Print(children); GD.Print(children);
for (int i = 0; i < children; i++) for (int i = 0; i < children; i++)
@ -85,38 +82,37 @@ public class WorldGrid : Node2D
var child = this.GetChild(i); var child = this.GetChild(i);
child.QueueFree(); child.QueueFree();
} }
_tileViews = null;
} }
private void GenerateGrid(int size) private void GenerateCanvasItems(TileGrid grid)
{ {
this.Clear(); this.Clear();
_tiles = new Tile[size, size]; _tileViews = new TileView[grid.Count];
_nextValues = new float[size, size]; _nextValues = new float[grid.Count];
for (int x = 0; x < size; x++) for (int i = 0; i < grid.Count; i++)
{ {
for (int y = 0; y < size; y++) _tileGrid.MapIndex(i, out var x, out var y);
var node = TileScene.Instance<Node2D>();
this.AddChild(node);
var position = new Vector2
{ {
var tile = new Tile(); x = (x + .5f) * CellSize,
tile.isHighlighted = false; y = (y + .5f) * CellSize
tile.temperature = 0.0f; };
tile.type = _startTileType; node.Position = position;
var canvasItem = (CanvasItem)node;
var node = TileScene.Instance<Node2D>(); var tile = _tileGrid[i];
this.AddChild(node);
var position = new Vector2
{
x = (x + .5f) * CellSize,
y = (y + .5f) * CellSize
};
node.Position = position;
var canvasItem = (CanvasItem)node;
tile.material = (ShaderMaterial)canvasItem.Material;
tile.material.SetShaderParam("lowColor", _startTileType.Color);
_tiles[x, y] = tile; TileView view = default;
} view.material = (ShaderMaterial)canvasItem.Material;
view.material.SetShaderParam("lowColor", _tileGrid.StartTileType.Color);
_tileViews[i] = view;
} }
} }
@ -126,6 +122,7 @@ public class WorldGrid : Node2D
Diffuse(); Diffuse();
} }
#region Simulation
private float TransferHeat(float t0, float alpha, float nx, float ny, float px, float py) private float TransferHeat(float t0, float alpha, float nx, float ny, float px, float py)
{ {
float d2tdx2 = nx - 2 * t0 + px; float d2tdx2 = nx - 2 * t0 + px;
@ -136,59 +133,56 @@ public class WorldGrid : Node2D
private void GetNeighbourTemperatures(int x, int y, out float nx, out float ny, out float px, out float py) private void GetNeighbourTemperatures(int x, int y, out float nx, out float ny, out float px, out float py)
{ {
// default value // default value
var t = _tiles[x, y].temperature; var t = _tileGrid[x, y].temperature;
nx = x > 0 ? _tiles[x - 1, y].temperature : t; nx = x > 0 ? _tileGrid[x - 1, y].temperature : t;
px = x < Size - 1 ? _tiles[x + 1, y].temperature : t; px = x < _tileGrid.Size - 1 ? _tileGrid[x + 1, y].temperature : t;
ny = y > 0 ? _tiles[x, y - 1].temperature : t; ny = y > 0 ? _tileGrid[x, y - 1].temperature : t;
py = y < Size - 1 ? _tiles[x, y + 1].temperature : t; py = y < _tileGrid.Size - 1 ? _tileGrid[x, y + 1].temperature : t;
} }
private void GenerateHeat() private void GenerateHeat()
{ {
for (int x = 0; x < Size; x++) for (int i = 0; i < _tileGrid.Count; i++)
{ {
for (int y = 0; y < Size; y++) var tile = _tileGrid[i];
{ var type = tile.type;
var tile = _tiles[x, y]; tile.temperature += type.HeatGeneration;
var type = tile.type; _tileGrid[i] = tile;
tile.temperature += type.HeatGeneration;
_tiles[x, y] = tile;
}
} }
} }
private void Diffuse() private void Diffuse()
{ {
for (int x = 0; x < Size; x++) var D = DiffusionCoefficient;
for (int i = 0; i < _tileGrid.Count; i++)
{ {
for (int y = 0; y < Size; y++) float t = _tileGrid[i].temperature;
{
float t = _tiles[x, y].temperature;
var D = DiffusionCoefficient;
GetNeighbourTemperatures( _tileGrid.MapIndex(i, out var x, out var y);
x, y,
out var nx,
out var ny,
out var px,
out var py);
// current value GetNeighbourTemperatures(
var temperature = TransferHeat(t, D, nx, ny, px, py); x, y,
// TODO: what if it's really really cold out? out var nx,
temperature = Mathf.Max(0, temperature); out var ny,
_nextValues[x, y] = temperature; out var px,
} out var py);
var temperature = TransferHeat(t, D, nx, ny, px, py);
// TODO: what if it's really really cold out?
temperature = Mathf.Max(0, temperature);
_nextValues[i] = temperature;
} }
for (int x = 0; x < Size; x++) for (int i = 0; i < _tileGrid.Count; i++)
{ {
for (int y = 0; y < Size; y++) var tile = _tileGrid[i];
{ tile.temperature = _nextValues[i];
_tiles[x, y].temperature = _nextValues[x, y]; _tileGrid[i] = tile;
}
} }
} }
#endregion
} }

View File

@ -4,6 +4,5 @@ public struct Tile
{ {
public bool isHighlighted; public bool isHighlighted;
public float temperature; public float temperature;
public ShaderMaterial material;
public TileType type; public TileType type;
} }

View File

@ -0,0 +1,92 @@
using Godot;
using System;
using System.Collections;
using System.Collections.Generic;
public class TileGrid : Resource, IReadOnlyList<Tile>
{
[Export]
public int Size { get; private set; } = 10;
[Export]
private Resource _startTileTypeResource;
public TileType StartTileType => (TileType)_startTileTypeResource;
public int Count => Size * Size;
public Tile this[int index]
{
get => Tiles[index];
set => Tiles[index] = value;
}
public Tile this[int x, int y]
{
get
{
MapPosition(x, y, out int idx);
return Tiles[idx];
}
set
{
MapPosition(x, y, out int idx);
Tiles[idx] = value;
}
}
private List<Tile> Tiles
{
get
{
if (_tiles == null)
{
_tiles = new List<Tile>();
Generate(_tiles);
}
return _tiles;
}
}
private List<Tile> _tiles = null;
private void Generate(List<Tile> tiles)
{
tiles.Clear();
for (int i = 0; i < Count; i++)
{
var tile = new Tile();
tile.isHighlighted = false;
tile.temperature = 0.0f;
tile.type = StartTileType;
tiles.Add(tile);
}
}
public IEnumerator<Tile> GetEnumerator()
{
return Tiles.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return Tiles.GetEnumerator();
}
public void MapIndex(int idx, out int x, out int y)
{
y = idx / Size;
x = idx % Size;
}
public void MapPosition(int x, int y, out int idx)
{
idx = y * Size + x;
}
public bool IsInBounds(int x, int y)
{
return x >= 0 && x < Size && y >= 0 && y < Size;
}
}