Re-introduce prototype code
This commit is contained in:
130
src/player/Player.cs
Normal file
130
src/player/Player.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public interface IPlayer : ICharacterBody3D
|
||||
{
|
||||
PlayerLogic PlayerLogic { get; }
|
||||
|
||||
PlayerData PlayerData { get; }
|
||||
|
||||
public Vector3 GetGlobalInputVector();
|
||||
}
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Player : CharacterBody3D, IPlayer, IProvide<PlayerLogic>
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
PlayerLogic IProvide<PlayerLogic>.Value() => PlayerLogic;
|
||||
|
||||
[Dependency] public IAppRepo AppRepo => this.DependOn<IAppRepo>();
|
||||
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
/// <summary>Rotation speed (quaternions?/sec).</summary>
|
||||
[Export(PropertyHint.Range, "0, 100, 0.1")]
|
||||
public float RotationSpeed { get; set; } = 0.5f;
|
||||
|
||||
/// <summary>Player speed (meters/sec).</summary>
|
||||
[Export(PropertyHint.Range, "0, 100, 0.1")]
|
||||
public float MoveSpeed { get; set; } = 2f;
|
||||
|
||||
/// <summary>Player speed (meters^2/sec).</summary>
|
||||
[Export(PropertyHint.Range, "0, 100, 0.1")]
|
||||
public float Acceleration { get; set; } = 1f;
|
||||
|
||||
public PlayerLogic.Settings Settings { get; set; } = default!;
|
||||
|
||||
public PlayerLogic PlayerLogic { get; set; } = default!;
|
||||
|
||||
public PlayerData PlayerData { get; set; } = default!;
|
||||
|
||||
public PlayerLogic.IBinding PlayerBinding { get; set; } = default!;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
Settings = new PlayerLogic.Settings(
|
||||
RotationSpeed,
|
||||
MoveSpeed);
|
||||
|
||||
PlayerLogic = new PlayerLogic();
|
||||
PlayerLogic.Set(this as IPlayer);
|
||||
PlayerLogic.Set(Settings);
|
||||
PlayerLogic.Set(AppRepo);
|
||||
PlayerLogic.Set(GameRepo);
|
||||
PlayerLogic.Set(PlayerData);
|
||||
|
||||
GameRepo.PlayerGlobalPosition.Sync += OnPlayerPositionUpdated;
|
||||
}
|
||||
|
||||
private void OnPlayerPositionUpdated(Vector3 globalPosition)
|
||||
{
|
||||
GlobalPosition = globalPosition;
|
||||
}
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
PlayerBinding = PlayerLogic.Bind();
|
||||
|
||||
PlayerBinding
|
||||
.Handle((in PlayerLogic.Output.MovementComputed output) =>
|
||||
{
|
||||
Transform = Transform with { Basis = output.Rotation };
|
||||
Velocity = output.Velocity;
|
||||
})
|
||||
.Handle((in PlayerLogic.Output.Animations.Attack output) =>
|
||||
{
|
||||
});
|
||||
|
||||
this.Provide();
|
||||
PlayerLogic.Start();
|
||||
}
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
SetPhysicsProcess(true);
|
||||
}
|
||||
|
||||
public void OnPhysicsProcess(double delta)
|
||||
{
|
||||
PlayerLogic.Input(new PlayerLogic.Input.PhysicsTick(delta));
|
||||
|
||||
var attackIsPressed = Input.IsActionJustPressed(GameInputs.Attack);
|
||||
if (attackIsPressed)
|
||||
PlayerLogic.Input(new PlayerLogic.Input.Attack());
|
||||
|
||||
MoveAndSlide();
|
||||
|
||||
PlayerLogic.Input(new PlayerLogic.Input.Moved(GlobalPosition));
|
||||
}
|
||||
|
||||
public Vector3 GetGlobalInputVector()
|
||||
{
|
||||
var rawInput = Input.GetVector(GameInputs.MoveLeft, GameInputs.MoveRight, GameInputs.MoveUp, GameInputs.MoveDown);
|
||||
|
||||
var input = new Vector3
|
||||
{
|
||||
X = rawInput.X,
|
||||
Z = rawInput.Y
|
||||
};
|
||||
return input with { Y = 0f };
|
||||
}
|
||||
|
||||
public void OnExitTree()
|
||||
{
|
||||
PlayerLogic.Stop();
|
||||
AppRepo.Dispose();
|
||||
GameRepo.Dispose();
|
||||
PlayerBinding.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/player/Player.tscn
Normal file
24
src/player/Player.tscn
Normal file
@@ -0,0 +1,24 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://cfecvvav8kkp6"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/player/Player.cs" id="1_xcol5"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_dw45s"]
|
||||
height = 1.2
|
||||
|
||||
[node name="Player" type="CharacterBody3D"]
|
||||
motion_mode = 1
|
||||
script = ExtResource("1_xcol5")
|
||||
RotationSpeed = 0.025
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.937567, 0)
|
||||
shape = SubResource("CapsuleShape3D_dw45s")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.19694, 0)
|
||||
|
||||
[node name="OmniLight3D" type="OmniLight3D" parent="."]
|
||||
omni_range = 73.156
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
22
src/player/PlayerData.cs
Normal file
22
src/player/PlayerData.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Chickensoft.Serialization;
|
||||
using Godot;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial record PlayerData
|
||||
{
|
||||
[Save("global_transform")]
|
||||
public required Transform3D GlobalTransform { get; init; }
|
||||
|
||||
[Save("state_machine")]
|
||||
public required PlayerLogic StateMachine { get; init; }
|
||||
|
||||
[Save("PlayerEquippedSword")]
|
||||
public required InventoryItem EquippedWeapon { get; set; }
|
||||
|
||||
[Save("PlayerInventory")]
|
||||
public required IEnumerable<InventoryItem> Inventory { get; set; }
|
||||
}
|
||||
}
|
||||
20
src/player/state/PlayerLogic.Input.cs
Normal file
20
src/player/state/PlayerLogic.Input.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public static class Input
|
||||
{
|
||||
public readonly record struct PhysicsTick(double Delta);
|
||||
|
||||
public readonly record struct Moved(Vector3 GlobalPosition);
|
||||
|
||||
public readonly record struct Enable;
|
||||
|
||||
public readonly record struct Attack;
|
||||
|
||||
public readonly record struct AttackAnimationFinished;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/player/state/PlayerLogic.Output.cs
Normal file
17
src/player/state/PlayerLogic.Output.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public static class Output
|
||||
{
|
||||
public static class Animations
|
||||
{
|
||||
public readonly record struct Attack;
|
||||
}
|
||||
|
||||
public readonly record struct MovementComputed(Basis Rotation, Vector3 Velocity);
|
||||
}
|
||||
}
|
||||
}
|
||||
9
src/player/state/PlayerLogic.Settings.cs
Normal file
9
src/player/state/PlayerLogic.Settings.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public record Settings(
|
||||
float RotationSpeed,
|
||||
float MoveSpeed);
|
||||
}
|
||||
}
|
||||
11
src/player/state/PlayerLogic.State.cs
Normal file
11
src/player/state/PlayerLogic.State.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
[Meta]
|
||||
public abstract partial record State : StateLogic<State>;
|
||||
}
|
||||
}
|
||||
14
src/player/state/PlayerLogic.cs
Normal file
14
src/player/state/PlayerLogic.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public interface IPlayerLogic : ILogicBlock<PlayerLogic.State>;
|
||||
|
||||
[Meta, Id("player_logic")]
|
||||
[LogicBlock(typeof(State), Diagram = true)]
|
||||
public partial class PlayerLogic : LogicBlock<PlayerLogic.State>, IPlayerLogic
|
||||
{
|
||||
public override Transition GetInitialState() => To<State.Idle>();
|
||||
}
|
||||
}
|
||||
20
src/player/state/PlayerLogic.g.puml
Normal file
20
src/player/state/PlayerLogic.g.puml
Normal file
@@ -0,0 +1,20 @@
|
||||
@startuml PlayerLogic
|
||||
state "PlayerLogic State" as GameJam2024Practice_PlayerLogic_State {
|
||||
state "Alive" as GameJam2024Practice_PlayerLogic_State_Alive {
|
||||
state "Idle" as GameJam2024Practice_PlayerLogic_State_Idle
|
||||
state "Attacking" as GameJam2024Practice_PlayerLogic_State_Attacking
|
||||
}
|
||||
state "Disabled" as GameJam2024Practice_PlayerLogic_State_Disabled
|
||||
}
|
||||
|
||||
GameJam2024Practice_PlayerLogic_State_Alive --> GameJam2024Practice_PlayerLogic_State_Alive : Moved
|
||||
GameJam2024Practice_PlayerLogic_State_Alive --> GameJam2024Practice_PlayerLogic_State_Alive : PhysicsTick
|
||||
GameJam2024Practice_PlayerLogic_State_Attacking --> GameJam2024Practice_PlayerLogic_State_Idle : AttackAnimationFinished
|
||||
GameJam2024Practice_PlayerLogic_State_Disabled --> GameJam2024Practice_PlayerLogic_State_Idle : Enable
|
||||
GameJam2024Practice_PlayerLogic_State_Idle --> GameJam2024Practice_PlayerLogic_State_Attacking : Attack
|
||||
|
||||
GameJam2024Practice_PlayerLogic_State_Alive : OnPhysicsTick → MovementComputed
|
||||
GameJam2024Practice_PlayerLogic_State_Idle : OnAttack → Attack
|
||||
|
||||
[*] --> GameJam2024Practice_PlayerLogic_State_Disabled
|
||||
@enduml
|
||||
19
src/player/state/states/PlayerLogic.State.Alive.Attacking.cs
Normal file
19
src/player/state/states/PlayerLogic.State.Alive.Attacking.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Chickensoft.Introspection;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record Attacking : Alive, IGet<Input.AttackAnimationFinished>
|
||||
{
|
||||
public Transition On(in Input.AttackAnimationFinished input)
|
||||
{
|
||||
return To<Idle>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/player/state/states/PlayerLogic.State.Alive.Idle.cs
Normal file
23
src/player/state/states/PlayerLogic.State.Alive.Idle.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public abstract partial record State
|
||||
{
|
||||
[Meta, Id("player_logic_state_alive_idle")]
|
||||
public partial record Idle : Alive, IGet<Input.Attack>
|
||||
{
|
||||
|
||||
public virtual Transition On(in Input.Attack input)
|
||||
{
|
||||
GD.Print("Attacking...");
|
||||
Output(new Output.Animations.Attack());
|
||||
return To<Attacking>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
41
src/player/state/states/PlayerLogic.State.Alive.cs
Normal file
41
src/player/state/states/PlayerLogic.State.Alive.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta, Id("player_logic_alive")]
|
||||
public abstract partial record Alive : State, IGet<Input.PhysicsTick>, IGet<Input.Moved>
|
||||
{
|
||||
public virtual Transition On(in Input.PhysicsTick input)
|
||||
{
|
||||
var player = Get<IPlayer>();
|
||||
var settings = Get<Settings>();
|
||||
|
||||
var rawInput = player.GetGlobalInputVector();
|
||||
|
||||
var transform = player.Transform;
|
||||
transform.Basis = new Basis(Vector3.Up, settings.RotationSpeed * -rawInput.X) * transform.Basis;
|
||||
var velocity = player.Basis * new Vector3(0, 0, rawInput.Z) * settings.MoveSpeed;
|
||||
|
||||
if (Godot.Input.IsActionPressed(GameInputs.Sprint))
|
||||
velocity *= 3;
|
||||
|
||||
Output(new Output.MovementComputed(transform.Basis, velocity));
|
||||
|
||||
return ToSelf();
|
||||
}
|
||||
|
||||
public virtual Transition On(in Input.Moved input)
|
||||
{
|
||||
var gameRepo = Get<IGameRepo>();
|
||||
gameRepo.SetPlayerGlobalPosition(input.GlobalPosition);
|
||||
return ToSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/player/state/states/PlayerLogic.State.Disabled.cs
Normal file
24
src/player/state/states/PlayerLogic.State.Disabled.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Chickensoft.Introspection;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public abstract partial record State
|
||||
{
|
||||
[Meta, Id("player_logic_state_disabled")]
|
||||
public partial record Disabled : State, IGet<Input.Enable>
|
||||
{
|
||||
public Disabled()
|
||||
{
|
||||
OnAttach(() => Get<IAppRepo>().GameEntered += OnGameEntered);
|
||||
OnDetach(() => Get<IAppRepo>().GameEntered -= OnGameEntered);
|
||||
}
|
||||
|
||||
public Transition On(in Input.Enable input) => To<Idle>();
|
||||
|
||||
public void OnGameEntered() => Input(new Input.Enable());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user