Skip to content

Instantly share code, notes, and snippets.

@walterpalladino
Created February 12, 2018 00:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save walterpalladino/3bd8cdfc282c1236ac94cc032b413514 to your computer and use it in GitHub Desktop.
Save walterpalladino/3bd8cdfc282c1236ac94cc032b413514 to your computer and use it in GitHub Desktop.
Unity Retro 2D Platform Platform Controller
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RetroPhysicsObject : MonoBehaviour {
// Boundary control
[System.Serializable]
public class BoundaryControl
{
public bool checkBoundaries = false;
public float boundaryLeft = 0;
public float boundaryRight = 1;
public float boundaryTop = 0;
public float boundaryBottom = 1;
}
public BoundaryControl boundaryControl;
private float movMinX;
private float movMaxX;
private float movMinY;
private float movMaxY;
[SerializeField]
private bool forceIntegerPositions = false;
public float customGravity = 9.8f;
protected Vector2 targetVelocity;
protected bool isGrounded;
protected Vector2 groundNormal;
protected Rigidbody2D rb2d;
protected Vector2 velocity;
protected int layerMask ;
protected const float minMoveDistance = 0.001f;
protected const float shellRadius = 0.01f;
protected BoxCollider2D bc2d;
void Awake () {
rb2d = GetComponent<Rigidbody2D> ();
bc2d = GetComponent<BoxCollider2D> ();
// Precaulculate the Maxs and Mins to check boundaries
Vector3 objectExtents ;
SpriteRenderer spriteRenderer;
spriteRenderer = GetComponent<SpriteRenderer> ();
objectExtents = spriteRenderer.bounds.extents;
// Works for Scale == 1
movMinX = boundaryControl.boundaryLeft + objectExtents.x ;
movMaxX = boundaryControl.boundaryRight - objectExtents.x ;
movMinY = boundaryControl.boundaryBottom + objectExtents.y ;
movMaxY = boundaryControl.boundaryTop - objectExtents.y ;
layerMask = LayerMask.GetMask ("Platform") | LayerMask.GetMask ("Wall");
}
void Update ()
{
targetVelocity = Vector2.zero;
ComputeVelocity ();
}
protected virtual void ComputeVelocity() {}
void FixedUpdate()
{
UpdateMovement ();
}
protected virtual void UpdateMovement () {
velocity -= customGravity * Vector2.up * Time.deltaTime;
velocity.x = targetVelocity.x;
isGrounded = false;
Vector2 deltaPosition = velocity * Time.deltaTime;
// Check movement along X (Ground)
Vector2 move = Vector2.right * deltaPosition.x;
Movement (move, false);
// Check movement along Y (Vertically)
move = Vector2.up * deltaPosition.y;
Movement (move, true);
}
protected void Movement (Vector2 move, bool yMovement)
{
float distance = move.magnitude;
RaycastHit2D hit ;
if (distance > minMoveDistance) {
// If the player is jumping will not test for collisions
if (!yMovement || (move.y < 0.01f)) {
Vector2 start = rb2d.position;
if (yMovement) {
start.y -= bc2d.bounds.extents.y;
} else {
start.x += bc2d.bounds.extents.x * Mathf.Sign (move.x);
}
Vector2 end = start + move;
hit = Physics2D.Linecast (start, end, layerMask, -Mathf.Infinity, distance + shellRadius);
if (hit.collider != null) {
if (yMovement) {
isGrounded = true;
velocity.y = 0.0f;
}
float modifiedDistance = hit.distance - shellRadius;
distance = modifiedDistance < distance ? modifiedDistance : distance;
}
}
UpdatePosition (rb2d.position + move.normalized * distance);
}
}
// This method controls the player movement inside boundaries
protected void UpdatePosition (Vector2 position) {
Vector2 newPosition = position;
if (boundaryControl.checkBoundaries) {
newPosition.x = Mathf.Clamp (newPosition.x, movMinX, movMaxX);
newPosition.y = Mathf.Clamp (newPosition.y, movMinY, movMaxY);
}
if (forceIntegerPositions) {
// Force the position x/y to integer values only
newPosition.x = Mathf.Floor (newPosition.x + 0.5f);
newPosition.y = Mathf.Floor (newPosition.y + 0.5f);
}
rb2d.position = newPosition ;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RetroPlatformController : RetroPhysicsObject {
[SerializeField]
private float walkingSpeed = 7;
[SerializeField]
private float jumpTakeOffSpeed = 7;
[SerializeField]
private float climbingSpeed = 7;
private SpriteRenderer spriteRenderer;
private Animator animator;
private float prevMovX = 0.0f;
private bool canClimb = false;
private Ladder ladder = null;
private bool isClimbing = false;
private bool hasStoppedClimbing = false;
private float deltaLadderBoundaries = 0.3f;
//
private Vector2 initialPosition;
private bool isDead = false;
// Use this for initialization
void Start ()
{
spriteRenderer = GetComponent<SpriteRenderer> ();
animator = GetComponent<Animator> ();
Ladder.onCanClimbChanged += OnCanClimbChanged;
// Store the initial position to respawn at the same place
initialPosition = rb2d.transform.position;
}
protected override void ComputeVelocity()
{
if (isDead) {
return;
}
Vector2 move = Vector2.zero;
if (isGrounded) {
if (Input.GetKey (KeyCode.A)) {
move.x = -1.0f;
} else if (Input.GetKey (KeyCode.D)) {
move.x = 1.0f;
}
prevMovX = move.x;
} else {
move.x = prevMovX;
}
bool flipSprite = (spriteRenderer.flipX ? (move.x < -0.01f) : (move.x > 0.01f)) ;
if (flipSprite)
{
spriteRenderer.flipX = !spriteRenderer.flipX;
}
// Check Ladder
if ((canClimb) && (isGrounded)) {
if (Input.GetKey (KeyCode.W)) {
if (IsPlayerOnLadderBottom()) {
isClimbing = true;
// Force x player position to the ladder center
Vector2 tmp = rb2d.position;
tmp.x = ladder.gameObject.transform.position.x;
rb2d.position = tmp;
}
} else if (Input.GetKey (KeyCode.S)) {
if (IsPlayerOnLadderTop ()) {
isClimbing = true;
// Force x player position to the ladder center
Vector2 tmp = rb2d.position;
tmp.x = ladder.gameObject.transform.position.x;
rb2d.position = tmp;
}
}
}
if (isClimbing) {
if (Input.GetKey (KeyCode.W)) {
targetVelocity = Vector2.up * climbingSpeed;
} else if (Input.GetKey (KeyCode.S)) {
targetVelocity = Vector2.up * -climbingSpeed;
}
} else {
if (Input.GetKey (KeyCode.W) && isGrounded) {
velocity.y = jumpTakeOffSpeed;
}
targetVelocity = move * walkingSpeed;
}
// Update the animations
if (animator != null) {
if (isGrounded && !isClimbing) {
animator.enabled = true;
if (Mathf.Abs (move.x) > 0.01f) {
animator.Play ("Henry Walk");
} else {
animator.Play ("Henry Idle");
}
} else if (isClimbing) {
animator.Play ("Henry Climb");
if (isGrounded) {
animator.enabled = true;
} else {
if (targetVelocity.y > 0.01f) {
animator.enabled = true;
} else if (targetVelocity.y < -0.01f) {
animator.enabled = true;
} else {
animator.enabled = false;
}
}
} else {
animator.enabled = true;
animator.Play ("Henry Jump");
}
}
}
public void OnCanClimbChanged (bool canClimb, Ladder ladder) {
this.canClimb = canClimb;
this.ladder = ladder;
}
private bool IsPlayerOnLadderBottom () {
if (ladder == null) {
return false;
}
BoxCollider2D ladderBc2d;
ladderBc2d = ladder.GetComponent<BoxCollider2D> ();
float ladderBottom = ladderBc2d.bounds.center.y - ladderBc2d.bounds.extents.y;
float playerBottom = bc2d.bounds.center.y - bc2d.bounds.extents.y;
if ((playerBottom - ladderBottom) < deltaLadderBoundaries) {
return true;
} else {
return false;
}
}
private bool IsPlayerOnLadderTop () {
if (ladder == null) {
return false;
}
BoxCollider2D ladderBc2d;
ladderBc2d = ladder.GetComponent<BoxCollider2D> ();
float ladderTop = ladderBc2d.bounds.center.y + ladderBc2d.bounds.extents.y;
float playerBottom = bc2d.bounds.center.y - bc2d.bounds.extents.y;
if ((ladderTop - playerBottom) < deltaLadderBoundaries) {
return true;
} else {
return false;
}
}
protected override void UpdateMovement () {
if (isClimbing) {
// Logic for ladder climbing
isGrounded = false;
// Check movement along Y (Vertically)
Vector2 newPosition = rb2d.position + Vector2.up * targetVelocity.y * Time.deltaTime;
if (targetVelocity.y > 0.01f) {
// Up - Check Top
if (IsPlayerOnLadderTop ()) {
// Adjust position on ground
BoxCollider2D ladderBc2d;
ladderBc2d = ladder.GetComponent<BoxCollider2D> ();
float ladderTop = ladderBc2d.bounds.center.y + ladderBc2d.bounds.extents.y;
newPosition.y = ladderTop + bc2d.bounds.extents.y + 0.01f;
isClimbing = false;
isGrounded = true;
}
} else if (targetVelocity.y < -0.01f) {
// Down - Check Bottom
if (IsPlayerOnLadderBottom ()) {
// Adjust position on ground
BoxCollider2D ladderBc2d;
ladderBc2d = ladder.GetComponent<BoxCollider2D> ();
float ladderBottom = ladderBc2d.bounds.center.y - ladderBc2d.bounds.extents.y;
newPosition.y = ladderBottom + bc2d.bounds.extents.y + 0.01f;
isClimbing = false;
isGrounded = true;
}
}
rb2d.position = newPosition;
} else {
// Logic for walking and jumping
base.UpdateMovement();
}
}
public void PlayerDied () {
isDead = true;
animator.enabled = true;
animator.Play ("Henry Died");
}
public void PlayerRespawn () {
isDead = false;
rb2d.transform.position = initialPosition;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment