Search Unity

Camera Rotation Flickering When Wall-Running

Discussion in 'Scripting' started by ElysianOne, Jan 19, 2018.

  1. ElysianOne

    ElysianOne

    Joined:
    Aug 16, 2017
    Posts:
    7
    Hey everyone, wondered if you could help me.
    I'm working on the foundations for a parkour/fps game and I've run into an odd problem. I have implemented wall-running and wall-climbing along with a basic shooting mechanic which fires projectiles in a straight line following the camera's transform.forward. However, wall-running (performed by holding W + A/D parallel to a wall), or just the player hitting a wall while facing parallel to it, causes the camera's transform.forward to flicker rapidly each frame between two different directions, normally about 5 degrees apart, and so the shooting starts to be inaccurate and fire along the wrong line. One of the two directions is the correct forward, the other is offset 5ish degrees in the direction of the wall the player hit. What's even weirder is that wall-climbing (performed by holding W while facing a wall) will then fix the problem. Code as follows.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PlayerMovement : MonoBehaviour {
    6.  
    7.     public float moveSpeed;
    8.     public float jumpHeight;
    9.     public float climbSpeed;
    10.     public float dashCooldownTime;
    11.     float translation;
    12.     float strafe;
    13.     bool grounded;
    14.     bool canDoubleJump;
    15.     public GameObject shuriken;
    16.     GameObject tempShuriken;
    17.     float shootTimer;
    18.     float requiredShootTimer;
    19.     public Camera cam1;
    20.     public GameObject shurikenSpawn;
    21.     float dashCooldown;
    22.     bool climbing;
    23.     Vector3 side1;
    24.     Vector3 side2;
    25.     bool wallRunning;
    26.  
    27.     // Use this for initialization
    28.     void Start () {
    29.         Cursor.lockState = CursorLockMode.Locked;
    30.         shootTimer = 1;
    31.         dashCooldown = 3;
    32.         requiredShootTimer = 1;
    33.         climbing = false;
    34.     }
    35.  
    36.     // Update is called once per frame
    37.     void Update () {
    38.         shootTimer += 1 * Time.deltaTime;
    39.         dashCooldown += 1 * Time.deltaTime;
    40.         side1 = transform.TransformDirection(Vector3.right);
    41.         side2 = transform.TransformDirection(-Vector3.right);
    42.         if (climbing == false)
    43.         {
    44.             if (Input.GetAxis("Horizontal") > 0)
    45.             {
    46.                 translation = Input.GetAxis("Vertical") * moveSpeed * Time.deltaTime / (1 + (Input.GetAxis("Horizontal") / 2));
    47.             }
    48.             else
    49.             {
    50.                 translation = Input.GetAxis("Vertical") * moveSpeed * Time.deltaTime / (1 + (-Input.GetAxis("Horizontal") / 2));
    51.             }
    52.         }
    53.         else
    54.         {
    55.             GetComponent<Rigidbody>().velocity = new Vector3(GetComponent<Rigidbody>().velocity.x, climbSpeed, GetComponent<Rigidbody>().velocity.z);
    56.         }
    57.         if ((Physics.Raycast(transform.position, side1, 1) && Input.GetAxis("Horizontal") > 0) || (Physics.Raycast(transform.position, side2, 1) && Input.GetAxis("Horizontal") < 0))
    58.         {
    59.             GetComponent<Rigidbody>().useGravity = false;
    60.             GetComponent<Rigidbody>().velocity = new Vector3(GetComponent<Rigidbody>().velocity.x, 0, GetComponent<Rigidbody>().velocity.z);
    61.             strafe = 0;
    62.             wallRunning = true;
    63.             canDoubleJump = true;
    64.         }
    65.         else
    66.         {
    67.             wallRunning = false;
    68.             GetComponent<Rigidbody>().useGravity = true;
    69.             if (Input.GetAxis("Vertical") > 0)
    70.             {
    71.                 strafe = Input.GetAxis("Horizontal") * moveSpeed * Time.deltaTime / (1 + (Input.GetAxis("Vertical") / 2));
    72.             }
    73.             else
    74.             {
    75.                 strafe = Input.GetAxis("Horizontal") * moveSpeed * Time.deltaTime / (1 + (-Input.GetAxis("Vertical") / 2));
    76.             }
    77.         }
    78.  
    79.         if (grounded == false && wallRunning == false)
    80.         {
    81.             translation /= 1.5f;
    82.             strafe /= 1.5f;
    83.         }
    84.  
    85.         GetComponent<Rigidbody>().AddForce(transform.forward * translation);
    86.         GetComponent<Rigidbody>().AddForce(transform.right * strafe);
    87.  
    88.         if (Input.GetKeyDown(KeyCode.LeftShift) && dashCooldown >= dashCooldownTime)
    89.         {
    90.             dashCooldown = 0;
    91.             GetComponent<Rigidbody>().velocity = cam1.transform.forward * 25;
    92.         }
    93.  
    94.         if (Input.GetKeyDown(KeyCode.Space))
    95.         {
    96.             if (grounded == true)
    97.             {
    98.                 grounded = false;
    99.                 GetComponent<Rigidbody>().velocity = new Vector3(GetComponent<Rigidbody>().velocity.x, jumpHeight, GetComponent<Rigidbody>().velocity.z);
    100.             }
    101.             else if (canDoubleJump == true)
    102.             {
    103.                 canDoubleJump = false;
    104.                 GetComponent<Rigidbody>().velocity = new Vector3(GetComponent<Rigidbody>().velocity.x, jumpHeight, GetComponent<Rigidbody>().velocity.z);
    105.             }
    106.             }
    107.  
    108.  
    109.         if (Input.GetMouseButton(0) && shootTimer >= requiredShootTimer)
    110.         {
    111.             StartCoroutine(FireShurikens());
    112.         }
    113.         if (Input.GetMouseButton(1) && shootTimer >= requiredShootTimer)
    114.         {
    115.             StartCoroutine(ShurikenSpam());
    116.         }
    117.  
    118.         if (Input.GetKeyDown("escape"))
    119.         {
    120.             Cursor.lockState = CursorLockMode.None;
    121.         }
    122.         Debug.DrawRay(shurikenSpawn.transform.position, cam1.transform.forward * 15, Color.green);
    123.     }
    124.  
    125.     void FixedUpdate()
    126.     {
    127.         GetComponent<Rigidbody>().velocity = new Vector3(GetComponent<Rigidbody>().velocity.x * 0.95f, GetComponent<Rigidbody>().velocity.y, GetComponent<Rigidbody>().velocity.z * 0.95f);
    128.         Vector3 fwd = transform.TransformDirection(Vector3.forward);
    129.         if (Physics.Raycast(new Vector3(transform.position.x, transform.position.y - 0.75f, transform.position.z), fwd, 1))
    130.         {
    131.             climbing = true;
    132.             canDoubleJump = true;
    133.         }
    134.         else
    135.         {
    136.             climbing = false;
    137.         }
    138.     }
    139.  
    140.     void OnCollisionStay()
    141.     {
    142.         grounded = true;
    143.         canDoubleJump = true;
    144.     }
    145.  
    146.     void OnCollisionExit()
    147.     {
    148.         grounded = false;
    149.     }
    150.  
    151.  
    152.     IEnumerator FireShurikens()
    153.     {
    154.         requiredShootTimer = 1;
    155.         shootTimer = 0;
    156.         for (int i = 0; i < 3; i++)
    157.         {
    158.             tempShuriken = Instantiate(shuriken, shurikenSpawn.transform.position, shurikenSpawn.transform.rotation);
    159.             tempShuriken.GetComponent<Rigidbody>().velocity = cam1.transform.forward * 25;
    160.             yield return new WaitForSeconds(0.1f);
    161.         }
    162.     }
    163.     IEnumerator ShurikenSpam()
    164.     {
    165.         requiredShootTimer = 0.5f;
    166.         shootTimer = 0;
    167.             tempShuriken = Instantiate(shuriken, shurikenSpawn.transform.position, shurikenSpawn.transform.rotation);
    168.             tempShuriken.transform.Rotate(transform.up * -10);
    169.             tempShuriken.GetComponent<Rigidbody>().velocity = tempShuriken.transform.forward * 25;
    170.         tempShuriken = Instantiate(shuriken, shurikenSpawn.transform.position, shurikenSpawn.transform.rotation);
    171.         tempShuriken.GetComponent<Rigidbody>().velocity = tempShuriken.transform.forward * 25;
    172.         tempShuriken = Instantiate(shuriken, shurikenSpawn.transform.position, shurikenSpawn.transform.rotation);
    173.         tempShuriken.transform.Rotate(transform.up * 10);
    174.         tempShuriken.GetComponent<Rigidbody>().velocity = tempShuriken.transform.forward * 25;
    175.         yield return null;
    176.     }
    177.  
    178. }
    179.  

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class CameraControls : MonoBehaviour {
    6.  
    7.     Vector2 mouseLook;
    8.     public float sensitivity;
    9.     GameObject character;
    10.  
    11.     // Use this for initialization
    12.     void Start () {
    13.         character = this.transform.parent.gameObject;
    14.     }
    15.  
    16.     // Update is called once per frame
    17.     void Update () {
    18.         var md = new Vector2(Input.GetAxisRaw("Mouse X") * sensitivity, Input.GetAxisRaw("Mouse Y") * sensitivity);
    19.         mouseLook += md;
    20.         transform.localRotation = Quaternion.AngleAxis(-mouseLook.y, Vector3.right);
    21.         character.transform.localRotation = Quaternion.AngleAxis(mouseLook.x, character.transform.up);
    22.     }
    23. }
    Any help would be greatly appreciated as I can't seem to figure out what's going wrong.
    Many thanks!
     
    Last edited: Jan 19, 2018
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,738
    I'm going to guess something about your physics setup is "snagging" the wall-facing side of the player and rotating him, which causes your camera to rotate, then the next frame you drive the player back to the right orientation, so you get the flicker.

    Maybe try making the wall very slippery with a PhysicMaterial, see if the problem goes away. That's not a great solution, but it might be all you need.
     
  3. ElysianOne

    ElysianOne

    Joined:
    Aug 16, 2017
    Posts:
    7
    You're the best! Don't know why I never thought of that!
    This is why I love this community so much. Thanks!
     
    Kurt-Dekker likes this.