93 lines
2.9 KiB
C#
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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|