- Home /
2D Platformer Wall Jump(Away From Wall)
I'm making just a very basic 2D Platformer kind of like Super Meat Boy. I got the wall Jump working but I want it to push the character/square away from the wall when you jump instead of just straight up. Im reasonably new to Unity and C# and I would really appreciate if someone could help me.
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(PlayerPhysics))]
public class PlayerController : MonoBehaviour {
// Player Handling
public float gravity = 20;
public float Speed = 15;
public float acceleration = 30;
public float jumpHeight = 12;
// System
private float currentSpeed;
private float targetSpeed;
private Vector2 amountToMove;
private float moveDirX;
// States
private bool jumping;
private bool wallHolding;
// Components
private PlayerPhysics playerPhysics;
void Start () {
playerPhysics = GetComponent<PlayerPhysics>();
}
void Update () {
// Reset acceleration upon collision
if (playerPhysics.movementStopped) {
targetSpeed = 0;
currentSpeed = 0;
}
// If player is touching the ground
if (playerPhysics.grounded) {
amountToMove.y = 0;
if (wallHolding) {
wallHolding = false;
}
// Jump logic
if (jumping) {
jumping = false;
}
}
else {
if (!wallHolding) {
if (playerPhysics.canWallHold) {
wallHolding = true;
}
}}
// Jump Input
if (Input.GetButtonDown ("Jump")) {
if (playerPhysics.grounded || wallHolding) {
amountToMove.y = jumpHeight;
jumping = true;
}
if (wallHolding) {
wallHolding = false;
}
}
// Input
moveDirX = Input.GetAxisRaw("Horizontal");
targetSpeed = moveDirX * Speed;
currentSpeed = IncrementTowards(currentSpeed, targetSpeed,acceleration);
// Set amount to move
amountToMove.x = currentSpeed;
if (wallHolding) {
amountToMove.x = 0;
if (Input.GetAxisRaw("Vertical") != -1) {
amountToMove.y = 0;
}
}
amountToMove.y -= gravity * Time.deltaTime;
playerPhysics.Move(amountToMove * Time.deltaTime, moveDirX);
}
// Increase n towards target by speed
private float IncrementTowards(float n, float target, float a) {
if (n == target) {
return n;
}
else {
float dir = Mathf.Sign(target - n); // must n be increased or decreased to get closer to target
n += a * Time.deltaTime * dir;
return (dir == Mathf.Sign(target-n))? n: target; // if n has now passed target then return target, otherwise return n
}
}
}
And the Player Physics code,
[RequireComponent (typeof(BoxCollider))]
public class PlayerPhysics : MonoBehaviour {
public LayerMask collisionMask;
private BoxCollider collider;
private Vector3 s;
private Vector3 c;
private Vector3 originalSize;
private Vector3 originalCenter;
private float colliderScale;
private int collisionDivisionsX = 3;
private int collisionDivisionsY =10;
private float skin = .005f;
[HideInInspector]
public bool grounded;
[HideInInspector]
public bool movementStopped;
[HideInInspector]
public bool canWallHold;
Ray ray;
RaycastHit hit;
void Start() {
collider = GetComponent<BoxCollider>();
colliderScale = transform.localScale.x;
originalSize = collider.size;
originalCenter = collider.center;
SetCollider(originalSize,originalCenter);
}
public void Move(Vector2 moveAmount, float moveDirX) {
float deltaY = moveAmount.y;
float deltaX = moveAmount.x;
Vector2 p = transform.position;
// Check collisions above and below
grounded = false;
for (int i = 0; i<collisionDivisionsX; i ++) {
float dir = Mathf.Sign(deltaY);
float x = (p.x + c.x - s.x/2) + s.x/(collisionDivisionsX-1) * i; // Left, Center and then rightmost point of collider
float y = p.y + c.y + s.y/2 * dir; // Bottom of collider
ray = new Ray(new Vector2(x,y), new Vector2(0,dir));
Debug.DrawRay(ray.origin,ray.direction);
if (Physics.Raycast(ray,out hit,Mathf.Abs(deltaY) + skin,collisionMask)) {
// Get Distance between player and ground
float dst = Vector3.Distance (ray.origin, hit.point);
// Stop player's downwards movement after coming within skin width of a collider
if (dst > skin) {
deltaY = dst * dir - skin * dir;
}
else {
deltaY = 0;
}
grounded = true;
break;
}
}
// Check collisions left and right
movementStopped = false;
canWallHold = false;
if (deltaX != 0) {
for (int i = 0; i<collisionDivisionsY; i ++) {
float dir = Mathf.Sign(deltaX);
float x = p.x + c.x + s.x/2 * dir;
float y = p.y + c.y - s.y/2 + s.y/(collisionDivisionsY-1) * i;
ray = new Ray(new Vector2(x,y), new Vector2(dir,0));
//Debug.DrawRay(ray.origin,ray.direction);
if (Physics.Raycast(ray,out hit,Mathf.Abs(deltaX) + skin,collisionMask)) {
if (hit.collider.tag == "Wall Jump") {
if (Mathf.Sign(deltaX) == Mathf.Sign(moveDirX) && moveDirX != 0) {
canWallHold = true;
}
}
// Get Distance between player and ground
float dst = Vector3.Distance (ray.origin, hit.point);
// Stop player's downwards movement after coming within skin width of a collider
if (dst > skin) {
deltaX = dst * dir - skin * dir;
}
else {
deltaX = 0;
}
movementStopped = true;
break;
}
}
}
if (!grounded && !movementStopped) {
Vector3 playerDir = new Vector3(deltaX,deltaY);
Vector3 o = new Vector3(p.x + c.x + s.x/2 * Mathf.Sign(deltaX),p.y + c.y + s.y/2 * Mathf.Sign(deltaY));
ray = new Ray(o,playerDir.normalized);
if (Physics.Raycast(ray,Mathf.Sqrt(deltaX * deltaX + deltaY * deltaY),collisionMask)) {
grounded = true;
deltaY = 0;
}
}
Vector2 finalTransform = new Vector2(deltaX,deltaY);
transform.Translate(finalTransform,Space.World);
}
// Set collider
public void SetCollider(Vector3 size, Vector3 center) {
collider.size = size;
collider.center = center;
s = size * colliderScale;
c = center * colliderScale;
}
public void ResetCollider() {
SetCollider(originalSize,originalCenter);
}
}
Once again I would really appreciate the help, Thanks.
Can anyone help me?
Answer by HYPERSAVV · Jan 05, 2015 at 11:17 AM
Within your controller: If the player is up against a wall and they request to jump then you want to apply a force inverse to the directed x-axis and up. Since you are handling all of this yourself with Translate (instead of a rigidbody), you'll need to (most likely) keep track that you are in this "special" type of jump to calculate the velocity curve over time. Say your wall is on the right, and we jump, we want a negative velocity along the x-axis (inverse exponential) followed by a positive velocity along the x-axis (exponential) until we collide with the wall. Of course, calculate along the y-axis like you normally would.
Also, the velocity approaching zero would only apply so long as the input continues to back towards the wall. I'll let you figure out the exact syntax, but essentially we need to know A) are we in a wall jump state and B) where is the origin of the wall. Use the origin of the wall to determine, while in flight, if we should be increasing or decreasing speed base on input along x-axis.
So if I add a wall jump state that the player enters after jumping from the wallHolding state, I then need to apply a force on the x-axis away from the origin of the wall.
The only problem is I don't know how to apply the force on the x-axis away from the wall or how to get the origin of the wall.
So there's two ways of doing this. One way you could go about doing this is using the Physics2D.OverlapCircle (or OverlapArea) on each side of your character to see if you are colliding with a wall. If it collides on the left side, then its on the left side, and vice versa.
Another way of going about this is by checking the normal of the collision using the contacts member of the Collider object. This will tell you from which direction the collision occurred, which will tell you what side you hit a wall. So if you know the origin of the wall (-1, 1) then you can apply the desired force along the x-axis.
Your answer
![](https://koobas.hobune.stream/wayback/20220613175612im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
2D platformer- getting errors I don't understand (c#) 1 Answer
Simple collision detection C# 2D 1 Answer
Load Scene Moving Too Fast(C#) 1 Answer
2D Flashlight for a platformer 2 Answers