From bca8d109649e3bfc91199af8c0426b00c409ae7a Mon Sep 17 00:00:00 2001 From: Hans Kokx Date: Fri, 13 Mar 2026 20:07:44 +0100 Subject: [PATCH] Break out spawnable entities and use a registry to spawn them. Signed-off-by: Hans Kokx --- lib/classes/sprite.dart | 1 - .../difficulty}/difficulty.dart | 0 .../difficulty/difficulty_screen.dart | 2 +- .../entities}/decorative.dart | 22 ++++++++- .../{ => entities}/enemies/brown_guard.dart | 48 ++++++++++++++----- .../entities/enemies}/enemy.dart | 2 +- .../entities}/entity.dart | 2 +- lib/features/entities/entity_registry.dart | 35 ++++++++++++++ lib/features/renderer/raycast_painter.dart | 2 +- lib/features/renderer/renderer.dart | 48 ++++++------------- 10 files changed, 110 insertions(+), 52 deletions(-) delete mode 100644 lib/classes/sprite.dart rename lib/{classes => features/difficulty}/difficulty.dart (100%) rename lib/{classes => features/entities}/decorative.dart (56%) rename lib/features/{ => entities}/enemies/brown_guard.dart (76%) rename lib/{classes => features/entities/enemies}/enemy.dart (97%) rename lib/{classes => features/entities}/entity.dart (93%) create mode 100644 lib/features/entities/entity_registry.dart diff --git a/lib/classes/sprite.dart b/lib/classes/sprite.dart deleted file mode 100644 index 9225c16..0000000 --- a/lib/classes/sprite.dart +++ /dev/null @@ -1 +0,0 @@ -typedef Sprite = ({double x, double y, int spriteIndex}); diff --git a/lib/classes/difficulty.dart b/lib/features/difficulty/difficulty.dart similarity index 100% rename from lib/classes/difficulty.dart rename to lib/features/difficulty/difficulty.dart diff --git a/lib/features/difficulty/difficulty_screen.dart b/lib/features/difficulty/difficulty_screen.dart index 9377de7..572de2a 100644 --- a/lib/features/difficulty/difficulty_screen.dart +++ b/lib/features/difficulty/difficulty_screen.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:wolf_dart/classes/difficulty.dart'; +import 'package:wolf_dart/features/difficulty/difficulty.dart'; import 'package:wolf_dart/features/renderer/renderer.dart'; class DifficultyScreen extends StatelessWidget { diff --git a/lib/classes/decorative.dart b/lib/features/entities/decorative.dart similarity index 56% rename from lib/classes/decorative.dart rename to lib/features/entities/decorative.dart index 90e0c8b..6101cba 100644 --- a/lib/classes/decorative.dart +++ b/lib/features/entities/decorative.dart @@ -1,4 +1,4 @@ -import 'package:wolf_dart/classes/entity.dart'; +import 'package:wolf_dart/features/entities/entity.dart'; class Decorative extends Entity { Decorative({ @@ -19,4 +19,24 @@ class Decorative extends Entity { if (objId == 124) return 95; // Dead guard return objId - 21; } + + static Decorative? trySpawn( + int objId, + double x, + double y, + int difficultyLevel, + ) { + if (isDecoration(objId)) { + return Decorative( + x: x, + y: y, + spriteIndex: getSpriteIndex(objId), + mapId: objId, + state: objId == 124 ? EntityState.dead : EntityState.staticObj, + ); + } + + // Not a decoration! + return null; + } } diff --git a/lib/features/enemies/brown_guard.dart b/lib/features/entities/enemies/brown_guard.dart similarity index 76% rename from lib/features/enemies/brown_guard.dart rename to lib/features/entities/enemies/brown_guard.dart index 435768b..1880f16 100644 --- a/lib/features/enemies/brown_guard.dart +++ b/lib/features/entities/enemies/brown_guard.dart @@ -1,8 +1,8 @@ import 'dart:math' as math; -import 'package:wolf_dart/classes/enemy.dart'; -import 'package:wolf_dart/classes/entity.dart'; import 'package:wolf_dart/classes/linear_coordinates.dart'; +import 'package:wolf_dart/features/entities/enemies/enemy.dart'; +import 'package:wolf_dart/features/entities/entity.dart'; class BrownGuard extends Enemy { static const double speed = 0.03; @@ -14,24 +14,42 @@ class BrownGuard extends Enemy { required super.angle, required super.mapId, }) : super( - spriteIndex: 50, // Default front-facing idle + // Default front-facing idle + spriteIndex: 50, state: EntityState.idle, ); - // Checks if a Map ID is a valid Brown Guard for the selected difficulty - static bool isSpawnableForDifficulty(int objId, int difficultyLevel) { + static BrownGuard? trySpawn( + int objId, + double x, + double y, + int difficultyLevel, + ) { + bool canSpawn = false; switch (difficultyLevel) { case 0: - return objId >= 108 && objId <= 115; + canSpawn = objId >= 108 && objId <= 115; + break; case 1: - return objId >= 144 && objId <= 151; + canSpawn = objId >= 144 && objId <= 151; + break; case 2: - return objId >= 180 && objId <= 187; + canSpawn = objId >= 180 && objId <= 187; + break; case 3: - return objId >= 216 && objId <= 223; - default: - return false; + canSpawn = objId >= 216 && objId <= 223; + break; } + + if (canSpawn) { + return BrownGuard( + x: x, + y: y, + angle: Enemy.getInitialAngle(objId), + mapId: objId, + ); + } + return null; // Not a Brown Guard! } @override @@ -64,8 +82,12 @@ class BrownGuard extends Enemy { } double diff = angle - angleToPlayer; - while (diff <= -math.pi) diff += 2 * math.pi; - while (diff > math.pi) diff -= 2 * math.pi; + while (diff <= -math.pi) { + diff += 2 * math.pi; + } + while (diff > math.pi) { + diff -= 2 * math.pi; + } int octant = ((diff + (math.pi / 8)) / (math.pi / 4)).floor() % 8; if (octant < 0) octant += 8; diff --git a/lib/classes/enemy.dart b/lib/features/entities/enemies/enemy.dart similarity index 97% rename from lib/classes/enemy.dart rename to lib/features/entities/enemies/enemy.dart index 64b2b36..6c53ae1 100644 --- a/lib/classes/enemy.dart +++ b/lib/features/entities/enemies/enemy.dart @@ -1,7 +1,7 @@ import 'dart:math' as math; -import 'package:wolf_dart/classes/entity.dart'; import 'package:wolf_dart/classes/linear_coordinates.dart'; +import 'package:wolf_dart/features/entities/entity.dart'; abstract class Enemy extends Entity { Enemy({ diff --git a/lib/classes/entity.dart b/lib/features/entities/entity.dart similarity index 93% rename from lib/classes/entity.dart rename to lib/features/entities/entity.dart index cf784c5..c327571 100644 --- a/lib/classes/entity.dart +++ b/lib/features/entities/entity.dart @@ -1,6 +1,6 @@ enum EntityState { staticObj, idle, patrolling, shooting, pain, dead } -class Entity { +abstract class Entity { double x; double y; int spriteIndex; diff --git a/lib/features/entities/entity_registry.dart b/lib/features/entities/entity_registry.dart new file mode 100644 index 0000000..422564c --- /dev/null +++ b/lib/features/entities/entity_registry.dart @@ -0,0 +1,35 @@ +import 'package:wolf_dart/features/entities/decorative.dart'; +import 'package:wolf_dart/features/entities/enemies/brown_guard.dart'; +import 'package:wolf_dart/features/entities/entity.dart'; + +typedef EntitySpawner = + Entity? Function(int objId, double x, double y, int difficultyLevel); + +abstract class EntityRegistry { + // Add future enemies (SSGuard, Dog, etc.) to this list! + static final List _spawners = [ + Decorative.trySpawn, + BrownGuard.trySpawn, + ]; + + static Entity? spawn( + int objId, + double x, + double y, + int difficultyLevel, + int maxSprites, + ) { + for (final spawner in _spawners) { + Entity? entity = spawner(objId, x, y, difficultyLevel); + + if (entity != null) { + // Safety bounds check for the VSWAP array + if (entity.spriteIndex >= 0 && entity.spriteIndex < maxSprites) { + return entity; + } + return null; // VSWAP doesn't have this sprite! + } + } + return null; // No class claimed this Map ID + } +} diff --git a/lib/features/renderer/raycast_painter.dart b/lib/features/renderer/raycast_painter.dart index c4340cf..78b5de3 100644 --- a/lib/features/renderer/raycast_painter.dart +++ b/lib/features/renderer/raycast_painter.dart @@ -1,9 +1,9 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; -import 'package:wolf_dart/classes/entity.dart'; import 'package:wolf_dart/classes/linear_coordinates.dart'; import 'package:wolf_dart/classes/matrix.dart'; +import 'package:wolf_dart/features/entities/entity.dart'; import 'package:wolf_dart/features/renderer/color_palette.dart'; class RaycasterPainter extends CustomPainter { diff --git a/lib/features/renderer/renderer.dart b/lib/features/renderer/renderer.dart index d77bc1e..d6df03b 100644 --- a/lib/features/renderer/renderer.dart +++ b/lib/features/renderer/renderer.dart @@ -3,13 +3,12 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; -import 'package:wolf_dart/classes/decorative.dart'; -import 'package:wolf_dart/classes/difficulty.dart'; -import 'package:wolf_dart/classes/enemy.dart'; -import 'package:wolf_dart/classes/entity.dart'; import 'package:wolf_dart/classes/linear_coordinates.dart'; import 'package:wolf_dart/classes/matrix.dart'; -import 'package:wolf_dart/features/enemies/brown_guard.dart'; +import 'package:wolf_dart/features/difficulty/difficulty.dart'; +import 'package:wolf_dart/features/entities/enemies/enemy.dart'; +import 'package:wolf_dart/features/entities/entity.dart'; +import 'package:wolf_dart/features/entities/entity_registry.dart'; import 'package:wolf_dart/features/map/wolf_map.dart'; import 'package:wolf_dart/features/renderer/raycast_painter.dart'; import 'package:wolf_dart/sprite_gallery.dart'; @@ -88,34 +87,17 @@ class _WolfRendererState extends State case 22: playerAngle = math.pi; } - } // 1. POPULATE DECORATIONS & DEAD BODIES - else if (Decorative.isDecoration(objId)) { - int spriteIdx = Decorative.getSpriteIndex(objId); - if (spriteIdx >= 0 && spriteIdx < gameMap.sprites.length) { - entities.add( - Decorative( - x: x + 0.5, - y: y + 0.5, - spriteIndex: spriteIdx, - mapId: objId, - // NEW: Dynamically assign the state! - state: objId == 124 ? EntityState.dead : EntityState.staticObj, - ), - ); - } - } else if (BrownGuard.isSpawnableForDifficulty( - objId, - widget.difficulty.level, - )) { - if (50 < gameMap.sprites.length) { - entities.add( - BrownGuard( - x: x + 0.5, - y: y + 0.5, - angle: Enemy.getInitialAngle(objId), - mapId: objId, - ), - ); + } else { + Entity? newEntity = EntityRegistry.spawn( + objId, + x + 0.5, + y + 0.5, + widget.difficulty.level, + gameMap.sprites.length, + ); + + if (newEntity != null) { + entities.add(newEntity); } } }