Bootstrap fight system
- Fight World data structure - Generating basic fight world - Opening correct fight room - Block paths in fight rooms - Transition between rooms
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
using Godot;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public partial class FightSceneSetup : Node
|
||||
{
|
||||
[Export] private Label debugLabel;
|
||||
public override void _Ready()
|
||||
{
|
||||
var room = FightWorld.Instance.currentRoom!;
|
||||
debugLabel.Text = $"Room Debug:\n{room.paths.Count} paths out of this room\n{room.enemyGroups.Count} enemy groups:\n";
|
||||
foreach (var enemyGroup in room.enemyGroups)
|
||||
{
|
||||
debugLabel.Text += $" {enemyGroup.enemies.Count} enemies:\n";
|
||||
foreach (var enemy in enemyGroup.enemies)
|
||||
{
|
||||
debugLabel.Text += $" {enemy.type}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dbu8afaiohpdh
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Babushka.scripts.CSharp.Common.SceneManagement;
|
||||
using Godot;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public partial class FightSceneSwitcher : Node
|
||||
{
|
||||
[Export] private Node sceneRoot;
|
||||
[Export] private string fightRoomScenePath;
|
||||
[Export] private string fightingGroupScene;
|
||||
|
||||
private void LoadNext()
|
||||
{
|
||||
var nextRoom = FightWorld.Instance.currentRoom;
|
||||
Debug.Assert(nextRoom != null, "nextRoom!=null");
|
||||
var nextEnemyGroup = FightWorld.Instance.inFightWith;
|
||||
SceneTransitionThreaded.Instance.ChangeSceneToFile(nextEnemyGroup != null
|
||||
? fightingGroupScene
|
||||
: fightRoomScenePath);
|
||||
UnloadAfterDelay();
|
||||
}
|
||||
|
||||
private async void UnloadAfterDelay()
|
||||
{
|
||||
await ToSignal(GetTree().CreateTimer(1.0f), "timeout"); // 1.0f seconds
|
||||
sceneRoot.QueueFree();
|
||||
}
|
||||
|
||||
public void SwitchRoom(int pathIndex)
|
||||
{
|
||||
Debug.Assert(FightWorld.Instance.currentRoom != null, "FightWorld.Instance.currentRoom!=null");
|
||||
|
||||
if (!FightWorld.Instance.currentRoom.paths.TryGetValue(pathIndex, out var nextRoom))
|
||||
throw new Exception("Trying to go down a non-existent path");
|
||||
|
||||
FightWorld.Instance.currentRoom = nextRoom;
|
||||
LoadNext();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cql8mt5jsmcdl
|
||||
@@ -0,0 +1,159 @@
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public partial class FightWorld : Node
|
||||
{
|
||||
public class World
|
||||
{
|
||||
public required List<Room> rooms;
|
||||
}
|
||||
|
||||
public class Room
|
||||
{
|
||||
public required Dictionary<int, Room> paths;
|
||||
public required List<EnemyGroup> enemyGroups;
|
||||
}
|
||||
|
||||
public class EnemyGroup
|
||||
{
|
||||
public required List<Enemy> enemies;
|
||||
}
|
||||
|
||||
public class Enemy
|
||||
{
|
||||
public enum Type
|
||||
{
|
||||
Blob,
|
||||
BigBlob,
|
||||
Mavka,
|
||||
YourMom
|
||||
}
|
||||
|
||||
public required Type type;
|
||||
public required int? health = null; // null => initialize to full health on spawn
|
||||
}
|
||||
|
||||
#region AutoLoad ( Contains _EnterTree() )
|
||||
|
||||
public static FightWorld Instance { get; private set; } = null!;
|
||||
|
||||
public override void _EnterTree()
|
||||
{
|
||||
Instance = this;
|
||||
MyEnterTree();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public World? world = null;
|
||||
public Room? currentRoom = null;
|
||||
public EnemyGroup? inFightWith = null;
|
||||
|
||||
public void MyEnterTree()
|
||||
{
|
||||
Generate();
|
||||
currentRoom = world!.rooms[0];
|
||||
}
|
||||
|
||||
public void Generate()
|
||||
{
|
||||
world = new Generator().GenerateWorld();
|
||||
}
|
||||
|
||||
private class Generator
|
||||
{
|
||||
public World GenerateWorld()
|
||||
{
|
||||
var world = new World
|
||||
{
|
||||
rooms = GenerateRooms()
|
||||
};
|
||||
return world;
|
||||
}
|
||||
|
||||
private List<Room> GenerateRooms()
|
||||
{
|
||||
var rooms = new List<Room>();
|
||||
|
||||
var roomCount = 2;
|
||||
|
||||
for (var i = 0; i < roomCount; i++)
|
||||
{
|
||||
rooms.Add(GenerateDisconnectedRoom());
|
||||
}
|
||||
|
||||
// Connect rooms linearly
|
||||
for (var i = 0; i < rooms.Count - 1; i++)
|
||||
{
|
||||
rooms[i].paths[0] = rooms[i + 1];
|
||||
rooms[i + 1].paths[1] = rooms[i];
|
||||
}
|
||||
|
||||
return rooms;
|
||||
}
|
||||
|
||||
private Room GenerateDisconnectedRoom()
|
||||
{
|
||||
var room = new Room
|
||||
{
|
||||
paths = new Dictionary<int, Room>(),
|
||||
enemyGroups = GenerateEnemyGroups()
|
||||
};
|
||||
return room;
|
||||
}
|
||||
|
||||
private List<EnemyGroup> GenerateEnemyGroups()
|
||||
{
|
||||
var enemyGroups = new List<EnemyGroup>();
|
||||
|
||||
var enemyGroupCount = GD.RandRange(1, 3);
|
||||
|
||||
for (var i = 0; i < enemyGroupCount; i++)
|
||||
{
|
||||
enemyGroups.Add(GenerateSingleEnemyGroup());
|
||||
}
|
||||
|
||||
return enemyGroups;
|
||||
}
|
||||
|
||||
private EnemyGroup GenerateSingleEnemyGroup()
|
||||
{
|
||||
var enemyGroup = new EnemyGroup
|
||||
{
|
||||
enemies = []
|
||||
};
|
||||
|
||||
var enemyCount = GD.RandRange(1, 3);
|
||||
|
||||
for (var i = 0; i < enemyCount; i++)
|
||||
{
|
||||
enemyGroup.enemies.Add(GenerateSingleEnemy());
|
||||
}
|
||||
|
||||
return enemyGroup;
|
||||
}
|
||||
|
||||
private Enemy GenerateSingleEnemy()
|
||||
{
|
||||
var typeRoll = GD.RandRange(0, 99);
|
||||
|
||||
var type = typeRoll switch
|
||||
{
|
||||
< 50 => Enemy.Type.Blob,
|
||||
< 75 => Enemy.Type.BigBlob,
|
||||
< 90 => Enemy.Type.Mavka,
|
||||
_ => Enemy.Type.YourMom
|
||||
};
|
||||
|
||||
var enemy = new Enemy
|
||||
{
|
||||
type = type,
|
||||
health = null
|
||||
};
|
||||
|
||||
return enemy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dqe1i2qmpttwf
|
||||
@@ -0,0 +1,19 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public partial class NextRoomTrigger : Area2D
|
||||
{
|
||||
[Export] private int pathIndex;
|
||||
|
||||
public override void _EnterTree()
|
||||
{
|
||||
BodyEntered += _OnBodyEnter;
|
||||
}
|
||||
|
||||
private void _OnBodyEnter(Node2D other)
|
||||
{
|
||||
var fss = GetNode<FightSceneSwitcher>("%FightSceneSwitcher");
|
||||
fss.SwitchRoom(pathIndex);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bryibv73x5iwr
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Diagnostics;
|
||||
using Godot;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public partial class PathSetup : Node
|
||||
{
|
||||
[Export] private int pathId;
|
||||
|
||||
[ExportCategory("Variants")] [Export] private CanvasItem closedVariant;
|
||||
[Export] private CanvasItem nextRoomVariant;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
SetupPathVariant();
|
||||
}
|
||||
|
||||
private void SetupPathVariant()
|
||||
{
|
||||
Debug.Assert(FightWorld.Instance.currentRoom != null);
|
||||
if (FightWorld.Instance.currentRoom.paths.TryGetValue(pathId, out var nextRoom))
|
||||
{
|
||||
ShowOnlyVariant(nextRoomVariant);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowOnlyVariant(closedVariant);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowOnlyVariant(CanvasItem variantToShow)
|
||||
{
|
||||
HideVariant(closedVariant);
|
||||
HideVariant(nextRoomVariant);
|
||||
ShowVariant(variantToShow);
|
||||
}
|
||||
|
||||
private void ShowVariant(CanvasItem variant)
|
||||
{
|
||||
variant.Visible = true;
|
||||
variant.ProcessMode = ProcessModeEnum.Always;
|
||||
}
|
||||
|
||||
private void HideVariant(CanvasItem variant)
|
||||
{
|
||||
variant.Visible = false;
|
||||
variant.ProcessMode = ProcessModeEnum.Disabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dpkx2gbg7b5xh
|
||||
Reference in New Issue
Block a user