diff --git a/half-earth/Half-earth.csproj b/half-earth/Half-earth.csproj
new file mode 100644
index 0000000..29905c2
--- /dev/null
+++ b/half-earth/Half-earth.csproj
@@ -0,0 +1,6 @@
+
+
+ net472
+ Halfearth
+
+
\ No newline at end of file
diff --git a/half-earth/Half-earth.sln b/half-earth/Half-earth.sln
new file mode 100644
index 0000000..a7cf826
--- /dev/null
+++ b/half-earth/Half-earth.sln
@@ -0,0 +1,19 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Half-earth", "Half-earth.csproj", "{C894A75C-991B-4000-9BD9-9B0B186304C4}"
+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
+ {C894A75C-991B-4000-9BD9-9B0B186304C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C894A75C-991B-4000-9BD9-9B0B186304C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C894A75C-991B-4000-9BD9-9B0B186304C4}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
+ {C894A75C-991B-4000-9BD9-9B0B186304C4}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
+ {C894A75C-991B-4000-9BD9-9B0B186304C4}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
+ {C894A75C-991B-4000-9BD9-9B0B186304C4}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/half-earth/materials/cursor.tres b/half-earth/materials/cursor.tres
new file mode 100644
index 0000000..a3218a5
--- /dev/null
+++ b/half-earth/materials/cursor.tres
@@ -0,0 +1,9 @@
+[gd_resource type="ShaderMaterial" load_steps=2 format=2]
+
+[ext_resource path="res://shaders/tile_shader.gdshader" type="Shader" id=1]
+
+[resource]
+shader = ExtResource( 1 )
+shader_param/baseColor = Color( 0.992157, 1, 0, 1 )
+shader_param/highlightColor = Color( 1, 0, 0.984314, 1 )
+shader_param/isHighlighted = 0
diff --git a/half-earth/materials/tile.tres b/half-earth/materials/tile.tres
new file mode 100644
index 0000000..327c5eb
--- /dev/null
+++ b/half-earth/materials/tile.tres
@@ -0,0 +1,10 @@
+[gd_resource type="ShaderMaterial" load_steps=2 format=2]
+
+[ext_resource path="res://shaders/tile_shader.gdshader" type="Shader" id=1]
+
+[resource]
+resource_local_to_scene = true
+shader = ExtResource( 1 )
+shader_param/baseColor = Color( 0.0823529, 0, 1, 1 )
+shader_param/highlightColor = Color( 1, 0, 0, 1 )
+shader_param/isHighlighted = null
diff --git a/half-earth/nodes/game.tscn b/half-earth/nodes/game.tscn
new file mode 100644
index 0000000..c7bf9d9
--- /dev/null
+++ b/half-earth/nodes/game.tscn
@@ -0,0 +1,11 @@
+[gd_scene load_steps=3 format=2]
+
+[ext_resource path="res://nodes/grid.tscn" type="PackedScene" id=1]
+[ext_resource path="res://nodes/grid_cursor.tscn" type="PackedScene" id=2]
+
+[node name="Root" type="Node2D"]
+
+[node name="Grid" parent="." instance=ExtResource( 1 )]
+
+[node name="Cursor" parent="." instance=ExtResource( 2 )]
+Grid = NodePath("../Grid")
diff --git a/half-earth/nodes/grid.tscn b/half-earth/nodes/grid.tscn
new file mode 100644
index 0000000..3a19d57
--- /dev/null
+++ b/half-earth/nodes/grid.tscn
@@ -0,0 +1,10 @@
+[gd_scene load_steps=3 format=2]
+
+[ext_resource path="res://scripts/WorldGrid.cs" type="Script" id=1]
+[ext_resource path="res://nodes/tile.tscn" type="PackedScene" id=2]
+
+[node name="Grid" type="Node2D"]
+script = ExtResource( 1 )
+TileScene = ExtResource( 2 )
+Size = 10
+CellSize = 64
diff --git a/half-earth/nodes/grid_cursor.tscn b/half-earth/nodes/grid_cursor.tscn
new file mode 100644
index 0000000..668f1a2
--- /dev/null
+++ b/half-earth/nodes/grid_cursor.tscn
@@ -0,0 +1,10 @@
+[gd_scene load_steps=4 format=2]
+
+[ext_resource path="res://textures/icon.png" type="Texture" id=1]
+[ext_resource path="res://scripts/GridCursor.cs" type="Script" id=2]
+[ext_resource path="res://materials/cursor.tres" type="Material" id=3]
+
+[node name="Grid Cursor" type="Sprite"]
+material = ExtResource( 3 )
+texture = ExtResource( 1 )
+script = ExtResource( 2 )
diff --git a/half-earth/nodes/tile.tscn b/half-earth/nodes/tile.tscn
new file mode 100644
index 0000000..5861ee1
--- /dev/null
+++ b/half-earth/nodes/tile.tscn
@@ -0,0 +1,8 @@
+[gd_scene load_steps=3 format=2]
+
+[ext_resource path="res://materials/tile.tres" type="Material" id=1]
+[ext_resource path="res://textures/icon.png" type="Texture" id=2]
+
+[node name="Tile" type="Sprite"]
+material = ExtResource( 1 )
+texture = ExtResource( 2 )
diff --git a/half-earth/project.godot b/half-earth/project.godot
index 4371922..93daccc 100644
--- a/half-earth/project.godot
+++ b/half-earth/project.godot
@@ -11,7 +11,8 @@ config_version=4
[application]
config/name="Half-earth"
-config/icon="res://icon.png"
+run/main_scene="res://nodes/game.tscn"
+config/icon="res://textures/icon.png"
[gui]
@@ -27,4 +28,5 @@ common/enable_pause_aware_picking=true
[rendering]
-environment/default_environment="res://default_env.tres"
+gles3/shaders/shader_compilation_mode=1
+environment/default_environment="res://resources/default_env.tres"
diff --git a/half-earth/default_env.tres b/half-earth/resources/default_env.tres
similarity index 100%
rename from half-earth/default_env.tres
rename to half-earth/resources/default_env.tres
diff --git a/half-earth/scripts/GridCursor.cs b/half-earth/scripts/GridCursor.cs
new file mode 100644
index 0000000..fd97c42
--- /dev/null
+++ b/half-earth/scripts/GridCursor.cs
@@ -0,0 +1,51 @@
+using Godot;
+using System;
+
+public class GridCursor : Sprite
+{
+ [Export]
+ public NodePath Grid { get; set; }
+ private WorldGrid _grid;
+ private ShaderMaterial _material;
+
+ private const string IS_HIGHLIGHTED = "isHighlighted";
+
+ public override void _Ready()
+ {
+ _grid = GetNode(Grid);
+ _material = (ShaderMaterial)Material;
+ }
+
+ public override void _Input(InputEvent @event)
+ {
+ base._Input(@event);
+
+ if (@event is InputEventMouseMotion mouseMoveEvent)
+ {
+ var pos = mouseMoveEvent.Position;
+ _grid.GetGridPos(pos, out var x, out var y);
+ this.Visible = _grid.IsInBounds(x, y);
+ var position = new Vector2(x + .5f, y + .5f) * _grid.CellSize;
+ this.Position = position;
+ }
+ else if (@event is InputEventMouseButton mouseButtonEvent)
+ {
+ switch ((ButtonList)mouseButtonEvent.ButtonIndex)
+ {
+ case ButtonList.Left:
+ if (mouseButtonEvent.Pressed)
+ {
+ var pos = mouseButtonEvent.Position;
+ _grid.GetGridPos(pos, out var x, out var y);
+ _grid.ToggleTileHighlight(x, y);
+ _material.SetShaderParam(IS_HIGHLIGHTED, 1);
+ }
+ else
+ {
+ _material.SetShaderParam(IS_HIGHLIGHTED, 0);
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/half-earth/scripts/WorldGrid.cs b/half-earth/scripts/WorldGrid.cs
new file mode 100644
index 0000000..a59855d
--- /dev/null
+++ b/half-earth/scripts/WorldGrid.cs
@@ -0,0 +1,103 @@
+using Godot;
+using System;
+
+public class WorldGrid : Node2D
+{
+ [Export]
+ private PackedScene TileScene { get; set; }
+
+ [Export]
+ public int Size { get; set; }
+
+ [Export]
+ public int CellSize { get; set; }
+
+ private struct Tile
+ {
+ public bool isHighlighted;
+ public ShaderMaterial material;
+ }
+ private Tile[,] _tiles;
+
+ // Called when the node enters the scene tree for the first time.
+ public override void _Ready()
+ {
+ GenerateGrid(Size);
+ }
+
+ public override void _Process(float delta)
+ {
+ base._Process(delta);
+
+ for (int x = 0; x < Size; x++)
+ {
+ for (int y = 0; y < Size; y++)
+ {
+ var tile = _tiles[x, y];
+ var material = tile.material;
+ material.SetShaderParam("isHighlighted", tile.isHighlighted ? 1 : 0);
+ }
+ }
+ }
+
+ public bool IsInBounds(int x, int y)
+ {
+ 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 GetGridPos(Vector2 position, out int x, out int y)
+ {
+ x = Mathf.FloorToInt(position.x / CellSize);
+ y = Mathf.FloorToInt(position.y / CellSize);
+ }
+
+ private void Clear()
+ {
+ _tiles = null;
+
+ int children = this.GetChildCount();
+ GD.Print(children);
+ for (int i = 0; i < children; i++)
+ {
+ var child = this.GetChild(i);
+ child.QueueFree();
+ }
+ }
+
+ private void GenerateGrid(int size)
+ {
+ this.Clear();
+
+ _tiles = new Tile[size, size];
+
+ for (int x = 0; x < size; x++)
+ {
+ for (int y = 0; y < size; y++)
+ {
+ var tile = new Tile();
+ tile.isHighlighted = false;
+
+ var node = TileScene.Instance();
+ 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;
+
+ _tiles[x, y] = tile;
+ }
+ }
+ }
+}
diff --git a/half-earth/shaders/tile_shader.gdshader b/half-earth/shaders/tile_shader.gdshader
new file mode 100644
index 0000000..98f8fe0
--- /dev/null
+++ b/half-earth/shaders/tile_shader.gdshader
@@ -0,0 +1,9 @@
+shader_type canvas_item;
+
+uniform vec4 baseColor : hint_color;
+uniform vec4 highlightColor : hint_color;
+uniform int isHighlighted;
+
+void fragment() {
+ COLOR = mix(baseColor, highlightColor, float(isHighlighted));
+}
diff --git a/half-earth/icon.png b/half-earth/textures/icon.png
similarity index 100%
rename from half-earth/icon.png
rename to half-earth/textures/icon.png
diff --git a/half-earth/icon.png.import b/half-earth/textures/icon.png.import
similarity index 73%
rename from half-earth/icon.png.import
rename to half-earth/textures/icon.png.import
index a4c02e6..b996b3c 100644
--- a/half-earth/icon.png.import
+++ b/half-earth/textures/icon.png.import
@@ -2,15 +2,15 @@
importer="texture"
type="StreamTexture"
-path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
+path="res://.import/icon.png-f931f6b997c470ed41f337ac62349254.stex"
metadata={
"vram_texture": false
}
[deps]
-source_file="res://icon.png"
-dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
+source_file="res://textures/icon.png"
+dest_files=[ "res://.import/icon.png-f931f6b997c470ed41f337ac62349254.stex" ]
[params]