title: Unity2D: Can't balance wall jump forces
body: <p>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.</p>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <p>I'm also really new to Unity so I might be missing something really simple.</p>
  
  <p>Here is a gif showing the character's behavior:
  <a href="https://imgur.com/a/TgUHzP6" rel="nofollow noreferrer">https://imgur.com/a/TgUHzP6</a></p>
  
  <p>And here is the relevant parts of my character's script:</p>
  
  <pre><code>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 float wallJumpTime = 0f;
      private Vector3[] wallJumpControlPoint;
  
      // Use this for initialization
      void Start () {
          body = GetComponent&lt;Rigidbody2D&gt;();
          anim = GetComponent&lt;Animator&gt;();
          dashController = GetComponent&lt;Dash&gt;();
          shotController = GetComponent&lt;Shooter&gt;();
      }
  
      // Update is called once per frame
      void Update () {
          PlayAnimations();
          CheckIfGrounded();
          checkIfWallSliding();
          dashing = dashController.IsDashing();
  
          if (Input.GetButtonDown("Jump") &amp;&amp; (onGround || isWallSliding)  &amp;&amp; !isGunLoading &amp;&amp; !jumping &amp;&amp; !takingDamage){
              jumping = true;
              wallJumpControlPoint = new Vector3[3];
              wallJumpControlPoint[0] = body.position;
              wallJumpControlPoint[1] = new Vector3(body.position.x +4, body.position.y + 2);
              wallJumpControlPoint[2] = new Vector3(body.position.x, body.position.y + 4);
          }
          if (Input.GetButtonDown("Melee") &amp;&amp; !attacking &amp;&amp; !isGunLoading){
              Attack();
          }
          if(Input.GetButtonDown("Ranged") &amp;&amp; !attacking  &amp;&amp; !isGunLoading &amp;&amp; onGround){
              Shoot();
          }
  
          if(Input.GetButtonDown("Dash") &amp;&amp; !attacking &amp;&amp; !isGunLoading &amp;&amp; onGround){
              dashController.DashTo(facingRight? Dash.RIGHT : Dash.LEFT);
          }
  
  
          if(isGunLoaded){
              idleGunTime += Time.deltaTime;
              if (idleGunTime &gt;= unloadWaitingTime){
                  UnloadGun();
              }
          }
  
      }
  
      void FixedUpdate(){
          if(!takingDamage){
  
              float move = Input.GetAxis("Horizontal");
  
              //while charachter is wall sliding, slowly fall
              if (isWallSliding){
                  body.velocity = new Vector2(body.velocity.x, -0.7f);
              }
  
              if(!dashing){
                  if(onGround){
                      //if not dashing on on ground, walk with normal speed
                      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 &lt; 0 &amp;&amp; facingRight) || (move &gt; 0 &amp;&amp; !facingRight) ){
                  //control direction character is facing
                  Flip();
              }
  
              if (jumping){
  
                  if(isWallSliding){
                      body.velocity = new Vector2(30, 20);
                  } else {
                      body.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
                  }
  
                  if(Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.LeftArrow)){
                      //if is moving while jumping, reduce jump height
                      body.velocity = new Vector2(body.velocity.x, body.velocity.y*0.8f);
                  }
                  onGround = false;
                  jumping = false;
              }       
          }
      }
  
      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 &lt;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 &lt;&lt; LayerMask.NameToLayer("SolidGround"));
              bool wallFound = totalRayHits &gt; 0 &amp;&amp; ray[0].collider.gameObject.tag == "SolidGround";
  
              isWallSliding = wallFound &amp;&amp; ( (facingRight &amp;&amp; Input.GetKey(KeyCode.RightArrow)) ||  (!facingRight &amp;&amp; Input.GetKey(KeyCode.LeftArrow))) ;
          } else {
              isWallSliding = false;
              if (body.velocity.y &gt; 10){
                  body.velocity = new Vector2(body.velocity.x, 5);
              }
          }
      }
  
  
      public void Die(){
          dead = true;
      }
  
  }
  </code></pre>