okay i have a custom third person controller and when i was playing around with it in my game to see if it was working right i came across a problem wall jump works fine but if i stand in one place ( like the middle of the stage) and start jumping ( mashing jump button) then start moving toward a wall he goes straight up it im trying to make him jump hit a wall turn around jump off other wall (it works fine) just the standing in one spot and mashing jump makes him able to climb walls with out haveing to to wall jump off another wall? my game is 3D or 2.5 d i dont know the dif? HERE'S THE SCRIPT Code (CSharp): using UnityEngine; using System.Collections; public class ThirdPersonController : MonoBehaviour { public AnimationClip idleAnimation; public AnimationClip fallAnimanton; public AnimationClip walkAnimation; public AnimationClip runAnimation; public AnimationClip jumpPoseAnimation; public AnimationClip edgeAnimation; public AnimationClip slamAnimation; public float walkMaxAnimationSpeed = 0.50f; public float trotMaxAnimationSpeed = 0.70f; public float runMaxAnimationSpeed = 1.0f; public float jumpAnimationSpeed = 1.15f; public float fallAnimationSpeed = 1.0f; public float edgeAnimationSpeed = 1.0f; public float slamAnimationSpeed = 1.0f; public float magnitude; public float vel = 1; private Animation _animation; public enum CharacterState { Idle = 0, Walking = 1, Trotting = 2, Running = 3, Jumping = 4, edge = 5, slam = 1, } public CharacterState _characterState; // The speed when walking float walkSpeed= 1.0f; // after trotAfterSeconds of walking we trot with trotSpeed float trotSpeed= 2.0f; // when pressing "Fire3" button (cmd) we start running float runSpeed= 3.0f; float inAirControlAcceleration= 3.0f; // How high do we jump when pressing jump and letting go immediately public float jumpHeight= 0.5f; // We add extraJumpHeight meters on top when holding the button down longer while jumping public float extraJumpHeight = 2.5f; // The gravity for the character float gravity= 20.0f; float controlledDescentGravity = 10.0f; // The gravity in controlled descent mode float speedSmoothing= 10.0f; float rotateSpeed= 500.0f; float trotAfterSeconds= 3.0f; bool canJump= true; bool canControlDescent = true; bool canWallJump = true; private float jumpRepeatTime= 0.05f; private float jumpTimeout= 0.15f; private float groundedTimeout= 0.25f; private float wallJumpTimeout = 0.15f; // The camera doesnt start following the target immediately but waits for a split second to avoid too much waving around. private float lockCameraTimer= 0.0f; // The current move direction in x-z private Vector3 moveDirection= Vector3.zero; // The current vertical speed private float verticalSpeed= 0.0f; // The current x-z move speed private float moveSpeed= 0.0f; // The last collision flags returned from controller.Move private CollisionFlags collisionFlags; // Are we jumping? (Initiated with jump button and not grounded yet) public static bool jumping= false; private bool jumpingReachedApex= false; // Are we moving backwards (This locks the camera to not do a 180 degree spin) private bool movingBack= false; // Is the user pressing any keys? private bool isMoving= false; // When did the user start walking (Used for going into trot after a while) private float walkTimeStart= 0.0f; // Last time the jump button was clicked down private float lastJumpButtonTime= -10.0f; // Last time we performed a jump private float lastJumpTime= -1.0f; // the height we jumped from (Used to determine for how long to apply extra jump power after jumping.) private float lastJumpStartHeight= 0.0f; public static Vector3 inAirVelocity= Vector3.zero; private float lastGroundedTime= 0.0f; private bool isControllable= true; // Average normal of the last touched geometry Vector3 wallJumpContactNormal; private float wallJumpContactNormalHeight; // When did we touch the wall the first time during this jump (Used for wall jumping) private float touchWallJumpTime = -1.0f; //Are we on a ledge public static Transform ledgeTransform; public static bool onLedge = false; private float lean = 0.0f; private bool slammed = false; void Awake (){ moveDirection = transform.TransformDirection(Vector3.forward); _animation = GetComponent<Animation>(); if(!_animation) Debug.Log("The character you would like to control doesn't have animations. Moving her might look weird."); if(!idleAnimation) { _animation = null; Debug.Log("No idle animation found. Turning off animations."); } if(!walkAnimation) { _animation = null; Debug.Log("No walk animation found. Turning off animations."); } if(!runAnimation) { _animation = null; Debug.Log("No run animation found. Turning off animations."); } if(!jumpPoseAnimation && canJump) { _animation = null; Debug.Log("No jump animation found and the character has canJump enabled. Turning off animations."); } } void OnTriggerEnter(Collider other) { } void UpdateSmoothedMovementDirection () { Transform cameraTransform= Camera.main.transform; bool grounded= IsGrounded(); // Forward vector relative to the camera along the x-z plane Vector3 forward= cameraTransform.TransformDirection(Vector3.forward); forward.y = 0; forward = forward.normalized; // Right vector relative to the camera // Always orthogonal to the forward vector Vector3 right = new Vector3(forward.z, 0, -forward.x); float v = Input.GetAxisRaw("Vertical"); float h = Input.GetAxisRaw("Horizontal"); // Are we moving backwards or looking backwards if (v < -0.2f) movingBack = true; else movingBack = false; bool wasMoving= isMoving; isMoving = Mathf.Abs (h) > 0.1f || Mathf.Abs (v) > 0.1f; // Target direction relative to the camera Vector3 targetDirection= h * right + v * forward; // Smooth the speed based on the current target direction float curSmooth= speedSmoothing * Time.deltaTime; // Choose target speed //* We want to support analog input but make sure you cant walk faster diagonally than just forward or sideways float targetSpeed= Mathf.Min(targetDirection.magnitude, 1.0f); if (onLedge && ledgeTransform) { _characterState = CharacterState.edge; // Lock camera for short period when transitioning moving & standing still lockCameraTimer += Time.deltaTime; if (isMoving != wasMoving) lockCameraTimer = 0.0f; // We store speed and direction seperately, // so that when the character stands still we still have a valid forward direction // moveDirection is always normalized, and we only update it if there is user input. //If the camera is behind/beside, right is right. Otherwise, right is left. if(Vector3.Dot(Camera.main.transform.forward, transform.forward) < 0) moveDirection = h * ledgeTransform.right; else moveDirection = h * -ledgeTransform.right; // Pick speed modifier if (Input.GetButton ("Fire3")) { targetSpeed *= runSpeed; } else if (Time.time - trotAfterSeconds > walkTimeStart) { targetSpeed *= trotSpeed; } else { targetSpeed *= walkSpeed; } moveSpeed = Mathf.Lerp(moveSpeed, targetSpeed, curSmooth); // Reset walk time start when we slow down if (moveSpeed < walkSpeed * 0.3) walkTimeStart = Time.time; } // Grounded controls else if (grounded) { // Lock camera for short period when transitioning moving & standing still lockCameraTimer += Time.deltaTime; if (isMoving != wasMoving) lockCameraTimer = 0.0f; // We store speed and direction seperately, // so that when the character stands still we still have a valid forward direction // moveDirection is always normalized, and we only update it if there is user input. if (targetDirection != Vector3.zero) { // If we are really slow, just snap to the target direction if (moveSpeed < walkSpeed * 0.9f && grounded) { moveDirection = targetDirection.normalized; } // Otherwise smoothly turn towards it else { moveDirection = Vector3.RotateTowards(moveDirection, targetDirection, rotateSpeed * Mathf.Deg2Rad * Time.deltaTime, 1000); moveDirection = moveDirection.normalized; } } _characterState = CharacterState.Idle; // Pick speed modifier if (Input.GetKey (KeyCode.LeftShift) || Input.GetKey (KeyCode.RightShift)) { targetSpeed *= runSpeed; _characterState = CharacterState.Running; if(magnitude > 0.1f) vel = 2; } else if (Time.time - trotAfterSeconds > walkTimeStart) { targetSpeed *= trotSpeed; _characterState = CharacterState.Trotting; vel = 1.4f; } else { targetSpeed *= walkSpeed; _characterState = CharacterState.Walking; vel = 1; } moveSpeed = Mathf.Lerp(moveSpeed, targetSpeed, curSmooth); // Reset walk time start when we slow down if (moveSpeed < walkSpeed * 0.3f) walkTimeStart = Time.time; } // In air controls else { // Lock camera while in air if (jumping) lockCameraTimer = 0.0f; if (isMoving) inAirVelocity += targetDirection.normalized * Time.deltaTime * inAirControlAcceleration; } } void ApplyWallJump () { // We must actually jump against a wall for this to work if (!jumping) return; // Store when we first touched a wall during this jump if (collisionFlags == CollisionFlags.CollidedSides) { touchWallJumpTime = Time.time; } // The user can trigger a wall jump by hitting the button shortly before or shortly after hitting the wall the first time. var mayJump = lastJumpButtonTime > touchWallJumpTime - wallJumpTimeout && lastJumpButtonTime < touchWallJumpTime + wallJumpTimeout; if (!mayJump) return; // Prevent jumping too fast after each other if (lastJumpTime + jumpRepeatTime > Time.time) return; if (Mathf.Abs(wallJumpContactNormal.y) < 0.2) { wallJumpContactNormal.y = 0; moveDirection = wallJumpContactNormal.normalized; // Wall jump gives us at least trotspeed moveSpeed = Mathf.Clamp(moveSpeed * 1.5f, trotSpeed, runSpeed); } else { moveSpeed = 0; } verticalSpeed = CalculateJumpVerticalSpeed (jumpHeight); DidJump(); SendMessage("DidWallJump", null, SendMessageOptions.DontRequireReceiver); } void ApplyJumping (){ // Prevent jumping too fast after each other if (lastJumpTime + jumpRepeatTime > Time.time) return; if (IsGrounded()) { // Jump // - Only when pressing the button down // - With a timeout so you can press the button slightly before landing if (canJump && Time.time < lastJumpButtonTime + jumpTimeout) { verticalSpeed = CalculateJumpVerticalSpeed (jumpHeight); SendMessage("DidJump", SendMessageOptions.DontRequireReceiver); } } } void ApplyGravity (){ if (isControllable) // don't move player at all if not controllable. { // Apply gravity bool jumpButton= Input.GetButton("Jump"); // * When falling down we use controlledDescentGravity (only when holding down jump) bool controlledDescent = canControlDescent && verticalSpeed <= 0.0f && jumpButton && jumping; // When we reach the apex of the jump we send out a message if (jumping && !jumpingReachedApex && verticalSpeed <= 0.0f) { jumpingReachedApex = true; SendMessage("DidJumpReachApex", SendMessageOptions.DontRequireReceiver); } // * When jumping up we don't apply gravity for some time when the user is holding the jump button // This gives more control over jump height by pressing the button longer bool extraPowerJump = IsJumping () && verticalSpeed > 0.0f && jumpButton && transform.position.y < lastJumpStartHeight + extraJumpHeight; //Let go of the ledge if (onLedge && jumpButton) { onLedge = false; moveDirection = transform.forward; movingBack = true; } if (controlledDescent) verticalSpeed -= controlledDescentGravity * Time.deltaTime; else if (extraPowerJump) return; else if (IsGrounded ()|| onLedge) verticalSpeed = 0.0f; else verticalSpeed -= gravity * Time.deltaTime; } } float CalculateJumpVerticalSpeed ( float targetJumpHeight ){ // From the jump height and gravity we deduce the upwards speed // for the character to reach at the apex. return Mathf.Sqrt(2 * targetJumpHeight * gravity); } void DidJump (){ jumping = true; jumpingReachedApex = false; lastJumpTime = Time.time; lastJumpStartHeight = transform.position.y; touchWallJumpTime = -1; lastJumpButtonTime = -10; _characterState = CharacterState.Jumping; } void Update (){ if (!isControllable) { // kill all inputs if not controllable. Input.ResetInputAxes(); } if (Input.GetButtonDown ("Jump")) { lastJumpButtonTime = Time.time; } UpdateSmoothedMovementDirection(); // Apply gravity // - extra power jump modifies gravity // - controlledDescent mode modifies gravity ApplyGravity (); // Perform a wall jump logic // - Make sure we are jumping against wall etc. // - Then apply jump in the right direction) if (canWallJump) ApplyWallJump(); // Apply jumping logic ApplyJumping (); // Calculate actual motion Vector3 movement = moveDirection * moveSpeed + new Vector3 (0, verticalSpeed, 0) + inAirVelocity; movement *= Time.deltaTime;//moveDirection * moveSpeed + Vector3 (0, verticalSpeed, 0) + inAirVelocity magnitude = movement.magnitude; // Move the controller CharacterController controller = GetComponent<CharacterController>(); wallJumpContactNormal = Vector3.zero; collisionFlags = controller.Move(movement); // ANIMATION sector if(_animation) { if(_characterState == CharacterState.edge) { _animation[edgeAnimation.name].speed = edgeAnimationSpeed; _animation[edgeAnimation.name].wrapMode = WrapMode.ClampForever; _animation.CrossFade(edgeAnimation.name); } if(_characterState == CharacterState.Jumping) { if(!jumpingReachedApex) { _animation[jumpPoseAnimation.name].speed = jumpAnimationSpeed; _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever; _animation.CrossFade(jumpPoseAnimation.name); } else { _animation[fallAnimanton.name].speed = -fallAnimationSpeed; _animation[fallAnimanton.name].wrapMode = WrapMode.ClampForever; _animation.CrossFade(fallAnimanton.name); } } else { if(controller.velocity.sqrMagnitude < 0.1f) { _animation.CrossFade(idleAnimation.name); } else { if(_characterState == CharacterState.Running) { _animation[runAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0f, runMaxAnimationSpeed); _animation.CrossFade(runAnimation.name); } else if(_characterState == CharacterState.Trotting) { _animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0f, trotMaxAnimationSpeed); _animation.CrossFade(walkAnimation.name); } else if(_characterState == CharacterState.Walking) { _animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0f, walkMaxAnimationSpeed); _animation.CrossFade(walkAnimation.name); } } } } // ANIMATION sector if(onLedge && ledgeTransform) { transform.rotation = Quaternion.LookRotation(-ledgeTransform.forward); } // Set rotation to the move direction else if (IsGrounded()) { if(slammed) // we got knocked over by an enemy. We need to reset some stuff { slammed = false; controller.height = 2; Vector3 temp = transform.position; // copy to an auxiliary variable... temp.y = 0.75f; // modify the component you want in the variable... } transform.rotation = Quaternion.LookRotation(moveDirection); } else { if(!slammed) { Vector3 xzMove= movement; xzMove.y = 0; if (xzMove.sqrMagnitude > 0.001f) { transform.rotation = Quaternion.LookRotation(xzMove); } } } // We are in jump mode but just became grounded if (IsGrounded()) { lastGroundedTime = Time.time; inAirVelocity = Vector3.zero; if (jumping) { jumping = false; SendMessage("DidLand", SendMessageOptions.DontRequireReceiver); } } } void OnControllerColliderHit ( ControllerColliderHit hit ){ // Debug.DrawRay(hit.point, hit.normal); if (hit.moveDirection.y > 0.01f) return; wallJumpContactNormal = hit.normal; } float GetSpeed (){ return moveSpeed; } public bool IsJumping (){ return jumping; } bool IsGrounded (){ return (collisionFlags & CollisionFlags.CollidedBelow) != 0; } void SuperJump (float height) { verticalSpeed = CalculateJumpVerticalSpeed (height); collisionFlags = CollisionFlags.None; SendMessage("DidJump", SendMessageOptions.DontRequireReceiver); } void SuperJump (float height, Vector3 jumpVelocity) { verticalSpeed = CalculateJumpVerticalSpeed (height); inAirVelocity = jumpVelocity; collisionFlags = CollisionFlags.None; SendMessage("DidJump", SendMessageOptions.DontRequireReceiver); } void Slam (Vector3 direction) { verticalSpeed = CalculateJumpVerticalSpeed (1); inAirVelocity = direction * 6; direction.y = 0.6f; Quaternion.LookRotation(-direction); CharacterController controller = GetComponent<CharacterController>(); controller.height = 0.5f; slammed = true; collisionFlags = CollisionFlags.None; SendMessage("DidJump", SendMessageOptions.DontRequireReceiver); } public void GrabLedge(Transform ledge) { ledgeTransform = ledge; onLedge = true; jumping = false; inAirVelocity = Vector3.zero; } Vector3 GetDirection (){ return moveDirection; } public bool IsMovingBackwards (){ return movingBack; } public float GetLockCameraTimer () { return lockCameraTimer; } bool IsMoving () { return Mathf.Abs(Input.GetAxisRaw("Vertical")) + Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0.5f; } bool HasJumpReachedApex () { return jumpingReachedApex; } bool IsGroundedWithTimeout () { return lastGroundedTime + groundedTimeout > Time.time; } bool IsControlledDescent () { // * When falling down we use controlledDescentGravity (only when holding down jump) bool jumpButton = Input.GetButton("Jump"); return canControlDescent && verticalSpeed <= 0.0 && jumpButton && jumping; } void Reset () { gameObject.tag = "Player"; } }