Remove Main scene and script, add StateManagement library, update project structure documentation
This commit is contained in:
29
README.md
29
README.md
@@ -6,21 +6,32 @@ A game project built with Godot 4.5 and C#.
|
|||||||
|
|
||||||
This project uses the following custom libraries:
|
This project uses the following custom libraries:
|
||||||
- **EinSoftworks.Utilities** - Math and utility functions
|
- **EinSoftworks.Utilities** - Math and utility functions
|
||||||
- **EinSoftworks.Input** - Input management system
|
|
||||||
- **EinSoftworks.Events** - Event system for game communication
|
- **EinSoftworks.Events** - Event system for game communication
|
||||||
|
- **EinSoftworks.Input** - Input management system
|
||||||
|
- **EinSoftworks.StateManagement** - State machine system
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
voider/
|
voider/
|
||||||
├── Scenes/ # Game scenes (.tscn files)
|
├── Scenes/ # Game scenes (.tscn files)
|
||||||
|
│ ├── Core/ # Core game scenes
|
||||||
|
│ │ └── Main.tscn
|
||||||
|
│ ├── Player/ # Player scenes
|
||||||
|
│ ├── Enemies/ # Enemy scenes
|
||||||
|
│ ├── UI/ # UI scenes
|
||||||
|
│ └── Testing/ # Test scenes
|
||||||
|
│ └── LibraryTest.tscn
|
||||||
├── Scripts/ # C# scripts
|
├── Scripts/ # C# scripts
|
||||||
├── Resources/ # Game resources
|
│ ├── Core/ # Core game systems
|
||||||
│ ├── Textures/ # Images and sprites
|
│ │ ├── Main.cs
|
||||||
│ ├── Audio/ # Sound effects and music
|
│ │ └── EventManager.cs
|
||||||
│ └── Fonts/ # Font files
|
│ ├── Player/ # Player-related scripts
|
||||||
├── Prefabs/ # Reusable scene prefabs
|
│ ├── Enemies/ # Enemy scripts
|
||||||
└── UI/ # User interface scenes
|
│ ├── UI/ # UI scripts
|
||||||
|
│ └── Testing/ # Test and debug scripts
|
||||||
|
│ └── LibraryTest.cs
|
||||||
|
└── Docs/ # Documentation
|
||||||
```
|
```
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
@@ -33,6 +44,10 @@ dotnet build
|
|||||||
### Running
|
### Running
|
||||||
Open the project in Godot 4.5 and press F5 to run.
|
Open the project in Godot 4.5 and press F5 to run.
|
||||||
|
|
||||||
|
### Testing Libraries
|
||||||
|
Run the `Scenes/Testing/LibraryTest.tscn` scene (F6) to test all integrated libraries.
|
||||||
|
See `Docs/LIBRARY_TEST.md` for details.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
TBD
|
TBD
|
||||||
|
|||||||
6
Scenes/Core/Main.tscn
Normal file
6
Scenes/Core/Main.tscn
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://bvx8qw3yqn5yk"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://emch0q5mxf8k" path="res://Scripts/Core/Main.cs" id="1_1"]
|
||||||
|
|
||||||
|
[node name="Main" type="Node2D"]
|
||||||
|
script = ExtResource("1_1")
|
||||||
0
Scenes/LibraryTest.tscn
Normal file
0
Scenes/LibraryTest.tscn
Normal file
@@ -1,6 +0,0 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://bvx8qw3yqn5yk"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://emch0q5mxf8k" path="res://Scripts/Main.cs" id="1_1"]
|
|
||||||
|
|
||||||
[node name="Main" type="Node2D"]
|
|
||||||
script = ExtResource("1_1")
|
|
||||||
|
|||||||
6
Scenes/Testing/LibraryTest.tscn
Normal file
6
Scenes/Testing/LibraryTest.tscn
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://c8yv7qm3xwxqj"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://Scripts/Testing/LibraryTest.cs" id="1_library_test"]
|
||||||
|
|
||||||
|
[node name="LibraryTest" type="Node"]
|
||||||
|
script = ExtResource("1_library_test")
|
||||||
262
Scripts/Testing/LibraryTest.cs
Normal file
262
Scripts/Testing/LibraryTest.cs
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
using System;
|
||||||
|
using EinSoftworks.Events;
|
||||||
|
using EinSoftworks.Input;
|
||||||
|
using EinSoftworks.StateManagement;
|
||||||
|
using EinSoftworks.Utilities;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Voider;
|
||||||
|
|
||||||
|
public partial class LibraryTest : Node
|
||||||
|
{
|
||||||
|
private StateMachine<PlayerState> _stateMachine;
|
||||||
|
private HierarchicalStateMachine<string> _hierarchicalSM;
|
||||||
|
private EventBus<TestEvent> _eventBus;
|
||||||
|
private int _frameCount = 0;
|
||||||
|
private IdlePlayerState _idleState;
|
||||||
|
private RunningPlayerState _runningState;
|
||||||
|
private JumpingPlayerState _jumpingState;
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
GD.Print("=== EinSoftworks Library Integration Test ===\n");
|
||||||
|
|
||||||
|
TestUtilities();
|
||||||
|
TestEvents();
|
||||||
|
TestInput();
|
||||||
|
TestStateMachine();
|
||||||
|
TestHierarchicalStateMachine();
|
||||||
|
|
||||||
|
GD.Print("\n=== All Tests Initialized Successfully ===");
|
||||||
|
GD.Print("Watch console for runtime behavior...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _Process(double delta)
|
||||||
|
{
|
||||||
|
_frameCount++;
|
||||||
|
|
||||||
|
// Update state machines
|
||||||
|
_stateMachine?.Update((float)delta);
|
||||||
|
_hierarchicalSM?.Update((float)delta);
|
||||||
|
|
||||||
|
// Test transitions every 60 frames
|
||||||
|
if (_frameCount == 60)
|
||||||
|
{
|
||||||
|
GD.Print("\n[Frame 60] Testing state transitions...");
|
||||||
|
_stateMachine?.ChangeState(_runningState);
|
||||||
|
}
|
||||||
|
else if (_frameCount == 120)
|
||||||
|
{
|
||||||
|
GD.Print("\n[Frame 120] Testing event-triggered transition...");
|
||||||
|
_stateMachine?.TriggerEvent("jump");
|
||||||
|
}
|
||||||
|
else if (_frameCount == 180)
|
||||||
|
{
|
||||||
|
GD.Print("\n[Frame 180] Testing hierarchical state change...");
|
||||||
|
_hierarchicalSM?.ChangeState("Combat");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestUtilities()
|
||||||
|
{
|
||||||
|
GD.Print("--- Testing EinSoftworks.Utilities ---");
|
||||||
|
|
||||||
|
// Test MathUtils
|
||||||
|
float angle = 90f;
|
||||||
|
float radians = MathUtils.DegreesToRadians(angle);
|
||||||
|
GD.Print($"✓ DegreesToRadians: {angle}° = {radians} rad");
|
||||||
|
|
||||||
|
float backToDegrees = MathUtils.RadiansToDegrees(radians);
|
||||||
|
GD.Print($"✓ RadiansToDegrees: {radians} rad = {backToDegrees}°");
|
||||||
|
|
||||||
|
float value = 1.5f;
|
||||||
|
float clamped = MathUtils.Clamp01(value);
|
||||||
|
GD.Print($"✓ Clamp01: {value} clamped to {clamped}");
|
||||||
|
|
||||||
|
bool approx = MathUtils.Approximately(0.1f + 0.2f, 0.3f);
|
||||||
|
GD.Print($"✓ Approximately: 0.1 + 0.2 ≈ 0.3 = {approx}");
|
||||||
|
|
||||||
|
GD.Print("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestEvents()
|
||||||
|
{
|
||||||
|
GD.Print("--- Testing EinSoftworks.Events ---");
|
||||||
|
|
||||||
|
_eventBus = new EventBus<TestEvent>();
|
||||||
|
|
||||||
|
// Subscribe to events
|
||||||
|
_eventBus.Subscribe(OnTestEvent);
|
||||||
|
GD.Print($"✓ EventBus created with {_eventBus.SubscriberCount} subscriber");
|
||||||
|
|
||||||
|
// Publish an event
|
||||||
|
_eventBus.Publish(new TestEvent("Initialization", 42));
|
||||||
|
|
||||||
|
GD.Print("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestInput()
|
||||||
|
{
|
||||||
|
GD.Print("--- Testing EinSoftworks.Input ---");
|
||||||
|
|
||||||
|
// Create input contexts
|
||||||
|
var gameplayContext = new InputContext(
|
||||||
|
"Gameplay",
|
||||||
|
10,
|
||||||
|
InputContext.ContextMode.AllowList,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
gameplayContext.AllowAction("move_left");
|
||||||
|
gameplayContext.AllowAction("move_right");
|
||||||
|
gameplayContext.AllowAction("jump");
|
||||||
|
|
||||||
|
var menuContext = new InputContext("Menu", 20, InputContext.ContextMode.BlockList, true);
|
||||||
|
menuContext.BlockAction("move_left");
|
||||||
|
menuContext.BlockAction("move_right");
|
||||||
|
|
||||||
|
GD.Print(
|
||||||
|
$"✓ Created InputContext: {gameplayContext.Name} (Priority: {gameplayContext.Priority})"
|
||||||
|
);
|
||||||
|
GD.Print($"✓ Created InputContext: {menuContext.Name} (Priority: {menuContext.Priority})");
|
||||||
|
GD.Print(" (InputManager is a Node singleton - add to scene tree for full functionality)");
|
||||||
|
|
||||||
|
// Test InputBuffer
|
||||||
|
var inputBuffer = new InputBuffer(0.15f);
|
||||||
|
inputBuffer.BufferInput("jump");
|
||||||
|
bool hasJump = inputBuffer.IsInputBuffered("jump");
|
||||||
|
GD.Print($"✓ InputBuffer: Buffered 'jump' action, has buffered = {hasJump}");
|
||||||
|
|
||||||
|
GD.Print("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestStateMachine()
|
||||||
|
{
|
||||||
|
GD.Print("--- Testing EinSoftworks.StateManagement (Basic) ---");
|
||||||
|
|
||||||
|
_stateMachine = new StateMachine<PlayerState>();
|
||||||
|
|
||||||
|
// Create states
|
||||||
|
_idleState = new IdlePlayerState();
|
||||||
|
_runningState = new RunningPlayerState();
|
||||||
|
_jumpingState = new JumpingPlayerState();
|
||||||
|
|
||||||
|
// Subscribe to state changes
|
||||||
|
_stateMachine.StateChanged += (from, to) =>
|
||||||
|
{
|
||||||
|
GD.Print(
|
||||||
|
$" → State changed: {from?.GetType().Name ?? "null"} → {to?.GetType().Name ?? "null"}"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add transitions
|
||||||
|
_stateMachine.AddTransition(_idleState, _runningState, () => false); // Won't trigger automatically
|
||||||
|
_stateMachine.AddTransition(_runningState, _jumpingState, "jump");
|
||||||
|
|
||||||
|
// Set initial state
|
||||||
|
_stateMachine.ChangeState(_idleState);
|
||||||
|
|
||||||
|
GD.Print(
|
||||||
|
$"✓ StateMachine created with initial state: {_stateMachine.CurrentState?.GetType().Name}"
|
||||||
|
);
|
||||||
|
GD.Print("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestHierarchicalStateMachine()
|
||||||
|
{
|
||||||
|
GD.Print("--- Testing EinSoftworks.StateManagement (Hierarchical) ---");
|
||||||
|
|
||||||
|
_hierarchicalSM = new HierarchicalStateMachine<string>();
|
||||||
|
|
||||||
|
// Create parent states
|
||||||
|
var exploration = "Exploration";
|
||||||
|
var combat = "Combat";
|
||||||
|
|
||||||
|
// Create sub-state machine for combat
|
||||||
|
var combatSubStates = new StateMachine<string>();
|
||||||
|
combatSubStates.ChangeState("Attacking");
|
||||||
|
|
||||||
|
_hierarchicalSM.AddSubStateMachine(combat, combatSubStates);
|
||||||
|
|
||||||
|
// Subscribe to state changes
|
||||||
|
_hierarchicalSM.StateChanged += (from, to) =>
|
||||||
|
{
|
||||||
|
GD.Print($" → Hierarchical state changed: {from ?? "null"} → {to ?? "null"}");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set initial state
|
||||||
|
_hierarchicalSM.ChangeState(exploration);
|
||||||
|
|
||||||
|
GD.Print($"✓ HierarchicalStateMachine created with state: {_hierarchicalSM.CurrentState}");
|
||||||
|
GD.Print("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTestEvent(TestEvent evt)
|
||||||
|
{
|
||||||
|
GD.Print($" → Event received: {evt.Message} (Value: {evt.Value})");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _ExitTree()
|
||||||
|
{
|
||||||
|
// Cleanup
|
||||||
|
_eventBus?.Unsubscribe(OnTestEvent);
|
||||||
|
_stateMachine?.Clear();
|
||||||
|
_hierarchicalSM?.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test event class
|
||||||
|
public class TestEvent
|
||||||
|
{
|
||||||
|
public string Message { get; }
|
||||||
|
public int Value { get; }
|
||||||
|
|
||||||
|
public TestEvent(string message, int value)
|
||||||
|
{
|
||||||
|
Message = message;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Player state classes for testing
|
||||||
|
public abstract class PlayerState : State
|
||||||
|
{
|
||||||
|
protected string StateName;
|
||||||
|
|
||||||
|
public override void Enter()
|
||||||
|
{
|
||||||
|
GD.Print($" → Entering {StateName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float delta) { }
|
||||||
|
|
||||||
|
public override void FixedUpdate(float fixedDelta) { }
|
||||||
|
|
||||||
|
public override void Exit()
|
||||||
|
{
|
||||||
|
GD.Print($" → Exiting {StateName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IdlePlayerState : PlayerState
|
||||||
|
{
|
||||||
|
public IdlePlayerState()
|
||||||
|
{
|
||||||
|
StateName = "Idle";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RunningPlayerState : PlayerState
|
||||||
|
{
|
||||||
|
public RunningPlayerState()
|
||||||
|
{
|
||||||
|
StateName = "Running";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class JumpingPlayerState : PlayerState
|
||||||
|
{
|
||||||
|
public JumpingPlayerState()
|
||||||
|
{
|
||||||
|
StateName = "Jumping";
|
||||||
|
}
|
||||||
|
}
|
||||||
1
Scripts/Testing/LibraryTest.cs.uid
Normal file
1
Scripts/Testing/LibraryTest.cs.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dho35wh8iaest
|
||||||
@@ -10,5 +10,6 @@
|
|||||||
<ProjectReference Include="..\..\libraries\utilities\Utilities.csproj" />
|
<ProjectReference Include="..\..\libraries\utilities\Utilities.csproj" />
|
||||||
<ProjectReference Include="..\..\libraries\input\Input.csproj" />
|
<ProjectReference Include="..\..\libraries\input\Input.csproj" />
|
||||||
<ProjectReference Include="..\..\libraries\events\Events.csproj" />
|
<ProjectReference Include="..\..\libraries\events\Events.csproj" />
|
||||||
|
<ProjectReference Include="..\..\libraries\state-management\StateManagement.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ config_version=5
|
|||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="Voider"
|
config/name="Voider"
|
||||||
run/main_scene="res://Scenes/Main.tscn"
|
run/main_scene="res://Scenes/Core/Main.tscn"
|
||||||
config/features=PackedStringArray("4.5", "C#", "Forward Plus")
|
config/features=PackedStringArray("4.5", "C#", "Forward Plus")
|
||||||
|
|
||||||
[dotnet]
|
[dotnet]
|
||||||
|
|||||||
Reference in New Issue
Block a user