basic capture functionality

This commit is contained in:
anonoe 2026-02-10 21:17:17 +01:00
parent 246f3c0840
commit c141e6a169
Signed by: anonoe
SSH key fingerprint: SHA256:OnAs6gNQelOnDiY5tBpDYKQiuTgBvnmIdMo5P09cdqg
20 changed files with 430 additions and 14 deletions

View file

@ -21,6 +21,7 @@ public partial class ChunkManager : Node2D
private WorldIndex? _world;
private Dictionary<(int x, int y), string> _chunkMap = new();
private readonly Dictionary<(int x, int y), Node2D> _loaded = new();
private readonly Dictionary<(int x, int y), ChunkData> _chunkDataByCoord = new();
public override void _Ready()
{
@ -102,6 +103,7 @@ public partial class ChunkManager : Node2D
{
_loaded[k].QueueFree();
_loaded.Remove(k);
_chunkDataByCoord.Remove(k);
}
if (_clock != null)
@ -140,7 +142,7 @@ public partial class ChunkManager : Node2D
var biome = data.biome ?? "biome:unknown";
var node = CreateDebugChunkNode(x, y, _world!.chunk_size_px, biome);
node.SetMeta("chunk_data", data);
_chunkDataByCoord[(x, y)] = data;
// Put the chunk into the scene tree first so Timers can run.
AddChild(node);
AddChunkMarkers(node, data);
@ -174,6 +176,8 @@ public partial class ChunkManager : Node2D
_ => new Color(0.2f, 0.2f, 0.2f, 0.25f)
}
};
rect.ZIndex = -100; // keep the biome overlay behind all markers
rect.ZAsRelative = true;
n.AddChild(rect);
return n;
@ -249,14 +253,73 @@ public partial class ChunkManager : Node2D
}
// Collision rects: gray outlines (optional later)
AddCollisionRects(chunkNode, data);
//if (data.spawn_zones != null)
//{
//foreach (var z in data.spawn_zones)
//SpawnCreaturesForZone(chunkNode, z);
//}
if (data.spawn_zones != null)
{
foreach (var z in data.spawn_zones)
{
var r = z.rect;
var zoneRect = new ColorRect
{
Position = new Vector2(r[0], r[1]),
Size = new Vector2(r[2], r[3]),
Color = new Color(0.9f, 0.9f, 0.1f, 0.10f), // faint yellow overlay
MouseFilter = Control.MouseFilterEnum.Ignore
};
chunkNode.AddChild(zoneRect);
SpawnCreaturesForZone(chunkNode, z);
}
}
}
private void AddCollisionRects(Node2D chunkNode, ChunkData data)
{
if (data.collision_rects == null) return;
foreach (var c in data.collision_rects)
{
var r = c.rect; // [x,y,w,h]
// Physics body
var body = new StaticBody2D
{
Name = $"Col_{c.id.Replace(":", "_")}",
Position = new Vector2(r[0], r[1])
};
var shape = new CollisionShape2D();
var rectShape = new RectangleShape2D
{
Size = new Vector2(r[2], r[3])
};
shape.Shape = rectShape;
// CollisionShape2D is centered, so offset it by half-size to align to top-left rect coords
shape.Position = new Vector2(r[2] / 2f, r[3] / 2f);
body.AddChild(shape);
// Visual outline (gray)
var outline = new RectOutline
{
Size = new Vector2(r[2], r[3]),
ZIndex = 10,
ZAsRelative = true
};
body.AddChild(outline);
chunkNode.AddChild(body);
}
}
private static long NowUnixSeconds()
{
return DateTimeOffset.UtcNow.ToUnixTimeSeconds();
@ -381,6 +444,8 @@ public partial class ChunkManager : Node2D
for (int i = 0; i < count; i++)
{
var c = (Node2D)CreatureMarkerScene.Instantiate();
c.ZIndex = 50; // draw above debug chunk background
c.ZAsRelative = true;
c.Position = new Vector2(
r[0] + rng.RandfRange(0, r[2]),
r[1] + rng.RandfRange(0, r[3])
@ -391,23 +456,23 @@ public partial class ChunkManager : Node2D
private void RefreshCreaturesInLoadedChunks()
{
foreach (var chunk in _loaded.Values)
foreach (var kv in _loaded)
{
var coord = kv.Key;
var chunk = kv.Value;
// Remove existing creature containers
foreach (var child in chunk.GetChildren())
foreach (var childObj in chunk.GetChildren())
{
if (child is Node n && n.Name.StartsWith("Creatures_"))
if (childObj is Node n && n.Name.ToString().StartsWith("Creatures_"))
n.QueueFree();
}
// Re-read spawn zones by re-parsing the chunk json is overkill.
// v0 hack: store ChunkData on the chunk node as metadata.
if (chunk.HasMeta("chunk_data"))
// Re-spawn creatures based on stored ChunkData
if (_chunkDataByCoord.TryGetValue(coord, out var data) && data.spawn_zones != null)
{
var data = (ChunkData)chunk.GetMeta("chunk_data");
if (data.spawn_zones != null)
foreach (var z in data.spawn_zones)
SpawnCreaturesForZone(chunk, z);
foreach (var z in data.spawn_zones)
SpawnCreaturesForZone(chunk, z);
}
}
}

20
scripts/world/Creature.cs Normal file
View file

@ -0,0 +1,20 @@
using Godot;
public partial class Creature : Area2D
{
[Export] public string CreatureId { get; set; } = "creature:ember_fox";
public bool IsCaptured { get; private set; } = false;
public override void _Ready()
{
// Make sure we receive overlap events
Monitoring = true;
Monitorable = true;
}
public void Despawn()
{
IsCaptured = true;
QueueFree();
}
}

View file

@ -0,0 +1 @@
uid://it4jgvdqmkvr

View file

@ -0,0 +1,52 @@
using Godot;
using System.Collections.Generic;
public partial class PlayerInteractor : Area2D
{
private readonly List<Creature> _nearbyCreatures = new();
private GameRoot _gameRoot = null!;
public override void _Ready()
{
AreaEntered += OnAreaEntered;
AreaExited += OnAreaExited;
}
public override void _Process(double delta)
{
if (!Input.IsActionJustPressed("interact"))
return;
var creature = GetClosestCreature();
if (creature == null) return;
// Ask GameRoot to start capture
GameRoot.Instance.RequestCapture(creature);
}
private void OnAreaEntered(Area2D area)
{
if (area is Creature c && !c.IsCaptured)
_nearbyCreatures.Add(c);
}
private void OnAreaExited(Area2D area)
{
if (area is Creature c)
_nearbyCreatures.Remove(c);
}
private Creature? GetClosestCreature()
{
Creature? best = null;
float bestDist = float.MaxValue;
foreach (var c in _nearbyCreatures)
{
if (!IsInstanceValid(c)) continue;
float d = GlobalPosition.DistanceSquaredTo(c.GlobalPosition);
if (d < bestDist) { bestDist = d; best = c; }
}
return best;
}
}

View file

@ -0,0 +1 @@
uid://dtaa141c1wb8e

View file

@ -0,0 +1,14 @@
using Godot;
public partial class RectOutline : Node2D
{
[Export] public Vector2 Size = new Vector2(64, 64);
public override void _Draw()
{
// Draw an outline only (transparent fill)
DrawRect(new Rect2(Vector2.Zero, Size), new Color(0.6f, 0.6f, 0.6f, 0.9f), filled: false, width: 2f);
}
public override void _Ready() => QueueRedraw();
}

View file

@ -0,0 +1 @@
uid://bvfgl0jt8ked7