- Home /
2D: Smooth Wall jump
My intention is to make my character wall jump/climb/slide, I got the sliding part working fine, but if he jumps while wall sliding, he should "bounce" back to the wall, the problem is that I can't balance the forces. In all tutorial I saw, it is simply a matter of detecting if the character is wall sliding, and if he is and he jumps, then you add a force oposite to the wall.
This is not working for me, because if I add enough force to make him jump, he goes way too fast and the player can barely see he jumped, he just sees that the character is now higher on the wall. If I add a smaller amount of force, it isn't enough to make a considerable jump and the player would have to hit space a thousand times to make him go up a few centimeters on the wall.
Any help is appreciated, I already tried a lot of things, even tried to freeze the controls, set gravity scale to 0 and make the character fo to the right points using MoveTowards, that is how desperate I am.
I'm also really new to Unity so I might be missing something really simple.
Here is a gif showing the character's behavior: https://imgur.com/a/TgUHzP6
And here are the relevant parts of my character's script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TheBot : MonoBehaviour {
public float speed;
public int jumpForce;
public Transform groundCheck;
public Transform meleeCheck;
public Transform bulletSpawner;
public LayerMask layerGround;
public float meleeCoolDown;
public float meleeDamage;
private Rigidbody2D body;
private Animator anim;
private Dash dashController;
private Shooter shotController;
private float unloadWaitingTime = 3;
private float idleGunTime = 0;
private bool facingRight = true;
private bool onGround = true;
private bool jumping = false;
private bool attacking = false;
private bool dead = false;
private bool isGunLoaded = false;
private bool isGunLoading = false;
private bool isGunUnloading = false;
private bool takingDamage = false;
private bool dashing = false;
private bool isWallSliding = false;
private bool wallJumping = false;
void Start () {
body = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
dashController = GetComponent<Dash>();
shotController = GetComponent<Shooter>();
}
void Update () {
PlayAnimations();
CheckIfGrounded();
checkIfWallSliding();
dashing = dashController.IsDashing();
if (Input.GetButtonDown("Jump") && onGround && !isGunLoading && !jumping && !takingDamage && !isWallSliding){
jumping = true;
}
if(Input.GetButtonDown("Jump") && !onGround && !isGunLoading && !takingDamage && !wallJumping && isWallSliding){
wallJumping = true;
}
if (Input.GetButtonDown("Melee") && !attacking && !isGunLoading){
Attack();
}
if(Input.GetButtonDown("Ranged") && !attacking && !isGunLoading && onGround){
Shoot();
}
if(Input.GetButtonDown("Dash") && !attacking && !isGunLoading && onGround){
dashController.DashTo(facingRight? Dash.RIGHT : Dash.LEFT);
}
if(isGunLoaded){
idleGunTime += Time.deltaTime;
if (idleGunTime >= unloadWaitingTime){
UnloadGun();
}
}
}
void FixedUpdate(){
if(!takingDamage){
float move = Input.GetAxis("Horizontal");
if (isWallSliding && !jumping){
body.velocity = new Vector2(body.velocity.x, -0.7f);
}
if(!dashing){
if(onGround){
body.velocity = new Vector2(move * speed, body.velocity.y);
} else {
//if character is not on ground, reduce the speed so he doesn't jump too far away
body.velocity = new Vector2(move * (speed * 0.7f), body.velocity.y);
}
}
if((move < 0 && facingRight) || (move > 0 && !facingRight) ){
Flip();
}
if (jumping){
body.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
if(Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.LeftArrow)){
body.velocity = new Vector2(body.velocity.x, body.velocity.y*0.8f);
}
onGround = false;
jumping = false;
}
if (wallJumping){
body.velocity = new Vector2(jumpPushForce * (facingRight ? -1:1), jumpForce);
wallJumping = false;
//body.AddForce(new Vector2(move * speed, jumpForce), ForceMode2D.Impulse);
}
}
}
void CheckIfGrounded(){
onGround = false;
Collider2D[] collisionResults = new Collider2D[2];
int objectsBeneath = Physics2D.OverlapBoxNonAlloc(groundCheck.position, new Vector2(0.9f, 0.3f), 0.0f, collisionResults, layerGround);
for (int i=0; i <objectsBeneath; i++ ){
if (!GameObject.ReferenceEquals(gameObject, collisionResults[i].gameObject)){
onGround = true;
}
}
}
void checkIfWallSliding(){
if (!onGround){
RaycastHit2D[] ray = new RaycastHit2D[1];
int totalRayHits = Physics2D.LinecastNonAlloc(bulletSpawner.position, body.position, ray, 1 << LayerMask.NameToLayer("SolidGround"));
bool wallFound = totalRayHits > 0 && ray[0].collider.gameObject.tag == "SolidGround";
isWallSliding = wallFound && ( (facingRight && Input.GetKey(KeyCode.RightArrow)) || (!facingRight && Input.GetKey(KeyCode.LeftArrow))) ;
if (isWallSliding) wallJumping = false;
} else {
isWallSliding = false;
}
}
void Flip(){
facingRight = !facingRight;
transform.localScale = new Vector3( -transform.localScale.x, transform.localScale.y, transform.localScale.z);
}
}
Answer by vlakitus · Oct 22, 2018 at 01:58 PM
Hey man!
did you solve that problem?
I'm in the same situation as you are.
Can you share de solution, if you did solve that problem?
Thanks so much.
I solved it, this guy on stack overflow helped me, the solution is in the link. Hope it helps you!
Thank you so much! I'm very new on unity, i'll try adjust my script with the post on stack overflow.
If it isn't asking too much, can you share your fixed script??
the important part of the corrected code is on the answer, my code has a lot of other stuff that could confuse you, but if you still want to see the whole fixed script, here it goes
Oh man! Thank you so much for your time! A big help from you!
Your answer
![](https://koobas.hobune.stream/wayback/20220612180109im_/https://answers.unity.com/themes/thub/images/avi.jpg)