Files
voider/Scripts/Testing/LibraryTest.cs

355 lines
11 KiB
C#

using System;
using EinSoftworks.Camera;
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;
// Camera test fields
private FirstPersonCamera _fpCamera;
private OrbitCamera _orbitCamera;
private Node3D _cameraTarget;
private CameraController _activeCamera;
public override void _Ready()
{
GD.Print("=== EinSoftworks Library Integration Test ===\n");
TestUtilities();
TestEvents();
TestInput();
TestStateMachine();
TestHierarchicalStateMachine();
TestCamera();
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");
}
else if (_frameCount == 240)
{
GD.Print("\n[Frame 240] Testing camera mode switch to Orbit...");
if (_orbitCamera != null && _activeCamera != null)
{
_activeCamera.SetCameraMode(CameraController.CameraMode.Orbit, 1.5f);
_orbitCamera.Visible = true;
_fpCamera.Visible = false;
_activeCamera = _orbitCamera;
}
}
else if (_frameCount == 360)
{
GD.Print("\n[Frame 360] Testing camera shake effect...");
_activeCamera?.Shake(0.3f, 0.5f);
}
else if (_frameCount == 420)
{
GD.Print("\n[Frame 420] Testing camera zoom effect...");
_activeCamera?.Zoom(60f, 1.0f);
}
}
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 TestCamera()
{
GD.Print("--- Testing EinSoftworks.Camera ---");
// Create a target node for cameras to follow
_cameraTarget = new Node3D();
_cameraTarget.Name = "CameraTarget";
_cameraTarget.Position = new Vector3(0, 1, 0);
AddChild(_cameraTarget);
// Create FirstPersonCamera
_fpCamera = new FirstPersonCamera();
_fpCamera.Name = "FirstPersonCamera";
_fpCamera.Target = _cameraTarget;
_fpCamera.MouseSensitivity = 0.15f;
_fpCamera.MinPitch = -85f;
_fpCamera.MaxPitch = 85f;
_fpCamera.Position = new Vector3(0, 1.6f, 0);
AddChild(_fpCamera);
_fpCamera.Camera.MakeCurrent();
_activeCamera = _fpCamera;
GD.Print($"✓ Created FirstPersonCamera (Active)");
GD.Print($" - Target: {_fpCamera.Target?.Name}");
GD.Print($" - Mouse Sensitivity: {_fpCamera.MouseSensitivity}");
GD.Print($" - Pitch Range: {_fpCamera.MinPitch}° to {_fpCamera.MaxPitch}°");
// Create OrbitCamera (initially hidden)
_orbitCamera = new OrbitCamera();
_orbitCamera.Name = "OrbitCamera";
_orbitCamera.Target = _cameraTarget;
_orbitCamera.MinDistance = 3f;
_orbitCamera.MaxDistance = 10f;
_orbitCamera.ZoomSpeed = 1f;
_orbitCamera.EnableCollisionAvoidance = true;
_orbitCamera.Visible = false;
AddChild(_orbitCamera);
GD.Print($"✓ Created OrbitCamera (Standby)");
GD.Print($" - Distance Range: {_orbitCamera.MinDistance} to {_orbitCamera.MaxDistance}");
GD.Print($" - Collision Avoidance: {_orbitCamera.EnableCollisionAvoidance}");
// Subscribe to camera events
_fpCamera.EventBus.Subscribe(evt =>
{
GD.Print($" → Camera event: {evt.OldMode} → {evt.NewMode} (Transition: {evt.TransitionTime}s)");
});
_fpCamera.CameraModeChanged += (oldMode, newMode) =>
{
GD.Print($" → Camera signal: Mode changed from {oldMode} to {newMode}");
};
GD.Print("✓ Subscribed to camera events and signals");
GD.Print(" (Camera will switch modes and demonstrate effects during runtime)");
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();
// Camera cleanup happens automatically
_fpCamera?.QueueFree();
_orbitCamera?.QueueFree();
_cameraTarget?.QueueFree();
}
}
// 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";
}
}