state machines
parent
9cd76af028
commit
ae0b914717
|
@ -1,5 +1,4 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace SupaLidlGame.Characters
|
namespace SupaLidlGame.Characters
|
||||||
{
|
{
|
||||||
|
@ -16,17 +15,35 @@ namespace SupaLidlGame.Characters
|
||||||
// Get the gravity from the project settings to be synced with RigidBody nodes.
|
// Get the gravity from the project settings to be synced with RigidBody nodes.
|
||||||
public float Gravity = ProjectSettings.GetSetting("physics/2d/default_gravity").AsSingle();
|
public float Gravity = ProjectSettings.GetSetting("physics/2d/default_gravity").AsSingle();
|
||||||
|
|
||||||
public Vector2 Direction { get; protected set; } = Vector2.Zero;
|
public Vector2 Direction { get; set; } = Vector2.Zero;
|
||||||
|
|
||||||
|
public Vector2 Target { get; set; } = Vector2.Zero;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public State.Machine StateMachine { get; set; }
|
||||||
|
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
|
if (StateMachine != null)
|
||||||
|
{
|
||||||
|
StateMachine.Process(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _Input(InputEvent @event)
|
||||||
|
{
|
||||||
|
if (StateMachine != null)
|
||||||
|
{
|
||||||
|
StateMachine.Input(@event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _PhysicsProcess(double delta)
|
public override void _PhysicsProcess(double delta)
|
||||||
{
|
{
|
||||||
// movement would be more crisp with no acceleration
|
if (StateMachine != null)
|
||||||
Velocity = Direction * Speed;
|
{
|
||||||
MoveAndSlide();
|
StateMachine.PhysicsProcess(delta);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
[gd_scene load_steps=4 format=3 uid="uid://dymwd5ihpwyqm"]
|
[gd_scene load_steps=7 format=3 uid="uid://dymwd5ihpwyqm"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://Characters/NPC.cs" id="1_4x3dm"]
|
[ext_resource type="Script" path="res://Characters/NPC.cs" id="1_4x3dm"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bw052v8ikfget" path="res://icon.svg" id="2_ujqd7"]
|
[ext_resource type="Texture2D" uid="uid://bw052v8ikfget" path="res://icon.svg" id="2_ujqd7"]
|
||||||
|
[ext_resource type="Script" path="res://Characters/States/Machine.cs" id="3_k4ypw"]
|
||||||
|
[ext_resource type="Script" path="res://Characters/States/NPCIdleState.cs" id="4_8r2qn"]
|
||||||
|
[ext_resource type="Script" path="res://Characters/States/NPCMoveState.cs" id="5_utogm"]
|
||||||
|
|
||||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_uict5"]
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_uict5"]
|
||||||
size = Vector2(32, 16)
|
size = Vector2(32, 16)
|
||||||
|
|
||||||
[node name="ExampleEnemy" type="CharacterBody2D"]
|
[node name="ExampleEnemy" type="CharacterBody2D" node_paths=PackedStringArray("StateMachine")]
|
||||||
script = ExtResource("1_4x3dm")
|
script = ExtResource("1_4x3dm")
|
||||||
Speed = 32.0
|
Speed = 32.0
|
||||||
|
StateMachine = NodePath("StateMachine")
|
||||||
|
|
||||||
[node name="Icon" type="Sprite2D" parent="."]
|
[node name="Icon" type="Sprite2D" parent="."]
|
||||||
scale = Vector2(0.25, 0.25)
|
scale = Vector2(0.25, 0.25)
|
||||||
|
@ -17,3 +21,16 @@ texture = ExtResource("2_ujqd7")
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
position = Vector2(0, 8)
|
position = Vector2(0, 8)
|
||||||
shape = SubResource("RectangleShape2D_uict5")
|
shape = SubResource("RectangleShape2D_uict5")
|
||||||
|
|
||||||
|
[node name="StateMachine" type="Node" parent="." node_paths=PackedStringArray("InitialState", "Character")]
|
||||||
|
script = ExtResource("3_k4ypw")
|
||||||
|
InitialState = NodePath("Idle")
|
||||||
|
Character = NodePath("..")
|
||||||
|
|
||||||
|
[node name="Idle" type="Node" parent="StateMachine" node_paths=PackedStringArray("MoveState")]
|
||||||
|
script = ExtResource("4_8r2qn")
|
||||||
|
MoveState = NodePath("../Move")
|
||||||
|
|
||||||
|
[node name="Move" type="Node" parent="StateMachine" node_paths=PackedStringArray("IdleState")]
|
||||||
|
script = ExtResource("5_utogm")
|
||||||
|
IdleState = NodePath("../Idle")
|
||||||
|
|
|
@ -8,9 +8,8 @@ namespace SupaLidlGame.Characters
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time in seconds it takes for the NPC to think FeelsDankCube
|
/// Time in seconds it takes for the NPC to think FeelsDankCube
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const float ThinkTime = 0.125f;
|
public const float ThinkTime = 0.25f;
|
||||||
|
|
||||||
public Character Target { get; protected set; }
|
|
||||||
public float[] Weights => _weights;
|
public float[] Weights => _weights;
|
||||||
|
|
||||||
float[] _weights = new float[16];
|
float[] _weights = new float[16];
|
||||||
|
@ -30,6 +29,7 @@ namespace SupaLidlGame.Characters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
if ((_thinkTimeElapsed += delta) > ThinkTime)
|
if ((_thinkTimeElapsed += delta) > ThinkTime)
|
||||||
|
@ -42,6 +42,7 @@ namespace SupaLidlGame.Characters
|
||||||
//Direction = (Target.GlobalPosition - GlobalPosition).Normalized();
|
//Direction = (Target.GlobalPosition - GlobalPosition).Normalized();
|
||||||
base._Process(delta);
|
base._Process(delta);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
public override void _Draw()
|
public override void _Draw()
|
||||||
{
|
{
|
||||||
|
@ -83,10 +84,21 @@ namespace SupaLidlGame.Characters
|
||||||
return bestChar;
|
return bestChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ThinkProcess(double delta)
|
||||||
|
{
|
||||||
|
if ((_thinkTimeElapsed += delta) > ThinkTime)
|
||||||
|
{
|
||||||
|
_thinkTimeElapsed = 0;
|
||||||
|
Think();
|
||||||
|
}
|
||||||
|
|
||||||
|
Direction = _weightDirs[_bestWeightIdx];
|
||||||
|
}
|
||||||
|
|
||||||
private void Think()
|
private void Think()
|
||||||
{
|
{
|
||||||
Vector2 pos = FindBestTarget().GlobalPosition;
|
Vector2 pos = FindBestTarget().GlobalPosition;
|
||||||
Vector2 dir = GlobalPosition.DirectionTo(pos);
|
Vector2 dir = Target = GlobalPosition.DirectionTo(pos);
|
||||||
float dist = GlobalPosition.DistanceSquaredTo(pos);
|
float dist = GlobalPosition.DistanceSquaredTo(pos);
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
|
@ -99,9 +111,9 @@ namespace SupaLidlGame.Characters
|
||||||
Vector2 rotatedDir = new Vector2(-dir.y, dir.x);
|
Vector2 rotatedDir = new Vector2(-dir.y, dir.x);
|
||||||
float horizDot = Math.Abs(_weightDirs[i].Dot(rotatedDir));
|
float horizDot = Math.Abs(_weightDirs[i].Dot(rotatedDir));
|
||||||
|
|
||||||
// this is a smaller weight so they are more likely to
|
// this is a smaller weight so they are more likely to pick the
|
||||||
// pick the direction they are currently heading when
|
// direction they are currently heading when choosing between two
|
||||||
// choosing between two horizontal weights
|
// horizontal weights
|
||||||
float currDirDot = (_weightDirs[i].Dot(Direction) + 1) / 16;
|
float currDirDot = (_weightDirs[i].Dot(Direction) + 1) / 16;
|
||||||
|
|
||||||
// square so lower values are even lower
|
// square so lower values are even lower
|
||||||
|
@ -158,7 +170,7 @@ namespace SupaLidlGame.Characters
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float dot = _weightDirs[i].Dot(_weightDirs[j]);
|
float dot = _weightDirs[i].Dot(_weightDirs[j]);
|
||||||
_weights[j] -= (dot + 1) / 4;
|
_weights[j] -= (dot + 1) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,16 +3,11 @@ using System;
|
||||||
|
|
||||||
namespace SupaLidlGame.Characters
|
namespace SupaLidlGame.Characters
|
||||||
{
|
{
|
||||||
public partial class Player : Character
|
public partial class Player : Character
|
||||||
{
|
{
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public override void _Process(double delta)
|
|
||||||
{
|
|
||||||
Direction = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,21 @@
|
||||||
[gd_scene load_steps=4 format=3 uid="uid://bncaar8vp3b84"]
|
[gd_scene load_steps=9 format=3 uid="uid://bncaar8vp3b84"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://Characters/Player.cs" id="1_flygr"]
|
[ext_resource type="Script" path="res://Characters/Player.cs" id="1_flygr"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bw052v8ikfget" path="res://icon.svg" id="2_xmgd1"]
|
[ext_resource type="Texture2D" uid="uid://bw052v8ikfget" path="res://icon.svg" id="2_xmgd1"]
|
||||||
|
[ext_resource type="Script" path="res://Characters/States/Machine.cs" id="3_npkjp"]
|
||||||
|
[ext_resource type="Script" path="res://Characters/States/PlayerIdleState.cs" id="4_4k4mb"]
|
||||||
|
[ext_resource type="Script" path="res://Characters/States/PlayerMoveState.cs" id="5_tx5rw"]
|
||||||
|
[ext_resource type="Script" path="res://Characters/States/PlayerRollState.cs" id="6_6bgrj"]
|
||||||
|
|
||||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_bfqew"]
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_bfqew"]
|
||||||
size = Vector2(32, 16)
|
size = Vector2(32, 16)
|
||||||
|
|
||||||
[node name="Node2D" type="CharacterBody2D"]
|
[sub_resource type="LabelSettings" id="LabelSettings_q5h1n"]
|
||||||
|
font_size = 24
|
||||||
|
|
||||||
|
[node name="Player" type="CharacterBody2D" node_paths=PackedStringArray("StateMachine")]
|
||||||
script = ExtResource("1_flygr")
|
script = ExtResource("1_flygr")
|
||||||
|
StateMachine = NodePath("StateMachine")
|
||||||
|
|
||||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
scale = Vector2(0.25, 0.25)
|
scale = Vector2(0.25, 0.25)
|
||||||
|
@ -21,4 +29,36 @@ shape = SubResource("RectangleShape2D_bfqew")
|
||||||
current = true
|
current = true
|
||||||
zoom = Vector2(4, 4)
|
zoom = Vector2(4, 4)
|
||||||
|
|
||||||
[node name="StateManager" type="Node" parent="."]
|
[node name="StateMachine" type="Node" parent="." node_paths=PackedStringArray("InitialState", "Character")]
|
||||||
|
script = ExtResource("3_npkjp")
|
||||||
|
InitialState = NodePath("Idle")
|
||||||
|
Character = NodePath("..")
|
||||||
|
DebugLevel = 2
|
||||||
|
|
||||||
|
[node name="Idle" type="Node" parent="StateMachine" node_paths=PackedStringArray("MoveState")]
|
||||||
|
script = ExtResource("4_4k4mb")
|
||||||
|
MoveState = NodePath("../Move")
|
||||||
|
|
||||||
|
[node name="Move" type="Node" parent="StateMachine" node_paths=PackedStringArray("IdleState", "RollState")]
|
||||||
|
script = ExtResource("5_tx5rw")
|
||||||
|
IdleState = NodePath("../Idle")
|
||||||
|
RollState = NodePath("../Roll")
|
||||||
|
|
||||||
|
[node name="Roll" type="Node" parent="StateMachine" node_paths=PackedStringArray("IdleState")]
|
||||||
|
script = ExtResource("6_6bgrj")
|
||||||
|
IdleState = NodePath("../Idle")
|
||||||
|
|
||||||
|
[node name="Debug" type="Control" parent="."]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 0
|
||||||
|
|
||||||
|
[node name="State" type="Label" parent="Debug"]
|
||||||
|
offset_left = -20.0
|
||||||
|
offset_top = -60.0
|
||||||
|
offset_right = 20.0
|
||||||
|
offset_bottom = -34.0
|
||||||
|
text = "lol"
|
||||||
|
label_settings = SubResource("LabelSettings_q5h1n")
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="Node" type="Node" parent="."]
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Characters.State
|
||||||
|
{
|
||||||
|
public partial class CharacterState : Node
|
||||||
|
{
|
||||||
|
public Character Character { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the <c>Character</c> enters this <c>CharacterState</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This returns a <c>CharacterState</c> in case a state is being
|
||||||
|
/// transitioned to but wants to transition to another state. For
|
||||||
|
/// example, an attack state can return to an idle state, but that idle
|
||||||
|
/// state can override it to the move state immediately when necessary.
|
||||||
|
/// </remarks>
|
||||||
|
public virtual CharacterState Enter(CharacterState previousState) => null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the <c>Character</c> exits this <c>CharacterState</c>.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Exit(CharacterState nextState) { }
|
||||||
|
|
||||||
|
public virtual CharacterState Process(double delta) => null;
|
||||||
|
|
||||||
|
public virtual CharacterState PhysicsProcess(double delta)
|
||||||
|
{
|
||||||
|
Character.Velocity = Character.Direction * Character.Speed;
|
||||||
|
Character.MoveAndSlide();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual CharacterState Input(InputEvent @event) => null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Characters.State
|
||||||
|
{
|
||||||
|
public partial class Machine : Node
|
||||||
|
{
|
||||||
|
protected Character _character;
|
||||||
|
|
||||||
|
public CharacterState State { get; protected set; }
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public CharacterState InitialState { get; set; }
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Character Character { get; set; }
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public int DebugLevel { get; set; }
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
ChangeState(InitialState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ChangeState(CharacterState nextState, bool isProxied = false)
|
||||||
|
{
|
||||||
|
if (DebugLevel >= 2)
|
||||||
|
{
|
||||||
|
if (State is not null)
|
||||||
|
{
|
||||||
|
string proxyNote = isProxied ? " (proxied)" : "";
|
||||||
|
GD.Print($"Transition{proxyNote} {State.Name} -> {nextState.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DebugLevel >= 1)
|
||||||
|
{
|
||||||
|
if (GetNode<Label>("../Debug/State") is Label label)
|
||||||
|
{
|
||||||
|
label.Text = nextState.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextState.Character = Character;
|
||||||
|
if (State != null)
|
||||||
|
{
|
||||||
|
State.Exit(nextState);
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextNextState = nextState.Enter(State);
|
||||||
|
|
||||||
|
State = nextState;
|
||||||
|
|
||||||
|
if (nextNextState is not null)
|
||||||
|
{
|
||||||
|
ChangeState(nextNextState, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Process(double delta)
|
||||||
|
{
|
||||||
|
CharacterState nextState = State.Process(delta);
|
||||||
|
if (nextState is not null)
|
||||||
|
{
|
||||||
|
ChangeState(nextState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PhysicsProcess(double delta)
|
||||||
|
{
|
||||||
|
CharacterState nextState = State.PhysicsProcess(delta);
|
||||||
|
if (nextState is not null)
|
||||||
|
{
|
||||||
|
ChangeState(nextState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Input(InputEvent @event)
|
||||||
|
{
|
||||||
|
CharacterState nextState = State.Input(@event);
|
||||||
|
if (nextState is not null)
|
||||||
|
{
|
||||||
|
ChangeState(nextState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace SupaLidlGame.Characters.State
|
||||||
|
{
|
||||||
|
public partial class MoveState : CharacterState
|
||||||
|
{
|
||||||
|
public override CharacterState PhysicsProcess(double delta)
|
||||||
|
{
|
||||||
|
return base.PhysicsProcess(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Characters.State
|
||||||
|
{
|
||||||
|
public partial class NPCIdleState : NPCState
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public CharacterState MoveState { get; set; }
|
||||||
|
|
||||||
|
public override CharacterState Process(double delta)
|
||||||
|
{
|
||||||
|
base.Process(delta);
|
||||||
|
if (Character.Direction.LengthSquared() > 0)
|
||||||
|
{
|
||||||
|
return MoveState;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Characters.State
|
||||||
|
{
|
||||||
|
public partial class NPCMoveState : NPCState
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public CharacterState IdleState { get; set; }
|
||||||
|
|
||||||
|
public override CharacterState Process(double delta)
|
||||||
|
{
|
||||||
|
base.Process(delta);
|
||||||
|
if (Character.Direction.LengthSquared() == 0)
|
||||||
|
{
|
||||||
|
return IdleState;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace SupaLidlGame.Characters.State
|
||||||
|
{
|
||||||
|
public partial class NPCState : CharacterState
|
||||||
|
{
|
||||||
|
protected NPC _npc => Character as NPC;
|
||||||
|
|
||||||
|
public override CharacterState Process(double delta)
|
||||||
|
{
|
||||||
|
_npc.ThinkProcess(delta);
|
||||||
|
return base.Process(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
using Godot;
|
||||||
|
using Godot.Collections;
|
||||||
|
using Godot.NativeInterop;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Characters.State
|
||||||
|
{
|
||||||
|
public partial class PlayerAttackState : PlayerState
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public CharacterState IdleState { get; set; }
|
||||||
|
|
||||||
|
private float _attackTime = 0;
|
||||||
|
|
||||||
|
public override CharacterState Enter(CharacterState previousState)
|
||||||
|
{
|
||||||
|
_attackTime = 0;
|
||||||
|
return base.Enter(previousState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Exit(CharacterState nextState)
|
||||||
|
{
|
||||||
|
_attackTime = 0;
|
||||||
|
base.Exit(nextState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CharacterState Input(InputEvent @event)
|
||||||
|
{
|
||||||
|
return base.Input(@event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CharacterState PhysicsProcess(double delta)
|
||||||
|
{
|
||||||
|
return base.PhysicsProcess(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CharacterState Process(double delta)
|
||||||
|
{
|
||||||
|
return base.Process(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Characters.State
|
||||||
|
{
|
||||||
|
public partial class PlayerIdleState : PlayerState
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public CharacterState MoveState { get; set; }
|
||||||
|
|
||||||
|
public override CharacterState Enter(CharacterState previousState)
|
||||||
|
{
|
||||||
|
GD.Print("Entered idle state");
|
||||||
|
if (previousState is not PlayerMoveState)
|
||||||
|
{
|
||||||
|
if (Character.Direction.LengthSquared() > 0)
|
||||||
|
{
|
||||||
|
// other states like attacking or rolling can just delegate
|
||||||
|
// the work of checking if the player is moving to this idle
|
||||||
|
// state, so they do not have to manually check if the player
|
||||||
|
// wants to move to switch to the move state.
|
||||||
|
return MoveState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base.Enter(previousState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CharacterState Process(double delta)
|
||||||
|
{
|
||||||
|
base.Process(delta);
|
||||||
|
if (Character.Direction.LengthSquared() > 0)
|
||||||
|
{
|
||||||
|
return MoveState;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Characters.State
|
||||||
|
{
|
||||||
|
public partial class PlayerMoveState : PlayerState
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public CharacterState IdleState { get; set; }
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public CharacterState RollState { get; set; }
|
||||||
|
|
||||||
|
public override CharacterState Enter(CharacterState previousState)
|
||||||
|
{
|
||||||
|
Godot.GD.Print("Started moving");
|
||||||
|
return base.Enter(previousState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CharacterState Process(double delta)
|
||||||
|
{
|
||||||
|
base.Process(delta);
|
||||||
|
if (Character.Direction.LengthSquared() == 0)
|
||||||
|
{
|
||||||
|
return IdleState;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CharacterState Input(Godot.InputEvent @event)
|
||||||
|
{
|
||||||
|
if (@event.IsActionPressed("roll"))
|
||||||
|
{
|
||||||
|
return RollState;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Characters.State
|
||||||
|
{
|
||||||
|
public partial class PlayerRollState : PlayerState
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public CharacterState IdleState { get; set; }
|
||||||
|
|
||||||
|
private double _timeLeftToRoll = 0;
|
||||||
|
|
||||||
|
private Vector2 _rollDirection = Vector2.Zero;
|
||||||
|
|
||||||
|
public override CharacterState Enter(CharacterState previousState)
|
||||||
|
{
|
||||||
|
_timeLeftToRoll = 0.5;
|
||||||
|
// roll the direction we were previously moving in
|
||||||
|
_rollDirection = Character.Direction;
|
||||||
|
return base.Enter(previousState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Exit(CharacterState nextState)
|
||||||
|
{
|
||||||
|
// we want to reset our state variables in case we are forced out of
|
||||||
|
// this state (e.g. from death)
|
||||||
|
_timeLeftToRoll = 0;
|
||||||
|
_rollDirection = Character.Direction;
|
||||||
|
base.Exit(nextState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CharacterState Process(double delta)
|
||||||
|
{
|
||||||
|
Character.Direction = _rollDirection;
|
||||||
|
if ((_timeLeftToRoll -= delta) <= 0)
|
||||||
|
{
|
||||||
|
return IdleState;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CharacterState PhysicsProcess(double delta)
|
||||||
|
{
|
||||||
|
Character.Velocity = Character.Direction * Character.Speed * 1.5f;
|
||||||
|
Character.MoveAndSlide();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
namespace SupaLidlGame.Characters.State
|
||||||
|
{
|
||||||
|
public partial class PlayerState : CharacterState
|
||||||
|
{
|
||||||
|
//public PlayerMachine PlayerMachine => Machine as PlayerMachine;
|
||||||
|
protected Player _player => Character as Player;
|
||||||
|
|
||||||
|
public override CharacterState Process(double delta)
|
||||||
|
{
|
||||||
|
Character.Direction = Godot.Input.GetVector("ui_left", "ui_right",
|
||||||
|
"ui_up", "ui_down");
|
||||||
|
return base.Process(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
|
@ -45,6 +45,11 @@ ui_down={
|
||||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null)
|
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
roll={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":3,"pressed":false,"double_click":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
[physics]
|
[physics]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue