Skip to main content

2D

Contents

Player Movement

All possible methods

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Controller2D : MonoBehaviour
{
public float horizontalMoveSpeed;
public float jumpStrength;

public bool isGrounded = true;

private float horizontalMovementInput;
private bool jumpInput = false;

private Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}


void Update()
{
// Take Input in Update and Act Upon it in FixedUpdate

horizontalMovementInput = Input.GetAxisRaw("Horizontal");

if (Input.GetButtonDown("Jump"))
{
jumpInput = true;
}

}

private void FixedUpdate()
{
// MoveHorizontalWithSmoothDamp(horizontalMovementInput);
//! MoveHorizontalWithSmoothDampTwo(horizontalMovementInput);
MoveHorizontalWithVelocity(horizontalMovementInput);
// MoveHorizontalWithAddForce(horizontalMovementInput);
//! MoveHorizontalWithMovePosition(horizontalMovementInput);
//! MoveHorizontalWithTransformPosition(horizontalMovementInput);
//! MoveHorizontalWithTransformTranslate(horizontalMovementInput);

// JumpWithAddForce();
// JumpWithSmoothDamping();
JumpWithVelocity();

FallFaster();
}

#region HorizontalMovement

private Vector2 currentHorizontalVelocity = Vector2.zero;
private float HorizontalMovementSmoothing = 0.01f;

private float maxSpeed = 20f;

// * Documentation
// Vector2 SmoothDamp(Vector2 current, Vector2 target, ref Vector2 currentVelocity, float smoothTime, float maxSpeed = Mathf.Infinity, float deltaTime = Time.deltaTime);
private void MoveHorizontalWithSmoothDamp(float horizontalMovementInput)
{
// use horizontalMoveSpeed = 20

Vector2 targetVelocity = new Vector2(horizontalMovementInput * horizontalMoveSpeed, rb.velocity.y);
rb.velocity = Vector2.SmoothDamp(rb.velocity, targetVelocity, ref currentHorizontalVelocity, HorizontalMovementSmoothing, maxSpeed, Time.deltaTime);

// ? NOTE
// Movement is similar to inertia and AddForce method?
}

private void MoveHorizontalWithSmoothDampTwo(float horizontalMovementInput)
{
// use horizontalMoveSpeed = 15
Vector2 currentHorizontalPosition = new Vector2(transform.position.x, transform.position.y);
Vector2 targetHorizontalPosition = currentHorizontalPosition + new Vector2(horizontalMovementInput * horizontalMoveSpeed, 0);
Vector2 currentHorizontalVelocityTwo = rb.velocity;
rb.velocity = Vector2.SmoothDamp(currentHorizontalPosition, targetHorizontalPosition, ref currentHorizontalVelocityTwo, HorizontalMovementSmoothing, maxSpeed, Time.deltaTime);

// ! TEST. DOES NOT WORK!
}

private void MoveHorizontalWithVelocity(float horizontalMovementInput)
{
// use horizontalMoveSpeed = 500
rb.velocity = new Vector2(horizontalMovementInput * horizontalMoveSpeed * Time.deltaTime, rb.velocity.y);
}

private void MoveHorizontalWithAddForce(float horizontalMovementInput)
{
// use horizontalMoveSpeed = 55
Vector2 horizontalMovement = new Vector2(horizontalMovementInput, 0.0f);
rb.AddForce(horizontalMovement * horizontalMoveSpeed * Time.deltaTime, ForceMode2D.Impulse);

// * NOTE
// Movement feels laggy due to inertia
// Player keeps moving even after releasing keys until other forces stop it
}

private void MoveHorizontalWithMovePosition(float horizontalMovementInput)
{
// use horizontalMoveSpeed = 15
Vector2 horizontalMovement = new Vector2(horizontalMovementInput, 0f);
rb.MovePosition((Vector2)transform.position + (horizontalMovement * horizontalMoveSpeed * Time.deltaTime));

// !! NOTE
// ! Affects Gravity
// Player falls slowly to ground and jump does not work
// * According to Unity Docs
// MovePosition is intended for use with kinematic rigidbodies.

}

private void MoveHorizontalWithTransformPosition(float horizontalMovementInput)
{
// use horizontalMoveSpeed = 15
Vector3 movement = new Vector3(horizontalMovementInput, 0.0f, 0.0f);
transform.position += movement * horizontalMoveSpeed * Time.deltaTime;

// !! NOTE
// ! Object Colliders don't work at high speeds

}

private void MoveHorizontalWithTransformTranslate(float horizontalMovementInput)
{
// use horizontalMoveSpeed = 15
Vector3 movement = new Vector3(horizontalMovementInput, 0.0f, 0.0f);
transform.Translate(movement * horizontalMoveSpeed * Time.deltaTime, Space.World);


// !! NOTE
// ! Object Colliders don't work at high speeds

// * Usage
// Use where physics is not used
// ex: Swiping between UI screens

}

// ? Make Player Kinematic
// Add gravity by adding a downward velocity Physics2D.gravity.y
private void MoveHorizontalWithKinematicBody(float horizontalMovementInput)
{


}

#endregion



#region Jump

private void JumpWithAddForce()
{
// use jumpStrength = 1000
if (jumpInput)
{
jumpInput = false;
rb.AddForce(new Vector2(0f, jumpStrength * Time.deltaTime), ForceMode2D.Impulse);
}
// GravitScale for Player = 3

}


private Vector2 currentVerticalVelocity = Vector2.zero;
private float VerticalMovementSmoothing = 0.01f;

private void JumpWithSmoothDamping()
{
// use jumpStrength = 25
if (jumpInput)
{
jumpInput = false;
Vector2 targetVelocity = new Vector2(rb.velocity.x, jumpStrength);
rb.velocity = Vector2.SmoothDamp(rb.velocity, targetVelocity, ref currentVerticalVelocity, VerticalMovementSmoothing, Mathf.Infinity, Time.deltaTime);
}

}

private void JumpWithVelocity()
{
// use jumpStrength = 1000
if (jumpInput)
{
jumpInput = false;
Vector2 jump = new Vector2(rb.velocity.x, jumpStrength * Time.deltaTime);
rb.velocity = jump;
}

// ? NOTE
// Slows HorizontalSpeed abruptly when combined with HorizontalSmoothDamping

}

public float fallMultiplier;
// use fallMultiplier = 2;

public float lowJumpMultiplier;
// use

private void FallFaster()
{
// If player is falling (negative Y velocity)
// Add additional downward velocity with increased gravitational force
if (rb.velocity.y < 0)
{
rb.velocity += Vector2.up * Physics2D.gravity.y * fallMultiplier * Time.deltaTime;
}
else if (rb.velocity.y > 0 && !Input.GetButton("Jump"))
{
// if player just tapped jump button AND is NOT holding down
// results in a smaller jump
// Add additional downward velocity with slightly increased gravitational force
rb.velocity += Vector2.up * Physics2D.gravity.y * lowJumpMultiplier * Time.deltaTime;
}
}

#endregion


}

Unity Microgame Platformer Method

  • Use kinematic object and add gravity manually ?? Physics2D.gravity

One Way Jumping Platform

  • Source: BalckThornProd YouTube Channel

  • Create a sprite with 16 x 4 pixels

  • Use 8 PixelPerUnit in Unity to make the platform thinner than normal platforms

  • Use MeshType FullRect

  • Drag into Scene

  • Change DrawMode Tiled

  • TileMode Adaptive

  • Now Tile can be resized using the RectTool

  • Add BoxCollider2D

  • Enable AutoTiling

  • Add PlatformEffector2D Component

  • Enable UseByEffector in BoxCollider2D

    public class OneWayPlatform : MonoBehaviour
    {
    private float keyHoldTime = 0.2f;

    private float keyHoldTimer;

    private PlatformEffector2D platformEffector2D;

    void Start()
    {
    platformEffector2D = GetComponent<PlatformEffector2D>();
    }

    void Update()
    {
    if(Input.GetKeyUp(KeyCode.S)){
    // if player releases the down key
    // reset the timer
    keyHoldTimer = keyHoldTime;
    }

    if (Input.GetKey(KeyCode.S))
    {
    if (keyHoldTimer <= 0)
    {
    // if the player holds the key for long enough disable the platform
    platformEffector2D.rotationalOffset = 180f;
    keyHoldTimer = keyHoldTime;
    }
    else
    {
    // count the time player has held the key
    keyHoldTimer -= Time.deltaTime;
    }
    }

    if(Input.GetButtonDown("Jump") || Input.GetKeyDown(KeyCode.W)){
    // reset the platform whenever player wants to jump
    // or if the player is climbing a ladder
    // reset the top of ladder
    platformEffector2D.rotationalOffset = 0f;
    }
    }
    }

Ladder

Using Raycast Method

  • Source: BlackThornProd YouTube Channel

  • Create a Sprite 16 x 4 pixels

  • Use 8 PixelPerUnit in Unity

  • Use MeshType FullRect

  • Drag into Scene

  • Change DrawMode Tiled

  • TileMode Adaptive

  • Drag vertically to elongate the ladder

  • Add BoxCollider2D

  • Enable AutoTiling

  • Enable IsTrigger

  • Create and add Ladder Layer

  • Cast a ray from player foot and check if it collides with the ladder

    public float climbSpeed;
    private bool isClimbing = false;
    public float ladderCheckDistance;
    public LayerMask whatIsLadder;
    public Transform feetPosition;
    void Update()
    {
    inputVerticalRaw = Input.GetAxisRaw("Vertical");

    if (Input.GetButtonDown("Jump"))
    {
    isClimbing = false;
    }

    }
    private void FixedUpdate()
    {
    ClimbLadder();
    }
    private void ClimbLadder(){
    RaycastHit2D checkForLadder = Physics2D.Raycast(feetPosition.position, Vector2.up, ladderCheckDistance, whatIsLadder);

    if(checkForLadder.collider != null){
    if(inputVerticalRaw != 0){
    isClimbing = true;
    }
    }else{
    isClimbing = false;
    }

    if(isClimbing && checkForLadder.collider != null){
    rb.gravityScale = 0;
    rb.velocity = new Vector2(rb.velocity.x, inputVerticalRaw * climbSpeed);
    }else{
    rb.gravityScale = 3;
    }
    }

Using OnTrigger Methods

  • Create a Sprite 16 x 4 pixels
  • Use 8 PixelPerUnit in Unity
  • Use MeshType FullRect
  • Drag into Scene
  • Change DrawMode Tiled
  • TileMode Adaptive
  • Drag vertically to elongate the ladder
  • Add BoxCollider2D
  • Enable AutoTiling
  • Enable IsTrigger
  • Add a script Ladder to trigger isOnLadder
Ladder.cs
private void OnTriggerEnter2D(Collider2D collider) {
if(collider.tag == "Player"){
collider.GetComponent<CharacterController2D>().isOnLadder = true;
collider.GetComponent<CharacterController2D>().chainPosition = transform;
}
}

private void OnTriggerExit2D(Collider2D collider) {
if(collider.tag == "Player"){
collider.GetComponent<CharacterController2D>().isOnLadder = false;
}
}
  • Use isOnLadder in PlayerController
PlayerController
public bool isOnLadder = false;
public float climbSpeed;
private bool isClimbing = false;
private float normalGravityScale;
public Transform chainPosition;

// check
public bool groundCheck;



void Start()
{
normalGravityScale = rb.gravityScale;
}
void Update()
{
inputVerticalRaw = Input.GetAxisRaw("Vertical");

if (Input.GetButtonDown("Jump"))
{
isClimbing = false;
}

// checks
groundCheck = Physics2D.OverlapCircle(feetPosition.position, checkRadius, whatIsGround);

if(groundCheck){
isClimbingChain = false;
}
}
private void FixedUpdate()
{
ClimbLadder();
}
private void ClimbLadder(){
if(isOnLadder){
if(inputVerticalRaw != 0){
isClimbingLadder = true;
}
}else{
isClimbingLadder = false;
}

if(isClimbingLadder){
// if Player is climbing auto center with ladder
transform.position = new Vector3(chainPosition.position.x, transform.position.y, transform.position.z);

rb.gravityScale = 0f;
rb.velocity = new Vector2(0, inputVerticalRaw * climbSpeed);
}else{
// reset gravity scale
rb.gravityScale = normalGravityScale;
}
}

Ladder Top

  • Create an empty game object
  • Add BoxCollider2D
  • Add PlatformEffector2D
  • Add LadderTop Script as component
LadderTop
// components
private PlatformEffector2D platformEffector2D;

// inputs
private float inputVertical;

void Start()
{
platformEffector2D = GetComponent<PlatformEffector2D>();
}

void Update()
{

inputVertical = Input.GetAxis("Vertical");

if (inputVertical < 0)
{
// when player wants to climb down the ladder
platformEffector2D.rotationalOffset = 180f;
}

if(Input.GetButtonDown("Jump") || inputVertical > 0){
// reset the platform whenever player wants to jump
// or if the player is climb up the ladder
// reset the top of ladder
platformEffector2D.rotationalOffset = 0f;
}
}

Dash

PlayerController
// dash

public float dashSpeed;
public float dashDuration;
private float dashDurationCounter;
public float dashCooldown;
private float dashCooldownCounter;
private bool isDashing = false;

// inputs
private bool inputDash = false;

void Update(){
// ! Input.GetButtonDown is not working properly
// ! Input.GetButton results in glitch where holding shift key moves player at high speed continuously
if (Input.GetButton("Dash"))
{
inputDash = true;
}else{
inputDash = false;
}
}

private void FixedUpdate()
{
// dash
AttemptDash();
Dash();
}

private void AttemptDash(){
// Debug.Log("rate " + dashCooldownCounter);

if(dashCooldownCounter > 0){
dashCooldownCounter -= Time.deltaTime;
// if(dashCooldownCounter == 0){
// dashCooldownCounter = 0;
// }
return;
}

if(inputDash){
// Debug.Log("Dash");
isDashing = true;
dashCooldownCounter = dashCooldown;
// dashDurationCounter = 0;
}

}

private void Dash(){
// Debug.Log("duration " + dashDurationCounter);
// Debug.Log("isDash " + isDashing);

if(!isDashing){
return;
}

if(dashDurationCounter >= dashDuration){
isDashing = false;
dashDurationCounter = 0;
return;
}

dashDurationCounter += Time.deltaTime;

// reset horizontal velocity before adding dash force
// rb.velocity = new Vector2(0, rb.velocity.y) * Time.deltaTime;
Vector2 dash = new Vector2(dashSpeed, 0) * Time.deltaTime;
rb.gravityScale = 0;
if(!facingRight){
dash = dash * (-1);
}
rb.velocity = dash;

}


Jump Pad


Moving Platform

  • Create Empty GameObject MovingPlatform
  • Create Platform GameObject as its child
  • Add sprite to Platform
  • Add Moving Platform Script to Platform
  • Add Nodes (Empty GameObjects) as children to MovingPlatform GameObject
  • Add icons to Nodes in the top left corner of Inspector for better view
  • Drag all Nodes into Platform script 'stops' array
  • Set RotationType
MovingPlatform
public float speed;

public float waitTime;

public enum RotationType
{
Loop,
ToAndFro
}
public RotationType rotationType;
public Transform[] stops;
private Transform nextStop;
private int currentStop = 0;
private bool toAndFroModeMovingForward = true;

private float waitTimeCounter;

void Start()
{
if(stops.Length != 0){
nextStop = stops[0];
}
}

void Update()
{
if(Vector2.Distance(transform.position, nextStop.position) > 0){
transform.position = Vector2.MoveTowards(transform.position, nextStop.position, speed * Time.deltaTime);
}else{
ChangeTarget();
}
}

private void ChangeTarget(){

if(waitTimeCounter < waitTime){
waitTimeCounter += Time.deltaTime;
return;
}

// reset waitTimeCounter
waitTimeCounter = 0;

// For Loop Rotation
// 0 1 2 3 0 1 2 3
if(rotationType == RotationType.Loop){
currentStop = (currentStop + 1) % stops.Length;
nextStop = stops[currentStop];
}

// For ToAndFro Rotation
// 0 1 2 3 3 2 1 0
if(rotationType == RotationType.ToAndFro){
if(currentStop == 0){
// move forward 0 1 2
toAndFroModeMovingForward = true;
}

if(currentStop == stops.Length - 1){
// move backward 2 1 0
toAndFroModeMovingForward = false;
}

if(toAndFroModeMovingForward){
currentStop ++;
}else{
currentStop --;
}

nextStop = stops[currentStop];
}
}

private void OnCollisionEnter2D(Collision2D collision) {
collision.collider.transform.parent = transform;
}

private void OnCollisionExit2D(Collision2D collision) {
collision.collider.transform.parent = null;
}

Self Destroying Platform

  • Create a SelfDestroyingPlatform Sprite
  • Add Script
SelfDestroyingPlatform
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SelfDestroyingPlatform : MonoBehaviour
{
public float destroyAfter;
private void OnCollisionEnter2D(Collision2D collision) {
if(collision.collider.tag == "Player"){
Destroy(gameObject, destroyAfter);
}
}
}

Trap - Death From Above

  • Create EmptyGameObject Trap-DeathFromAbove
  • Add Trap Sprite as child
    • Add Rigidbody2D, BoxCollider2D to Trap
      • Set Gravity Scale to 0
    • Add DeathFromAboveTrap Script to Trap
DeathFromAboveTrap
private void OnCollisionEnter2D(Collision2D collision) {
if (collision.collider.tag == "Player")
{
// Death Function
Destroy(collision.collider.gameObject);
}else{
// Destroy collision.collider
}
}
  • Add TriggerArea EmptyGameObject
    • Add BoxCollider2D and make it a Trigger
    • Add DeathFromAboveTrigger Script to Trigger
    • Drag Trap Object into TrapRigidBody field in Inspector
DeathFromAboveTrigger
public float fallSpeed;
public Rigidbody2D TrapRigidbody;

private void OnTriggerEnter2D(Collider2D collider)
{
TrapRigidbody.gravityScale = fallSpeed;
}
  • Make a prefab of Trap-DeathFromAbove object

Gate and Keys

  • Create EmptyGameObject GateAndKeys
  • Add Gate Sprite as child
    • Add Gate Script
    • Edit number of keys in the inspector
Gate
public int keysToUnlock;

private int keysRemaining;

private void OnCollisionEnter2D(Collision2D collision) {
if(collision.collider.tag == "Player"){
if(keysRemaining == 0){
Destroy(gameObject, 0.5f);
}
}
}

public void KeyCollected(){
keysRemaining--;
}

void Start()
{
keysRemaining = keysToUnlock;
}
  • Add Key Sprite as child
    • Add Key Script
    • Drag Gate Object into Gate field in Inspector
Key
public Gate gate;

private void OnTriggerEnter2D(Collider2D collider) {
if(collider.tag == "Player"){
gate.KeyCollected();
Destroy(gameObject);
}
}