Major Player refactor

This commit is contained in:
2025-02-07 02:29:50 -08:00
parent 0cdae88952
commit fe1a1e61ef
132 changed files with 2554 additions and 2478 deletions

View File

@@ -1,8 +1,9 @@
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using GameJamDungeon;
using Godot;
namespace GameJamDungeon;
[Meta(typeof(IAutoNode))]
public partial class BossFloor : Node3D, IDungeonFloor
{

View File

@@ -3,67 +3,66 @@ using Chickensoft.Introspection;
using Godot;
using System.Linq;
namespace GameJamDungeon
namespace GameJamDungeon;
[Meta(typeof(IAutoNode))]
public partial class BossRoom : Node3D, IDungeonRoom
{
[Meta(typeof(IAutoNode))]
public partial class BossRoom : Node3D, IDungeonRoom
public override void _Notification(int what) => this.Notify(what);
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
[Node] public Marker3D PlayerSpawn { get; set; } = default!;
[Node] public Marker3D TeleportSpawn { get; set; } = default!;
[Node] public Marker3D ItemSpawnPoint { get; set; } = default!;
[Node] public ItemDatabase ItemDatabase { get; set; } = default!;
[Node] public Node3D HorseHeadStatue { get; set; } = default!;
[Node] public Node3D OxFaceStatue { get; set; } = default!;
[Node] public Boss OxFace { get; set; } = default!;
[Node] public Boss HorseFace { get; set; } = default!;
[Node] public Area3D ActivateTrap { get; set; } = default!;
[Node] public StaticBody3D GateCollision { get; set; } = default!;
public void Setup()
{
public override void _Notification(int what) => this.Notify(what);
SpawnItems();
ActivateTrap.BodyEntered += StartBossFight;
OxFace.CurrentHP.Sync += BossHPUpdate;
HorseFace.CurrentHP.Sync += BossHPUpdate;
}
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
private void BossHPUpdate(double obj)
{
if (OxFace.CurrentHP.Value <= 0 && HorseFace.CurrentHP.Value <= 0)
GateCollision.CallDeferred(MethodName.QueueFree);
}
[Node] public Marker3D PlayerSpawn { get; set; } = default!;
private void SpawnItems()
{
var database = ItemDatabase.Initialize().OfType<ConsumableItem>().ToArray();
var rng = new RandomNumberGenerator();
rng.Randomize();
var weights = database.Select(x => x.SpawnRate).ToArray();
var selectedItem = database[rng.RandWeighted(weights)];
var duplicated = selectedItem.Duplicate((int)DuplicateFlags.UseInstantiation) as Node3D;
duplicated.Position = ItemSpawnPoint.Position;
AddChild(duplicated);
}
[Node] public Marker3D TeleportSpawn { get; set; } = default!;
[Node] public Marker3D ItemSpawnPoint { get; set; } = default!;
[Node] public ItemDatabase ItemDatabase { get; set; } = default!;
[Node] public Node3D HorseHeadStatue { get; set; } = default!;
[Node] public Node3D OxFaceStatue { get; set; } = default!;
[Node] public Boss OxFace { get; set; } = default!;
[Node] public Boss HorseFace { get; set; } = default!;
[Node] public Area3D ActivateTrap { get; set; } = default!;
[Node] public StaticBody3D GateCollision { get; set; } = default!;
public void Setup()
{
SpawnItems();
ActivateTrap.BodyEntered += StartBossFight;
OxFace.CurrentHP.Sync += BossHPUpdate;
HorseFace.CurrentHP.Sync += BossHPUpdate;
}
private void BossHPUpdate(double obj)
{
if (OxFace.CurrentHP.Value <= 0 && HorseFace.CurrentHP.Value <= 0)
GateCollision.CallDeferred(MethodName.QueueFree);
}
private void SpawnItems()
{
var database = ItemDatabase.Initialize().OfType<ConsumableItem>().ToArray();
var rng = new RandomNumberGenerator();
rng.Randomize();
var weights = database.Select(x => x.Info.SpawnRate).ToArray();
var selectedItem = database[rng.RandWeighted(weights)];
var duplicated = selectedItem.Duplicate((int)DuplicateFlags.UseInstantiation) as Node3D;
duplicated.Position = ItemSpawnPoint.Position;
AddChild(duplicated);
}
private void StartBossFight(Node3D body)
{
OxFaceStatue.Hide();
HorseHeadStatue.Hide();
OxFace.Activate();
HorseFace.Activate();
}
private void StartBossFight(Node3D body)
{
OxFaceStatue.Hide();
HorseHeadStatue.Hide();
OxFace.Activate();
HorseFace.Activate();
}
}

View File

@@ -1,90 +1,83 @@
using Chickensoft.AutoInject;
using Chickensoft.GodotNodeInterfaces;
using Chickensoft.Introspection;
using Godot;
using System.Collections.Generic;
using System.Linq;
public interface IDungeonFloor : INode3D
namespace GameJamDungeon
{
void InitializeDungeon();
public Transform3D GetPlayerSpawnPoint();
public Vector3 GetTeleportSpawnPoint();
}
[Meta(typeof(IAutoNode))]
public partial class DungeonFloor : Node3D, IDungeonFloor
{
public override void _Notification(int what) => this.Notify(what);
[Node] public GodotObject DungeonGenerator { get; set; } = default!;
[Node] public NavigationRegion3D NavigationRegion3D { get; set; } = default!;
private Transform3D _playerSpawnPoint;
private Vector3 _teleportSpawnPoint;
internal List<IDungeonRoom> Rooms { get; private set; }
public void InitializeDungeon()
[Meta(typeof(IAutoNode))]
public partial class DungeonFloor : Node3D, IDungeonFloor
{
Rooms = new List<IDungeonRoom>();
DungeonGenerator.Call("generate");
NavigationRegion3D.BakeNavigationMesh();
Rooms = FindAllDungeonRooms([.. GetChildren()], Rooms);
_playerSpawnPoint = RandomizePlayerSpawnPoint();
_teleportSpawnPoint = RandomizeTeleportSpawnPointAwayFromPosition(_playerSpawnPoint.Origin);
}
public override void _Notification(int what) => this.Notify(what);
public Transform3D GetPlayerSpawnPoint() => _playerSpawnPoint;
[Node] public GodotObject DungeonGenerator { get; set; } = default!;
public Vector3 GetTeleportSpawnPoint() => _teleportSpawnPoint;
[Node] public NavigationRegion3D NavigationRegion3D { get; set; } = default!;
private Transform3D RandomizePlayerSpawnPoint()
{
var rng = new RandomNumberGenerator();
rng.Randomize();
var rngDistribution = new List<float>();
var randomSpawnLocations = Rooms
.Select(x => x.PlayerSpawn);
var godotCollection = new Godot.Collections.Array<Marker3D>(randomSpawnLocations);
var result = godotCollection.PickRandom();
return result.GlobalTransform;
}
private Transform3D _playerSpawnPoint;
private Vector3 RandomizeTeleportSpawnPointAwayFromPosition(Vector3 target)
{
var rng = new RandomNumberGenerator();
rng.Randomize();
var rngDistribution = new List<float>();
var roomsSortedByDistance = Rooms
.Select(x => x.TeleportSpawn.GlobalPosition)
.OrderByDescending(x => x.DistanceTo(target))
.ToArray();
var rngIndex = 1.0;
var rngSteps = rngIndex / roomsSortedByDistance.Count();
foreach (var room in roomsSortedByDistance)
private Vector3 _teleportSpawnPoint;
internal List<IDungeonRoom> Rooms { get; private set; }
public void InitializeDungeon()
{
rngIndex -= rngSteps;
rngDistribution.Add((float)rngIndex);
Rooms = new List<IDungeonRoom>();
DungeonGenerator.Call("generate");
NavigationRegion3D.BakeNavigationMesh();
Rooms = FindAllDungeonRooms([.. GetChildren()], Rooms);
_playerSpawnPoint = RandomizePlayerSpawnPoint();
_teleportSpawnPoint = RandomizeTeleportSpawnPointAwayFromPosition(_playerSpawnPoint.Origin);
}
var result = roomsSortedByDistance[rng.RandWeighted([.. rngDistribution])];
return result;
}
public Transform3D GetPlayerSpawnPoint() => _playerSpawnPoint;
private List<IDungeonRoom> FindAllDungeonRooms(List<Node> nodesToSearch, List<IDungeonRoom> roomsFound)
{
if (nodesToSearch.Count == 0)
return roomsFound;
public Vector3 GetTeleportSpawnPoint() => _teleportSpawnPoint;
foreach (var node in nodesToSearch)
if (node is IDungeonRoom dungeonRoom)
roomsFound.Add(dungeonRoom);
private Transform3D RandomizePlayerSpawnPoint()
{
var rng = new RandomNumberGenerator();
rng.Randomize();
var rngDistribution = new List<float>();
var randomSpawnLocations = Rooms
.Select(x => x.PlayerSpawn);
var godotCollection = new Godot.Collections.Array<Marker3D>(randomSpawnLocations);
var result = godotCollection.PickRandom();
return result.GlobalTransform;
}
return FindAllDungeonRooms(nodesToSearch.SelectMany(x => x.GetChildren()).ToList(), roomsFound);
private Vector3 RandomizeTeleportSpawnPointAwayFromPosition(Vector3 target)
{
var rng = new RandomNumberGenerator();
rng.Randomize();
var rngDistribution = new List<float>();
var roomsSortedByDistance = Rooms
.Select(x => x.TeleportSpawn.GlobalPosition)
.OrderByDescending(x => x.DistanceTo(target))
.ToArray();
var rngIndex = 1.0;
var rngSteps = rngIndex / roomsSortedByDistance.Length;
foreach (var room in roomsSortedByDistance)
{
rngIndex -= rngSteps;
rngDistribution.Add((float)rngIndex);
}
var result = roomsSortedByDistance[rng.RandWeighted([.. rngDistribution])];
return result;
}
private static List<IDungeonRoom> FindAllDungeonRooms(List<Node> nodesToSearch, List<IDungeonRoom> roomsFound)
{
if (nodesToSearch.Count == 0)
return roomsFound;
foreach (var node in nodesToSearch)
if (node is IDungeonRoom dungeonRoom)
roomsFound.Add(dungeonRoom);
return FindAllDungeonRooms(nodesToSearch.SelectMany(x => x.GetChildren()).ToList(), roomsFound);
}
}
}

View File

@@ -5,6 +5,7 @@ using GameJamDungeon;
using Godot;
using System.Linq;
namespace GameJamDungeon;
public interface IDungeonRoom : INode3D
{
public Marker3D PlayerSpawn { get; set; }
@@ -50,7 +51,7 @@ public partial class DungeonRoom : Node3D, IDungeonRoom
break;
numberOfItemsToSpawn--;
var weights = database.Select(x => x.Info.SpawnRate).ToArray();
var weights = database.Select(x => x.SpawnRate).ToArray();
var selectedItem = database[rng.RandWeighted(weights)];
var duplicated = selectedItem.Duplicate((int)DuplicateFlags.UseInstantiation) as Node3D;
duplicated.Position = new Vector3(spawnPoint.Position.X, -1.75f, spawnPoint.Position.Z);

View File

@@ -2,6 +2,7 @@
using Chickensoft.Introspection;
using Godot;
namespace GameJamDungeon;
[Meta(typeof(IAutoNode))]
public partial class Floor0 : Node3D, IDungeonFloor
{

View File

@@ -0,0 +1,12 @@
using Chickensoft.GodotNodeInterfaces;
using Godot;
namespace GameJamDungeon;
public interface IDungeonFloor : INode3D
{
void InitializeDungeon();
public Transform3D GetPlayerSpawnPoint();
public Vector3 GetTeleportSpawnPoint();
}

View File

@@ -2,6 +2,7 @@ using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
namespace GameJamDungeon;
[Meta(typeof(IAutoNode))]
public partial class MinimapManager : Area3D
{

View File

@@ -1,8 +1,8 @@
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using GameJamDungeon;
using Godot;
namespace GameJamDungeon;
[Meta(typeof(IAutoNode))]
public partial class Overworld : Node3D, IDungeonFloor
{

View File

@@ -705,7 +705,7 @@ skeleton = NodePath("")
[node name="PlayerSpawn" type="Marker3D" parent="Antechamber"]
unique_name_in_owner = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.61757, -2.04983, 0.580412)
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.61757, -1.89174, 0.580412)
[node name="ItemSpawnPoints" type="Node3D" parent="Antechamber"]
unique_name_in_owner = true