time-of-day + creature spawns in spawn zones
This commit is contained in:
parent
c5d89c898a
commit
246f3c0840
8 changed files with 148 additions and 2 deletions
|
|
@ -53,6 +53,11 @@ ui_down={
|
||||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
|
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
debug_cycle_time={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":84,"key_label":0,"unicode":116,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
[physics]
|
[physics]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@
|
||||||
[ext_resource type="Script" uid="uid://cqdq8fslu7cyp" path="res://scripts/world/ChunkManager.cs" id="2_0bbpv"]
|
[ext_resource type="Script" uid="uid://cqdq8fslu7cyp" path="res://scripts/world/ChunkManager.cs" id="2_0bbpv"]
|
||||||
[ext_resource type="Script" uid="uid://db2vbbh5737ke" path="res://scripts/core/PackManager.cs" id="3_rarhs"]
|
[ext_resource type="Script" uid="uid://db2vbbh5737ke" path="res://scripts/core/PackManager.cs" id="3_rarhs"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bs7qu34sfgvjx" path="res://scenes/world/PickupMarker.tscn" id="3_vcsgt"]
|
[ext_resource type="PackedScene" uid="uid://bs7qu34sfgvjx" path="res://scenes/world/PickupMarker.tscn" id="3_vcsgt"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://bjil24xdbm76x" path="res://scenes/world/CreatureMarker.tscn" id="4_nxtc6"]
|
||||||
[ext_resource type="Script" uid="uid://osk74jjhtcjy" path="res://scripts/core/SaveManager.cs" id="4_rarhs"]
|
[ext_resource type="Script" uid="uid://osk74jjhtcjy" path="res://scripts/core/SaveManager.cs" id="4_rarhs"]
|
||||||
|
[ext_resource type="Script" uid="uid://b6gxknud5unt" path="res://scripts/core/WorldClock.cs" id="6_c01mt"]
|
||||||
|
|
||||||
[node name="Main" type="Node2D" unique_id=1194367579]
|
[node name="Main" type="Node2D" unique_id=1194367579]
|
||||||
|
|
||||||
|
|
@ -18,9 +20,14 @@ PlayerPath = NodePath("../Player")
|
||||||
PackManagerPath = NodePath("../../PackManager")
|
PackManagerPath = NodePath("../../PackManager")
|
||||||
PickupMarkerScene = ExtResource("3_vcsgt")
|
PickupMarkerScene = ExtResource("3_vcsgt")
|
||||||
SaveManagerPath = NodePath("../../SaveManager")
|
SaveManagerPath = NodePath("../../SaveManager")
|
||||||
|
CreatureMarkerScene = ExtResource("4_nxtc6")
|
||||||
|
WorldClockPath = NodePath("../../WorldClock")
|
||||||
|
|
||||||
[node name="PackManager" type="Node" parent="." unique_id=1706387276]
|
[node name="PackManager" type="Node" parent="." unique_id=1706387276]
|
||||||
script = ExtResource("3_rarhs")
|
script = ExtResource("3_rarhs")
|
||||||
|
|
||||||
[node name="SaveManager" type="Node" parent="." unique_id=1115563669]
|
[node name="SaveManager" type="Node" parent="." unique_id=1115563669]
|
||||||
script = ExtResource("4_rarhs")
|
script = ExtResource("4_rarhs")
|
||||||
|
|
||||||
|
[node name="WorldClock" type="Node" parent="." unique_id=437350596]
|
||||||
|
script = ExtResource("6_c01mt")
|
||||||
|
|
|
||||||
5
scenes/world/CreatureMarker.tscn
Normal file
5
scenes/world/CreatureMarker.tscn
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
[gd_scene format=3 uid="uid://bjil24xdbm76x"]
|
||||||
|
|
||||||
|
[node name="CreatureMarker" type="Node2D" unique_id=1874810005]
|
||||||
|
|
||||||
|
[node name="Visual" type="Node2D" parent="." unique_id=309456162]
|
||||||
30
scripts/core/WorldClock.cs
Normal file
30
scripts/core/WorldClock.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
public partial class WorldClock : Node
|
||||||
|
{
|
||||||
|
public enum TimeOfDay { Morning, Day, Night }
|
||||||
|
|
||||||
|
[Export] public TimeOfDay Current { get; private set; } = TimeOfDay.Day;
|
||||||
|
|
||||||
|
public override void _Process(double delta)
|
||||||
|
{
|
||||||
|
// Debug toggle: press T to cycle
|
||||||
|
if (Input.IsActionJustPressed("debug_cycle_time"))
|
||||||
|
{
|
||||||
|
Current = Current switch
|
||||||
|
{
|
||||||
|
TimeOfDay.Morning => TimeOfDay.Day,
|
||||||
|
TimeOfDay.Day => TimeOfDay.Night,
|
||||||
|
_ => TimeOfDay.Morning
|
||||||
|
};
|
||||||
|
GD.Print($"TimeOfDay -> {Current}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToPackString(TimeOfDay t) => t switch
|
||||||
|
{
|
||||||
|
TimeOfDay.Morning => "morning",
|
||||||
|
TimeOfDay.Day => "day",
|
||||||
|
_ => "night"
|
||||||
|
};
|
||||||
|
}
|
||||||
1
scripts/core/WorldClock.cs.uid
Normal file
1
scripts/core/WorldClock.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://b6gxknud5unt
|
||||||
|
|
@ -10,6 +10,11 @@ public partial class ChunkManager : Node2D
|
||||||
[Export] public int LoadRadius { get; set; } = 1; // 1 => 3x3
|
[Export] public int LoadRadius { get; set; } = 1; // 1 => 3x3
|
||||||
[Export] public PackedScene PickupMarkerScene { get; set; }
|
[Export] public PackedScene PickupMarkerScene { get; set; }
|
||||||
[Export] public NodePath SaveManagerPath { get; set; }
|
[Export] public NodePath SaveManagerPath { get; set; }
|
||||||
|
[Export] public PackedScene CreatureMarkerScene { get; set; }
|
||||||
|
[Export] public NodePath WorldClockPath { get; set; }
|
||||||
|
[Export] public int MaxCreaturesPerChunk { get; set; } = 3;
|
||||||
|
private WorldClock? _clock;
|
||||||
|
private WorldClock.TimeOfDay? _lastTime;
|
||||||
private SaveManager? _save;
|
private SaveManager? _save;
|
||||||
private CharacterBody2D? _player;
|
private CharacterBody2D? _player;
|
||||||
private PackManager? _packs;
|
private PackManager? _packs;
|
||||||
|
|
@ -36,6 +41,9 @@ public partial class ChunkManager : Node2D
|
||||||
_save = GetNodeOrNull<SaveManager>(SaveManagerPath);
|
_save = GetNodeOrNull<SaveManager>(SaveManagerPath);
|
||||||
if (_save == null) GD.PrintErr("ChunkManager: SaveManagerPath not set or invalid.");
|
if (_save == null) GD.PrintErr("ChunkManager: SaveManagerPath not set or invalid.");
|
||||||
|
|
||||||
|
_clock = GetNodeOrNull<WorldClock>(WorldClockPath);
|
||||||
|
if (_clock == null) GD.PrintErr("ChunkManager: WorldClockPath not set or invalid.");
|
||||||
|
|
||||||
LoadWorldIndex();
|
LoadWorldIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,6 +103,17 @@ public partial class ChunkManager : Node2D
|
||||||
_loaded[k].QueueFree();
|
_loaded[k].QueueFree();
|
||||||
_loaded.Remove(k);
|
_loaded.Remove(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_clock != null)
|
||||||
|
{
|
||||||
|
if (_lastTime == null) _lastTime = _clock.Current;
|
||||||
|
|
||||||
|
if (_clock.Current != _lastTime)
|
||||||
|
{
|
||||||
|
_lastTime = _clock.Current;
|
||||||
|
RefreshCreaturesInLoadedChunks();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnsureLoaded(int x, int y)
|
private void EnsureLoaded(int x, int y)
|
||||||
|
|
@ -121,8 +140,10 @@ public partial class ChunkManager : Node2D
|
||||||
var biome = data.biome ?? "biome:unknown";
|
var biome = data.biome ?? "biome:unknown";
|
||||||
|
|
||||||
var node = CreateDebugChunkNode(x, y, _world!.chunk_size_px, biome);
|
var node = CreateDebugChunkNode(x, y, _world!.chunk_size_px, biome);
|
||||||
AddChunkMarkers(node, data);
|
node.SetMeta("chunk_data", data);
|
||||||
|
// Put the chunk into the scene tree first so Timers can run.
|
||||||
AddChild(node);
|
AddChild(node);
|
||||||
|
AddChunkMarkers(node, data);
|
||||||
_loaded[key] = node;
|
_loaded[key] = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,6 +249,12 @@ public partial class ChunkManager : Node2D
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collision rects: gray outlines (optional later)
|
// Collision rects: gray outlines (optional later)
|
||||||
|
|
||||||
|
if (data.spawn_zones != null)
|
||||||
|
{
|
||||||
|
foreach (var z in data.spawn_zones)
|
||||||
|
SpawnCreaturesForZone(chunkNode, z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NowUnixSeconds()
|
private static long NowUnixSeconds()
|
||||||
|
|
@ -326,6 +353,63 @@ public partial class ChunkManager : Node2D
|
||||||
};
|
};
|
||||||
|
|
||||||
chunkNode.AddChild(timer);
|
chunkNode.AddChild(timer);
|
||||||
timer.Start();
|
// Start after the node is fully in-tree (avoids start-before-tree edge cases).
|
||||||
|
timer.CallDeferred(Timer.MethodName.Start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SpawnCreaturesForZone(Node2D chunkNode, ChunkSpawnZone zone)
|
||||||
|
{
|
||||||
|
if (_clock == null || CreatureMarkerScene == null) return;
|
||||||
|
|
||||||
|
var timeStr = WorldClock.ToPackString(_clock.Current);
|
||||||
|
if (zone.time_windows != null && zone.time_windows.Count > 0 && !zone.time_windows.Contains(timeStr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Dedup: ensure one spawn container per zone
|
||||||
|
var containerName = $"Creatures_{zone.id.Replace(":", "_")}";
|
||||||
|
if (chunkNode.HasNode(containerName))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var container = new Node2D { Name = containerName };
|
||||||
|
chunkNode.AddChild(container);
|
||||||
|
|
||||||
|
var r = zone.rect; // [x,y,w,h]
|
||||||
|
var rng = new RandomNumberGenerator();
|
||||||
|
rng.Randomize();
|
||||||
|
|
||||||
|
var count = Math.Min(MaxCreaturesPerChunk, 3);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var c = (Node2D)CreatureMarkerScene.Instantiate();
|
||||||
|
c.Position = new Vector2(
|
||||||
|
r[0] + rng.RandfRange(0, r[2]),
|
||||||
|
r[1] + rng.RandfRange(0, r[3])
|
||||||
|
);
|
||||||
|
container.AddChild(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshCreaturesInLoadedChunks()
|
||||||
|
{
|
||||||
|
foreach (var chunk in _loaded.Values)
|
||||||
|
{
|
||||||
|
// Remove existing creature containers
|
||||||
|
foreach (var child in chunk.GetChildren())
|
||||||
|
{
|
||||||
|
if (child is Node n && n.Name.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"))
|
||||||
|
{
|
||||||
|
var data = (ChunkData)chunk.GetMeta("chunk_data");
|
||||||
|
if (data.spawn_zones != null)
|
||||||
|
foreach (var z in data.spawn_zones)
|
||||||
|
SpawnCreaturesForZone(chunk, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
13
scripts/world/CreatureVisual.cs
Normal file
13
scripts/world/CreatureVisual.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
public partial class CreatureVisual : Node2D
|
||||||
|
{
|
||||||
|
[Export] public float Radius = 8f;
|
||||||
|
|
||||||
|
public override void _Draw()
|
||||||
|
{
|
||||||
|
DrawCircle(Vector2.Zero, Radius, new Color(1f, 0.8f, 0.2f, 0.9f));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _Ready() => QueueRedraw();
|
||||||
|
}
|
||||||
1
scripts/world/CreatureVisual.cs.uid
Normal file
1
scripts/world/CreatureVisual.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://c3276p03ic158
|
||||||
Loading…
Add table
Add a link
Reference in a new issue