diff --git a/scenes/player/Player.cs b/scenes/player/Player.cs index 6eda834..2b1ed0c 100644 --- a/scenes/player/Player.cs +++ b/scenes/player/Player.cs @@ -1,35 +1,83 @@ using Godot; +using System; +using System.Collections.Generic; public class Player : KinematicBody2D { [Export] - private bool _invincible { get; set; } + private bool _isInvincible { get; set; } = false; + [Export] + private bool _canDoubleJump { get; set; } = true; + [Export] + private bool _cayoteTime { get; set; } = true; + [Export] + private int _maxWalkSpeed { get; set; } = 50; + [Export] + private int _maxRunSpeed { get; set; } = 150; private Event _eventBus; private Vector2 _velocity; + private AnimatedSprite _sprite; + private Camera2D _camera; + private Timer _cayoteTimer; + + private enum State + { + Idle, + Walk, + Jump, + DoubleJump, + Fall, + Swim + }; + + private Dictionary> _states; + private Stack _stateStack; public override void _Ready() { _eventBus = GetNode("/root/Event"); _eventBus.Connect("PlayerTouched", this, "PlayerTouched"); - _invincible = false; _velocity = new Vector2(); + _sprite = GetNode("AnimatedSprite"); + _camera = GetNode("Camera2D"); + + _cayoteTimer = GetNode("CayoteTimer"); + + _states = new Dictionary>(); + _states.Add(State.Idle, Idle); + _states.Add(State.Walk, Walk); + _states.Add(State.Fall, Fall); + _states.Add(State.Jump, Jump); + _states.Add(State.DoubleJump, Jump); + + _stateStack = new Stack(); + _stateStack.Push(State.Idle); } public override void _PhysicsProcess(float delta) { - _velocity.x = 0; + _states[_stateStack.Peek()].Invoke(delta); - if (Input.IsActionPressed("right")) + var maxSpeed = (Input.IsActionPressed("run")) ? _maxRunSpeed : _maxWalkSpeed; + + _velocity.x = Mathf.Clamp(_velocity.x, -_maxRunSpeed, _maxRunSpeed); + + if (_velocity.x > maxSpeed) { - _velocity.x += 50; + _velocity.x = Mathf.Lerp(maxSpeed, _velocity.x, 0.1f); } - if (Input.IsActionPressed("left")) { - _velocity.x -= 50; + if (_velocity.x < -maxSpeed) + { + _velocity.x = Mathf.Lerp(-maxSpeed, _velocity.x, 0.1f); } _velocity = MoveAndSlide(_velocity, Vector2.Up); + // Make sure the player is drawn in pixel perfect spacing + Mathf.Round(Position.x); + Mathf.Round(Position.y); + var count = GetSlideCount(); for (var i = 0; i < count; i++) { @@ -39,10 +87,200 @@ public class Player : KinematicBody2D { _eventBus.EmitSignal("PlayerTouched"); } + collision.Dispose(); } } - private void PlayerTouched() { + private void ApplyGravity(float delta) + { + _velocity.y += (int) ProjectSettings.GetSetting("physics/2d/default_gravity") * delta * 5; + } + + private void EnterState(State state) + { + _eventBus.EmitSignal("DebugState", state.ToString()); + _stateStack.Push(state); + ChangeStateMechanics(); + ChangeStateAnimation(); + } + + private void ExitState() + { + _stateStack.Pop(); + _eventBus.EmitSignal("DebugState", _stateStack.Peek().ToString()); + ChangeStateAnimation(); + } + + private void ChangeStateMechanics() + { + switch (_stateStack.Peek()) + { + case State.Jump: + _velocity.y = -250; + break; + case State.DoubleJump: + _velocity.y = -260; + break; + default: + _cayoteTimer.Stop(); + break; + } + } + + private void ChangeStateAnimation() + { + switch (_stateStack.Peek()) + { + case State.Idle: + _sprite.Play("idle"); + break; + case State.Walk: + _sprite.Play("walk"); + break; + case State.Fall: + _sprite.Play("jump"); + break; + case State.Jump: + _sprite.Play("jump"); + break; + } + } + + private void Idle(float delta) + { + ApplyGravity(delta); + + _velocity.x = Mathf.Lerp(_velocity.x, 0, 0.5f); + + if (Input.IsActionPressed("right") || Input.IsActionPressed("left")) + { + EnterState(State.Walk); + return; + } + + if (Input.IsActionJustPressed("jump")) + { + EnterState(State.Jump); + } + + if (!IsOnFloor()) + { + EnterState(State.Fall); + return; + } + } + + private void Walk(float delta) + { + ApplyGravity(delta); + + if (Input.IsActionPressed("right")) + { + _velocity.x += (_velocity.x < 0) ? 9 : 3; + + // Ice: + //_velocity.x += 3; + + _sprite.FlipH = false; + } + else if (Input.IsActionPressed("left")) + { + _velocity.x -= (_velocity.x > 0) ? 9 : 3; + + // Ice: + //_velocity.x -= 3; + + _sprite.FlipH = true; + } + else + { + ExitState(); + return; + } + + if (Input.IsActionJustPressed("jump")) + { + EnterState(State.Jump); + return; + } + + if (!IsOnFloor()) + { + if (!_cayoteTime) + { + EnterState(State.Fall); + } + else + { + if (_cayoteTimer.TimeLeft == 0) + { + _cayoteTimer.Start(); + } + } + return; + } + } + + private void Fall(float delta) + { + JumpMove(delta); + + if (IsOnFloor()) + { + ExitState(); + return; + } + } + + private void Jump(float delta) + { + JumpMove(delta); + + if (_canDoubleJump && _stateStack.Peek() != State.DoubleJump && Input.IsActionJustPressed("jump")) + { + EnterState(State.DoubleJump); + return; + } + + if (IsOnFloor()) + { + ExitState(); + return; + } + } + + private void JumpMove(float delta) + { + ApplyGravity(delta); + + if (Input.IsActionJustReleased("jump")) + { + if (_velocity.y < -100) + { + _velocity.y = -100; + return; + } + } + + if (Input.IsActionPressed("right")) + { + _velocity.x += (_velocity.x >= 20) ? 2 : 5; + _sprite.FlipH = false; + } + else if (Input.IsActionPressed("left")) + { + _velocity.x -= (_velocity.x <= -20) ? 2 : 5; + _sprite.FlipH = true; + } + } + + public void OnCayoteTimerTimeout() + { + EnterState(State.Fall); + } + + public void PlayerTouched() + { GD.Print("Touched"); } } diff --git a/scenes/player/Player.tscn b/scenes/player/Player.tscn index 492fbcb..e251a7c 100644 --- a/scenes/player/Player.tscn +++ b/scenes/player/Player.tscn @@ -131,8 +131,9 @@ animations = [ { extents = Vector2( 6, 6.5 ) [node name="Player" type="KinematicBody2D"] -collision_mask = 0 +collision_mask = 2 script = ExtResource( 10 ) +_canDoubleJump = false [node name="AnimatedSprite" type="AnimatedSprite" parent="."] frames = SubResource( 3 ) @@ -145,3 +146,8 @@ shape = SubResource( 4 ) [node name="Camera2D" type="Camera2D" parent="."] current = true + +[node name="CayoteTimer" type="Timer" parent="."] +wait_time = 0.2 + +[connection signal="timeout" from="CayoteTimer" to="." method="OnCayoteTimerTimeout"]