oldie/scenes/player/Player.cs

297 lines
6.9 KiB
C#

using Godot;
using System;
using System.Collections.Generic;
public class Player : KinematicBody2D
{
[Export]
private bool _isInvincible = false;
[Export]
private bool _canDoubleJump = true;
[Export]
private bool _cayoteTime = true;
[Export]
private int _maxWalkSpeed = 50;
[Export]
private int _maxRunSpeed = 150;
[Export]
private int _gravity = (int) ProjectSettings.GetSetting("physics/2d/default_gravity");
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<State, Action<float>> _states;
private Stack<State> _stateStack;
public override void _Ready()
{
_eventBus = GetNode<Event>("/root/Event");
_eventBus.Connect("PlayerTouched", this, "PlayerTouched");
_velocity = new Vector2();
_sprite = GetNode<AnimatedSprite>("AnimatedSprite");
_camera = GetNode<Camera2D>("Camera2D");
_cayoteTimer = GetNode<Timer>("CayoteTimer");
_states = new Dictionary<State, Action<float>>();
_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<State>();
_stateStack.Push(State.Idle);
}
public override void _PhysicsProcess(float delta)
{
_states[_stateStack.Peek()].Invoke(delta);
var maxSpeed = (Input.IsActionPressed("run")) ? _maxRunSpeed : _maxWalkSpeed;
_velocity.x = Mathf.Clamp(_velocity.x, -_maxRunSpeed, _maxRunSpeed);
if (_velocity.x > maxSpeed)
{
_velocity.x = Mathf.Lerp(maxSpeed, _velocity.x, 0.1f);
}
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++)
{
KinematicCollision2D collision = GetSlideCollision(i);
var collider = (Node) collision.Collider;
if (collider.IsInGroup("Enemy"))
{
_eventBus.EmitSignal("PlayerTouched");
}
else if (collider.IsInGroup("Block") && Vector2.Down.Dot(collision.Normal) > 0)
{
if (collider.HasMethod("Hit"))
{
collider.RemoveFromGroup("Block");
collider.CallDeferred("Hit");
}
}
collision.Dispose();
}
}
private void ApplyGravity(float delta)
{
_velocity.y += (int) _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");
}
}