cirnogodot/Scripts/Controllers/RogueliteRoom.cs

223 lines
6.7 KiB
C#
Raw Normal View History

2025-04-11 18:39:39 +02:00
using System;
2025-04-16 18:18:52 +02:00
using System.Collections.Generic;
2025-04-11 18:39:39 +02:00
using System.Linq;
2025-04-16 18:18:52 +02:00
using Cirno.Scripts.Components.FSM.Enemy;
2025-04-11 15:53:59 +02:00
using Cirno.Scripts.Resources;
using Cirno.Scripts.Resources.Roguelite;
2025-04-10 19:04:06 +02:00
using Godot;
2025-04-11 15:53:59 +02:00
using Godot.Collections;
2025-04-10 19:04:06 +02:00
namespace Cirno.Scripts.Controllers;
public partial class RogueliteRoom : Node2D
{
[Export] public RogueliteRoomResource RoomResource { get; set; }
2025-04-14 16:50:58 +02:00
2025-04-11 18:39:39 +02:00
public Vector2I GridPosition { get; set; } // Set by dungeon manager
2025-04-14 16:50:58 +02:00
2025-04-21 17:46:26 +02:00
public Vector2I BottomLeft => GridPosition + new Vector2I(0, RoomResource.Size.Y - 1);
2025-04-22 13:50:26 +02:00
public Vector2I RandomBottomExit()
{
return BottomLeft + new Vector2I(GD.RandRange(0, RoomResource.Size.X - 1), 0);
}
2025-04-21 17:46:26 +02:00
2025-04-11 18:39:39 +02:00
[Export] public PackedScene DoorPrefab { get; private set; }
2025-04-16 15:11:29 +02:00
[Export] public PackedScene WallPrefab { get; private set; }
2025-04-14 16:50:58 +02:00
2025-04-16 18:18:52 +02:00
private static readonly Godot.Collections.Dictionary<string, Vector2I> DirectionMap = new()
2025-04-11 18:39:39 +02:00
{
{ "North", new Vector2I(0, -1) },
{ "South", new Vector2I(0, 1) },
2025-04-14 16:50:58 +02:00
{ "East", new Vector2I(1, 0) },
{ "West", new Vector2I(-1, 0) },
2025-04-11 18:39:39 +02:00
};
2025-04-11 15:53:59 +02:00
2025-04-16 18:18:52 +02:00
private List<Door> _doors = [];
private List<RoomConnection> _connections = [];
private List<EnemyFSMProxy> _enemies = [];
2025-04-14 16:50:58 +02:00
private Array<EnemyResource> SpawnableEnemies => RoomResource.SpawnableEnemies;
2025-04-11 15:53:59 +02:00
2025-04-14 16:50:58 +02:00
public RogueliteRoom Spawn()
2025-04-11 18:39:39 +02:00
{
SpawnEnemies();
2025-04-14 16:50:58 +02:00
//HandleDoors(connectionChecker);
2025-04-16 15:11:29 +02:00
AddDebugLabel();
2025-04-11 18:39:39 +02:00
return this;
}
2025-04-14 16:50:58 +02:00
2025-04-16 15:11:29 +02:00
private void AddDebugLabel()
{
for (int i = 0; i < RoomResource.Size.X; i++)
{
for (int j = 0; j < RoomResource.Size.Y; j++)
{
var label = new Label();
label.Text = $"{GridPosition + new Vector2I(i, j)}";
label.ZIndex = 11;
label.Position = (new Vector2(i, j) * new Vector2(320, 160)) + new Vector2(160, 80);
this.AddChild(label);
}
}
}
public void HandleDoors(Func<Vector2I, Vector2I, RoomConnection> connectionChecker)
2025-04-11 18:39:39 +02:00
{
if (!HasNode("Doors")) return;
var doorsNode = GetNode("Doors");
foreach (Node child in doorsNode.GetChildren())
{
if (child is not DoorMarker marker) continue;
2025-04-14 16:50:58 +02:00
2025-04-11 18:39:39 +02:00
var baseDir = marker.GetWorldDirection();
// WallIndex determines the offset *along* the edge of the room
Vector2I offset = marker.Direction switch
{
2025-04-16 15:11:29 +02:00
RoomDirection.North => new Vector2I(marker.WallIndex, 0),
RoomDirection.South => new Vector2I(marker.WallIndex, RoomResource.Size.Y - 1),
RoomDirection.East => new Vector2I(RoomResource.Size.X - 1, marker.WallIndex),
RoomDirection.West => new Vector2I(0, marker.WallIndex),
2025-04-11 18:39:39 +02:00
_ => Vector2I.Zero
};
// Combine GridPosition + offset to locate where this door aligns
Vector2I doorEdge = GridPosition + offset;
Vector2I neighborPos = doorEdge + baseDir;
2025-04-16 15:11:29 +02:00
var connection = connectionChecker.Invoke(doorEdge, neighborPos);
var connected = connection is not null;
2025-04-14 16:50:58 +02:00
if (connected)
{
2025-04-17 16:51:20 +02:00
var door = this.CreateChildOf<Door>(marker, DoorPrefab, marker.GlobalPosition);
2025-04-11 18:39:39 +02:00
2025-04-16 15:11:29 +02:00
door.State = DoorState.Closed;
2025-04-16 18:18:52 +02:00
_doors.Add(door);
2025-04-17 16:51:20 +02:00
if (doorEdge == connection.From)
2025-04-17 13:04:56 +02:00
{
connection.FromDoor = door;
}
2025-04-17 16:51:20 +02:00
else if (doorEdge == connection.To)
2025-04-17 13:04:56 +02:00
{
connection.ToDoor = door;
}
else
{
GD.Print($"Door {door} connection was full: {connection.From} {connection.FromDoor} to {connection.To} {connection.ToDoor}");
}
2025-04-16 18:18:52 +02:00
2025-04-17 16:51:20 +02:00
// if (connection.FromDoor is null && connection.ToDoor != door)
// {
// connection.FromDoor = door;
// }
// else if (connection.ToDoor is null && connection.FromDoor != door)
// {
// connection.ToDoor = door;
// }
// else
// {
// GD.Print($"Door {door} connection was full: {connection.From} {connection.FromDoor} to {connection.To} {connection.ToDoor}");
// }
2025-04-16 18:18:52 +02:00
_connections.Add(connection);
2025-04-16 15:11:29 +02:00
// var label = new Label();
// label.Text = $"Door Edge: {doorEdge}, {connection}";
// label.ZIndex = 10;
//
// door.AddChild(label);
2025-04-14 16:50:58 +02:00
}
else
{
var wall = this.CreateChild<Node2D>(WallPrefab, marker.GlobalPosition);
2025-04-16 15:11:29 +02:00
// var label = new Label();
// label.Text = $"Door Edge: {doorEdge}, Neighbor: {neighborPos}";
// label.ZIndex = 10;
//
// marker.AddChild(label);
2025-04-14 16:50:58 +02:00
}
2025-04-16 18:18:52 +02:00
2025-04-11 18:39:39 +02:00
}
}
private void SpawnEnemies()
2025-04-11 15:53:59 +02:00
{
2025-04-11 18:39:39 +02:00
if (SpawnableEnemies is null || !SpawnableEnemies.Any()) return;
2025-04-14 16:50:58 +02:00
2025-04-11 15:53:59 +02:00
var enemySpawners = this.GetNode("EnemySpawners").GetChildren().Cast<Marker2D>();
foreach (var spawner in enemySpawners)
{
var index = GD.RandRange(0, SpawnableEnemies.Count - 1);
2025-04-14 16:50:58 +02:00
2025-04-11 15:53:59 +02:00
var e = SpawnableEnemies[index];
2025-04-14 16:50:58 +02:00
2025-04-11 15:53:59 +02:00
var enemyScene = GD.Load<PackedScene>(e.PrefabPath);
2025-04-16 18:18:52 +02:00
var spawnedEnemy = spawner.CreateChild<EnemyFSMProxy>(enemyScene);
_enemies.Add(spawnedEnemy);
spawnedEnemy.Death += SpawnedEnemyOnDeath;
}
}
private void SpawnedEnemyOnDeath(EnemyFSMProxy enemy)
{
enemy.Death -= SpawnedEnemyOnDeath;
_enemies.Remove(enemy);
if (_enemies.Count == 0)
{
OpenDoors();
}
}
public void OpenDoors()
{
foreach (var connection in _connections)
{
2025-04-17 13:04:56 +02:00
connection.FromDoor?.Open();
connection.ToDoor?.Open();
2025-04-11 15:53:59 +02:00
}
}
2025-04-16 18:18:52 +02:00
public void CloseDoors()
{
foreach (var connection in _connections)
{
2025-04-17 13:04:56 +02:00
connection.FromDoor?.Close();
connection.ToDoor?.Close();
2025-04-16 18:18:52 +02:00
}
}
private void OnRoomEntered(Area2D area)
{
if (area is not InteractionController player) return;
if (_enemies.Count <= 0)
{
OpenDoors();
}
else
{
CloseDoors();
}
}
private void OnRoomExited(Area2D area)
{
if (area is not InteractionController player) return;
}
2025-04-21 17:46:26 +02:00
public override string ToString()
{
return $"{GridPosition} {RoomResource}";
}
2025-04-10 19:04:06 +02:00
}