proto_platformer/Assets/Scripts/Player.cs

93 lines
2.9 KiB
C#

using System;
using UnityEngine;
using UnityEngine.InputSystem;
[RequireComponent(typeof(Rigidbody2D), typeof(BoxCollider2D))]
public class Player : MonoBehaviour
{
private Rigidbody2D _rigidbody;
private bool _wantsJump;
private bool _isJumping;
private bool _isGrounded;
private float _jumpStartTime;
private float _dir;
private Vector3 _oldPos;
public InputAction movement;
public InputAction jump;
public float speed = 4;
[Tooltip("This is the desired height, relative to the initial jump point, in unity units (meters)")]
public float jumpHeight;
[Tooltip("This is how long it takes to achieve the `jumpHeight` value")]
public float jumpDuration;
private void Start()
{
_rigidbody = GetComponent<Rigidbody2D>();
movement.Enable();
jump.Enable();
jump.started += JumpStart;
jump.canceled += JumpEnd;
Application.targetFrameRate = 144;
}
private void JumpStart(InputAction.CallbackContext callbackContext)
{
_wantsJump = true;
}
private void JumpEnd(InputAction.CallbackContext callbackContext)
{
_wantsJump = false;
_isJumping = false;
}
private void Update()
{
_dir = movement.ReadValue<float>();
_oldPos = _rigidbody.position;
_oldPos.x += _dir * speed * Time.deltaTime;
if (_wantsJump && _isGrounded)
{
_isJumping = true;
_isGrounded = false;
_jumpStartTime = Time.time;
}
if (_isJumping && _wantsJump && _jumpStartTime + jumpDuration > Time.time)
{
_rigidbody.gravityScale = 0;
var metersPerSecond = jumpHeight / jumpDuration;
// This simulates "acceleration" or rather the immediate force of a jump and the falloff due to gravity,
// without actually using gravity. That sounds odd, and maybe it can be improved, but this was the first
// solution that gives the designer a maximum height to hit over a duration while allowing the user to
// end the jump early (like most SNES era platformers). All this while still looking good or "correct".
// TODO: I think the closer the end value (b in the lerp function) is to 0 the more "correct" it will look.
var accelerationCoefficient = Mathf.Lerp(1.5f, 0.5f, (Time.time - _jumpStartTime) / jumpDuration);
_oldPos.y += accelerationCoefficient * metersPerSecond * Time.deltaTime;
}
else
{
_rigidbody.gravityScale = 1;
}
_rigidbody.position = _oldPos;
}
private void OnCollisionEnter2D(Collision2D other)
{
foreach (var contacts in other.contacts)
{
if (contacts.point.y < _rigidbody.position.y)
{
// we are grounded and can exit!
_isGrounded = true;
return;
}
}
}
}