Files
przygody-pana-cegly/scripts/components/PlatformMovement.cs

169 lines
4.5 KiB
C#

using Godot;
using Mr.BrickAdventures.scripts.interfaces;
namespace Mr.BrickAdventures.scripts.components;
public partial class PlatformMovement : Node2D, IMovement
{
[Export]
public float Speed { get; set; } = 300.0f;
[Export]
public float JumpHeight { get; set; } = 100f;
[Export]
public float JumpTimeToPeak { get; set; } = 0.5f;
[Export]
public float JumpTimeToDescent { get; set; } = 0.4f;
[Export]
public int CoyoteFrames { get; set; } = 6;
[Export]
public AudioStreamPlayer2D JumpSfx { get; set; }
[Export]
public Node2D RotationTarget { get; set; }
[Export]
public CharacterBody2D Body { get; set; }
private float _gravity;
private bool _wasLastFloor = false;
private bool _coyoteMode = false;
private Timer _coyoteTimer;
private Vector2 _lastDirection = new Vector2(1, 0);
private float _jumpVelocity;
private float _jumpGravity;
private float _fallGravity;
public override void _Ready()
{
base._Ready();
if (Body == null)
return;
_gravity = (float)ProjectSettings.GetSetting("physics/2d/default_gravity");
_jumpVelocity = ((2.0f * JumpHeight) / JumpTimeToPeak) * -1.0f;
_jumpGravity = ((-2.0f * JumpHeight) / (JumpTimeToPeak * JumpTimeToPeak)) * -1.0f;
_fallGravity = ((-2.0f * JumpHeight) / (JumpTimeToDescent * JumpTimeToDescent)) * -1.0f;
_coyoteTimer = new Timer
{
OneShot = true,
WaitTime = CoyoteFrames / 60.0f
};
_coyoteTimer.Timeout += OnCoyoteTimerTimeout;
AddChild(_coyoteTimer);
}
public string MovementType { get; } = "platform";
public bool Enabled { get; set; }
public Vector2 PreviousVelocity { get; set; }
public override void _Process(double delta)
{
base._Process(delta);
if (Body == null || !Enabled)
return;
if (Body.Velocity.X > 0.0f)
RotationTarget.Rotation = Mathf.DegToRad(-10);
else if (Body.Velocity.X < 0.0f)
RotationTarget.Rotation = Mathf.DegToRad(10);
else
RotationTarget.Rotation = 0;
CalculateJumpVars();
}
public override void _PhysicsProcess(double delta)
{
base._PhysicsProcess(delta);
if (Body == null || !Enabled)
return;
if (Body.IsOnFloor())
{
_wasLastFloor = true;
_coyoteMode = false; // Reset coyote mode when back on the floor
_coyoteTimer.Stop(); // Stop timer when grounded
}
else
{
if (_wasLastFloor) // Start coyote timer only once
{
_coyoteMode = true;
_coyoteTimer.Start();
}
_wasLastFloor = false;
}
if (!Body.IsOnFloor())
Body.Velocity += new Vector2(0, CalculateGravity()) * (float)delta;
if (Input.IsActionPressed("jump") && (Body.IsOnFloor() || _coyoteMode))
Jump();
if (Input.IsActionJustPressed("down"))
Body.Position += new Vector2(0, 1);
float direction = Input.GetAxis("left", "right");
if (direction != 0)
_lastDirection = HandleDirection(direction);
if (direction != 0)
Body.Velocity = new Vector2(direction * Speed, Body.Velocity.Y);
else
Body.Velocity = new Vector2(Mathf.MoveToward(Body.Velocity.X, 0, Speed), Body.Velocity.Y);
Body.MoveAndSlide();
}
private void Jump()
{
if (Body == null)
return;
Body.Velocity = new Vector2(Body.Velocity.X, _jumpVelocity);
_coyoteMode = false;
if (JumpSfx != null)
JumpSfx.Play();
}
private float CalculateGravity()
{
return Body.Velocity.Y < 0.0f ? _jumpGravity : _fallGravity;
}
private void OnCoyoteTimerTimeout()
{
_coyoteMode = false;
}
private Vector2 HandleDirection(float inputDir)
{
if (inputDir > 0)
return new Vector2(1, 0);
else if (inputDir < 0)
return new Vector2(-1, 0);
return _lastDirection;
}
public void OnShipEntered()
{
RotationTarget.Rotation = 0;
}
private void CalculateJumpVars()
{
_jumpVelocity = ((2.0f * JumpHeight) / JumpTimeToPeak) * -1.0f;
_jumpGravity = ((-2.0f * JumpHeight) / (JumpTimeToPeak * JumpTimeToPeak)) * -1.0f;
_fallGravity = ((-2.0f * JumpHeight) / (JumpTimeToDescent * JumpTimeToDescent)) * -1.0f;
}
}