How to fix my wallrun
Im trying to make a wallrun in unity like the wallrun of the Prince of Persia.
The idea is that when you are touching the wall and you press "left shift" the player would run some seconds without falling. I would like to add that if you press "enter" the character would jump to the side using the Wall as support for impulse.
You can watch this in the first minutes of the video: https://www.youtube.com/watch?v=zsnB7HEiLr0
I have made this script for the character controller:
public Transform playerPosition;
//controls the x movement. (right/left)
public float horizontalmove;
//controls the y movement. (forward/back)
public float verticalmove;
//controls the movement direction.
private Vector3 playerInput;
//Here I store my character controller.
public CharacterController player;
//controls the player speed.
public float playerSpeed;
//controls de movement direction according to camera
public Vector3 movePlayer;
//controls the last movement
public Vector3 lastMovePlayer;
public float gravity = 9.8f;
public float fallVelocity;
public float jumpForce = 5.0f;
public float verticalSpeed;
private RaycastHit HitR;
private RaycastHit HitL;
//Here I store the main camera
public Camera mainCamera;
//It stores the camera direction when the player is looking forward.
private Vector3 camForward;
//It stores the camera direction when the player is looking right.
private Vector3 camRight;
//Checks
//The meaning of Caida is fall.
public bool Caida;
//The meaning of salto is jump.
public bool Salto;
public bool Wallrun;
public bool WallrunCount;
// Start is called befoe the first frame update
void Start()
{
//i store the character controler.
player = GetComponent<CharacterController>();
Caida = true;
}
// Update is called once per frame
void Update()
{
if (Wallrun == true)
{
Caida = false;
}
if (Salto == true)
{
fallVelocity -= gravity * Time.deltaTime;
movePlayer = lastMovePlayer;
}
if (Caida == true)
{
fallVelocity -= gravity * Time.deltaTime;
}
if (player.isGrounded && Wallrun == false)
{
Caida = false;
Salto = false;
WallrunCount = false;
//I assign the horizontal move to the w and s keys.
horizontalmove = Input.GetAxis("Horizontal");
//I assign the vertical move to the a and d keys.)
verticalmove = Input.GetAxis("Vertical");
//controls the movement direction
playerInput = new Vector3(horizontalmove, 0, verticalmove);
//limits the player speed. With this method if teh player waalks in diagonal doesn´t
//exceed the speed limit.
playerInput = Vector3.ClampMagnitude(playerInput, 1);
// It calls the function that give the camera look direction.
camDirection();
//Here, It`s calculates the player movement considering the camera point and the movement
//we have assing to teh player earlier
//With this method the player always moves looking to the camera
movePlayer = playerInput.x * camRight + playerInput.z * camForward;
//The movement * the speed we want.
movePlayer = movePlayer * playerSpeed;
//we are going to say to the player where is looking at.
player.transform.LookAt(player.transform.position + movePlayer);
//It gives the gravity to the player.
fallVelocity = -gravity * Time.deltaTime;
if (Input.GetKeyDown(KeyCode.Space))
{
Salto = true;
fallVelocity = jumpForce;
}
}
else if (!player.isGrounded && Salto == false && Wallrun == false)
{
Caida = true;
}
movePlayer.y = fallVelocity;
//we give the movement to th eplayer.
player.Move(movePlayer * Time.deltaTime);
lastMovePlayer = movePlayer;
}
private void OnTriggerStay(Collider other)
{
if (Input.GetKeyDown(KeyCode.LeftShift) && Wallrun == false && WallrunCount == false)
{
if (Input.GetKey("w"))
{
Wallrun = true;
WallrunCount = true;
fallVelocity = 5f;
movePlayer.y = fallVelocity;
movePlayer.z = movePlayer.z * 1.6f;
if (Physics.Raycast(transform.position, transform.right, out HitR, 1))
{
movePlayer.x = 1.6f;
}
else if (Physics.Raycast(transform.position, -transform.right, out HitL, 1))
{
movePlayer.x = -1.6f;
}
StartCoroutine(wallrunTime());
}
}
}
void camDirection()
{
//we store the forward and right directions here.
camForward = mainCamera.transform.forward;
camRight = mainCamera.transform.right;
//we block the direction and the camera direction because we are not going to use it.
camForward.y = 0;
camRight.y = 0;
//It gives as the normalized vectors.
camForward = camForward.normalized;
camRight = camRight.normalized;
}
private void OnControllerColliderHit(ControllerColliderHit hit)
{
if (!player.isGrounded && hit.normal.y < 0.1f)
{
if (Input.GetKeyDown(KeyCode.Space))
{
fallVelocity = jumpForce;
movePlayer = hit.normal * 7;
player.transform.LookAt(player.transform.position + movePlayer);
}
}
}
IEnumerator wallrunTime()
{
yield return new WaitForSeconds(1);
Wallrun = false;
}
As you can see, when the player enters the leftshift it checks to what direction is moving the character, if this is front (w) the script make the z movement * 1.6 (to make the character run a bit in the wall) and the character go a bit up bit the y axis.Then, the script checks if the Wall it i son the right or on the left and, depending on where the wall is, sticks the character to that wall.
private void OnTriggerStay(Collider other)
{
if (Input.GetKeyDown(KeyCode.LeftShift) && Wallrun == false && WallrunCount == false)
{
if (Input.GetKey("w"))
{
Wallrun = true;
WallrunCount = true;
fallVelocity = 5f;
movePlayer.y = fallVelocity;
movePlayer.z = movePlayer.z * 1.6f;
if (Physics.Raycast(transform.position, transform.right, out HitR, 1))
{
movePlayer.x = 1.6f;
}
else if (Physics.Raycast(transform.position, -transform.right, out HitL, 1))
{
movePlayer.x = -1.6f;
}
StartCoroutine(wallrunTime());
}
}
}
Im trying to make a wallrun in unity like the wallrun of the Prince of Persia. The idea is that when you are touching the wall and you press "left shift" the player would run some seconds without falling. I would like to add that if you press "enter" the character would jump to the side using the Wall as support for impulse. You can watch this in the first minutes of the video: https://www.youtube.com/watch?v=zsnB7HEiLr0 I have made this script for the character controller: public Transform playerPosition; //controls the x movement. (right/left) public float horizontalmove; //controls the y movement. (forward/back) public float verticalmove; //controls the movement direction. private Vector3 playerInput; //Here I store my character controller. public CharacterController player; //controls the player speed. public float playerSpeed; //controls de movement direction according to camera public Vector3 movePlayer; //controls the last movement public Vector3 lastMovePlayer; public float gravity = 9.8f; public float fallVelocity; public float jumpForce = 5.0f; public float verticalSpeed; private RaycastHit HitR; private RaycastHit HitL; //Here I store the main camera public Camera mainCamera; //It stores the camera direction when the player is looking forward. private Vector3 camForward; //It stores the camera direction when the player is looking right. private Vector3 camRight; //Checks //The meaning of Caida is fall. public bool Caida; //The meaning of salto is jump. public bool Salto; public bool Wallrun; public bool WallrunCount; // Start is called befoe the first frame update void Start() { //i store the character controler. player = GetComponent<CharacterController>(); Caida = true; } // Update is called once per frame void Update() { if (Wallrun == true) { Caida = false; } if (Salto == true) { fallVelocity -= gravity * Time.deltaTime; movePlayer = lastMovePlayer; } if (Caida == true) { fallVelocity -= gravity * Time.deltaTime; } if (player.isGrounded && Wallrun == false) { Caida = false; Salto = false; WallrunCount = false; //I assign the horizontal move to the w and s keys. horizontalmove = Input.GetAxis("Horizontal"); //I assign the vertical move to the a and d keys.) verticalmove = Input.GetAxis("Vertical"); //controls the movement direction playerInput = new Vector3(horizontalmove, 0, verticalmove); //limits the player speed. With this method if teh player waalks in diagonal doesn´t //exceed the speed limit. playerInput = Vector3.ClampMagnitude(playerInput, 1); // It calls the function that give the camera look direction. camDirection(); //Here, It
s calculates the player movement considering the camera point and the movement //we have assing to teh player earlier //With this method the player always moves looking to the camera movePlayer = playerInput.x camRight + playerInput.z camForward;
//The movement * the speed we want.
movePlayer = movePlayer * playerSpeed;
//we are going to say to the player where is looking at.
player.transform.LookAt(player.transform.position + movePlayer);
//It gives the gravity to the player.
fallVelocity = -gravity * Time.deltaTime;
if (Input.GetKeyDown(KeyCode.Space))
{
Salto = true;
fallVelocity = jumpForce;
}
}
else if (!player.isGrounded && Salto == false && Wallrun == false)
{
Caida = true;
}
movePlayer.y = fallVelocity;
//we give the movement to th eplayer.
player.Move(movePlayer * Time.deltaTime);
lastMovePlayer = movePlayer;
}
private void OnTriggerStay(Collider other) { if (Input.GetKeyDown(KeyCode.LeftShift) && Wallrun == false && WallrunCount == false) { if (Input.GetKey("w")) { Wallrun = true; WallrunCount = true; fallVelocity = 5f; movePlayer.y = fallVelocity; movePlayer.z = movePlayer.z * 1.6f; if (Physics.Raycast(transform.position, transform.right, out HitR, 1)) { movePlayer.x = 1.6f; } else if (Physics.Raycast(transform.position, -transform.right, out HitL, 1)) { movePlayer.x = -1.6f; } StartCoroutine(wallrunTime()); } } }
void camDirection() { //we store the forward and right directions here. camForward = mainCamera.transform.forward; camRight = mainCamera.transform.right;
//we block the direction and the camera direction because we are not going to use it.
camForward.y = 0;
camRight.y = 0;
//It gives as the normalized vectors.
camForward = camForward.normalized;
camRight = camRight.normalized;
}
private void OnControllerColliderHit(ControllerColliderHit hit) { if (!player.isGrounded && hit.normal.y < 0.1f) {
if (Input.GetKeyDown(KeyCode.Space))
{
fallVelocity = jumpForce;
movePlayer = hit.normal * 7;
player.transform.LookAt(player.transform.position + movePlayer);
}
}
}
IEnumerator wallrunTime() { yield return new WaitForSeconds(1); Wallrun = false; } As you can see, when the player enters the leftshift it checks to what direction is moving the character, if this is front (w) the script make the z movement * 1.6 (to make the character run a bit in the wall) and the character go a bit up bit the y axis.Then, the script checks if the Wall it i son the right or on the left and, depending on where the wall is, sticks the character to that wall.
private void OnTriggerStay(Collider other) { if (Input.GetKeyDown(KeyCode.LeftShift) && Wallrun == false && WallrunCount == false) { if (Input.GetKey("w")) { Wallrun = true; WallrunCount = true; fallVelocity = 5f; movePlayer.y = fallVelocity; movePlayer.z = movePlayer.z * 1.6f; if (Physics.Raycast(transform.position, transform.right, out HitR, 1)) { movePlayer.x = 1.6f; } else if (Physics.Raycast(transform.position, -transform.right, out HitL, 1)) { movePlayer.x = -1.6f; } StartCoroutine(wallrunTime()); } } }
With this method, I can make the character jump when the player enters space because the character is hitting the wall (a condition required to bounce in the wall).
And after some seconds, the character falls simulating a wallrun.
IEnumerator wallrunTime()
{
yield return new WaitForSeconds(1);
Wallrun = false;
}
The problem is that this works perfectly if the character makes the wallrun when is looking in the same direction as the axes of the environment.
When the character z axis is looking at the same direction of the environment z axes it works perfectly. But when the axes are not looking at the same direction is a disaster. I show you a video I have recorded.
The problem, I suppose, is that with the code I have written, I'm moving the character according to the axes of the environment, and not its axes, so I have to tell him to move according to his own.
My teacher says I might have to change the way I make the character move. I would like to know if you can tell me a way to fix this without changing the movement method or if it is not possible, how can I change that movement.
Thank you in advance.