Skip to content

Instantly share code, notes, and snippets.

@LiamPerson
Last active April 29, 2021 08:26
Show Gist options
  • Save LiamPerson/ed28083c7a649b302d30f5ff1520d49c to your computer and use it in GitHub Desktop.
Save LiamPerson/ed28083c7a649b302d30f5ff1520d49c to your computer and use it in GitHub Desktop.
Physics-compliant 2D Platformer Movement in Unity using Rigidbody2D
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class Movement : MonoBehaviour
{
// Rigidbody contained on the object this script is attached to.
private Rigidbody2D rb;
// Player size and ground detection for jumping.
public Vector2 PlayerSize = new Vector2(1f, 1f);
public float GroundDetectionLength = 0.1f;
// Movement settings.
public float Acceleration = 2;
public float MaxSpeed = 8;
public float GroundFriction = 1;
public float JumpHeight = 3f;
// Transfers jump button to fixedUpdate.
private bool JumpPressed = false;
void Start()
{
// Get the rigidbody.
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
// If jump button is pressed, set jump pressed to true.
if (Input.GetButtonDown("Jump"))
JumpPressed = true;
}
void FixedUpdate()
{
// Scale acceleration by target velocity and clamp it between 0 and Accelleration.
float scaledAcceleration = Acceleration * (1 - Mathf.Abs(rb.velocity.x) / MaxSpeed);
// Simulate friction.
if (rb.velocity.x > 0)
rb.velocity = new Vector2(rb.velocity.x - Mathf.Min(GroundFriction, rb.velocity.x), rb.velocity.y); // Velocity is positive.
else if (rb.velocity.x < 0)
rb.velocity = new Vector2(rb.velocity.x - Mathf.Max(-GroundFriction, rb.velocity.x), rb.velocity.y); // Velocity is negative.
// Add scaled acceleration to velocity in the direction of the horizontal axis.
rb.velocity += new Vector2(scaledAcceleration * Input.GetAxis("Horizontal"), 0);
// Simulate jumping.
if(JumpPressed && CheckIsGrounded())
{
JumpPressed = false;
rb.AddForce(Vector2.up * JumpHeight);
}
}
/// <summary>
/// Checks if this object is grounded based on defined PlayerSize field.
/// </summary>
bool CheckIsGrounded()
{
// Check what is below us.
RaycastHit2D[] collisions = Physics2D.BoxCastAll(rb.position, PlayerSize, rb.rotation, transform.TransformDirection(Vector2.down), GroundDetectionLength);
// Check if any of the collided objects are solid.
foreach(RaycastHit2D hit in collisions)
{
// Get the collider and check if its solid and not the current game object.
if (!hit.collider.isTrigger && hit.collider.gameObject != gameObject)
return true;
}
// If nothing was a trigger, return false.
return false;
}
/// <summary>
/// Draws the character PlayerSize box and the ground detection box.
/// </summary>
private void OnDrawGizmosSelected()
{
// Change drawing matrix to local space.
Gizmos.matrix = transform.localToWorldMatrix;
// Draw the character shape.
Gizmos.color = new Color(.68f, .04f, .37f); // Purple
Gizmos.DrawWireCube(Vector2.zero, PlayerSize);
// Draw the ground detection length.
Gizmos.color = new Color(1f, .74f, 0f); // Orange
Gizmos.DrawWireCube(Vector2.zero - new Vector2(0, PlayerSize.y / 2 + GroundDetectionLength / 2), new Vector2(PlayerSize.x, GroundDetectionLength));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment