Search Unity

Character controller stops working in perspective cam

Discussion in '2D' started by GearsofMotion, Oct 22, 2020.

  1. GearsofMotion

    GearsofMotion

    Joined:
    Sep 25, 2020
    Posts:
    5
    Hello,

    I have been working on my first project, a mobile game, for 2-3 weeks now. It's an endless runner of sorts but instead of running its a falling character with increasing speed through a canyon.
    I made my assets to be able to work with a perspective camera but if I change my main camera from orthographic to perspective, it simply stops working. For a week now I have tried all sorts of things to fix this but with my limited knowledge of coding and Unity I cannot seem to fgure it out :(.

    This is the code I used on my character ( only the movement parts ).

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class FallCharacter : MonoBehaviour
    6. {
    7.     public static FallCharacter instance = null;
    8.     public Camera MainCamera;
    9.     private Rigidbody2D rb;
    10.     private Vector3 mousePosition;
    11.     private Vector2 screenBounds;
    12.     private Vector2 direction;
    13.     bool isDead = false;
    14.     public float horizontalSpeed;
    15.     public float fallSpeed;
    16.     public float fallSpeedIncreaseTime = 0.0f;
    17.     public float fallSpeedIncreaseValue = 0.0f;
    18.     public float maxfallSpeed;
    19.        
    20.     public Vector3 GetPosition()
    21.     {
    22.         return transform.position;
    23.     }
    24.     void increaseSpeed ()
    25.     {
    26.         if (fallSpeed < maxfallSpeed && isDead == false){
    27.             fallSpeed = fallSpeed + fallSpeedIncreaseValue;
    28.         } else if (fallSpeed > maxfallSpeed){
    29.             fallSpeed = fallSpeed;
    30.         }
    31.        
    32.     }
    33.    
    34.     void Start(){
    35.         InvokeRepeating("increaseSpeed", fallSpeedIncreaseTime, fallSpeedIncreaseTime);
    36.         screenBounds = MainCamera.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, MainCamera.transform.position.z));
    37.         rb = GetComponent<Rigidbody2D>();
    38.     }  
    39.  
    40.     private void Update(){
    41.         HandleMovement();
    42.     }
    43.     private void HandleMovement(){
    44.         if (Input.GetMouseButton(0) && isDead == false )
    45.         {
    46.             mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    47.             direction = (mousePosition - transform.position).normalized;
    48.             rb.velocity = new Vector2(direction.x * horizontalSpeed * (fallSpeed /2), 0 - fallSpeed);
    49.            
    50.             Vector3 viewPos = transform.position;
    51.             viewPos.x = Mathf.Clamp(viewPos.x, screenBounds.x * -1, screenBounds.x);
    52.             transform.position = viewPos;
    53.            
    54.         }
    55.         else {
    56.             rb.velocity = new Vector2(0, fallSpeed *-1);
    57.         }
    58.     }
    59. }
    Can anyone help me fix my code? I am stumped...
    Heres a screenshot of the game so far. The green outlined is foreground and the waterfall is back, by changing the cam into perspective I could give depth to those layers which are now moving at 1 speed together.
    upload_2020-10-22_9-31-57.png

    Thank you in advance :)
     
  2. webox

    webox

    Joined:
    Aug 27, 2015
    Posts:
    72
    letting your actual issue aside, why did you "have" to use a perspective camera? were sorting layers not enough for what you wanted to do? Maybe it's not visible in the still screenshot, but it seems like an orthographic camera and sorting layers would be enough.
     
  3. GearsofMotion

    GearsofMotion

    Joined:
    Sep 25, 2020
    Posts:
    5
    Thanks for your reply webox.

    The reason I want to have a perspective camera is because I want actual depth in the scenes. Some parts moving slower than the other. The way I prepared my generated prefabs is like this ( tilted in the scene view to see the intended depth) :

    upload_2020-10-22_14-3-9.png

    The dark cyan parts are behind the black/green frontground
    There will be another layer very very far away to complete the "shoebox" depth effect. I hope this makes my question a bit more clear.

    If you are implying there is another way to do this easily within orthographic then I am all ears! :D
     
  4. Cornysam

    Cornysam

    Joined:
    Feb 8, 2018
    Posts:
    1,465
    You can achieve this by paralaxing. Just by using some code you can fake the movement of the background/foreground, etc. There are plenty of videos on Paralaxing
     
  5. webox

    webox

    Joined:
    Aug 27, 2015
    Posts:
    72
    Ahh, I figured you wanted to make some kind of effect, that's why I's asking... When you use a perspective camera, you cannot really use ScreenToWorldPoint as you would do on an orthographic camera, since it's converting to a 3D point in the world. When you click on the screen it's actually pointing to something in the 3d space. If you want to use a perspective camera on a 2D game to get the position you have to create a "fake" plane and raycast to that plane. Such a plane has to be on the same Z value as your character. This should work:

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. public class FallCharacter : MonoBehaviour
    6. {
    7.     public static FallCharacter instance = null;
    8.     public Camera MainCamera;
    9.     private Rigidbody2D rb;
    10.     private Vector3 mousePosition;
    11.     private Vector2 screenBounds;
    12.     private Vector2 direction;
    13.     bool isDead = false;
    14.     public float horizontalSpeed;
    15.     public float fallSpeed;
    16.     public float fallSpeedIncreaseTime = 0.0f;
    17.     public float fallSpeedIncreaseValue = 0.0f;
    18.     public float maxfallSpeed;
    19.      
    20.     public Vector3 GetPosition()
    21.     {
    22.         return transform.position;
    23.     }
    24.     void increaseSpeed ()
    25.     {
    26.         if (fallSpeed < maxfallSpeed && isDead == false){
    27.             fallSpeed = fallSpeed + fallSpeedIncreaseValue;
    28.         } else if (fallSpeed > maxfallSpeed){
    29.             fallSpeed = fallSpeed;
    30.         }
    31.      
    32.     }
    33.  
    34.     void Start(){
    35.         InvokeRepeating("increaseSpeed", fallSpeedIncreaseTime, fallSpeedIncreaseTime);
    36.         screenBounds = GetPerspectiveCameraWorldPoint(new Vector3(Screen.width, Screen.height, MainCamera.transform.position.z));
    37.         rb = GetComponent<Rigidbody2D>();
    38.     }
    39.     private void Update(){
    40.         HandleMovement();
    41.     }
    42.     private void HandleMovement(){
    43.         if (Input.GetMouseButton(0) && isDead == false )
    44.         {
    45.             mousePosition = GetPerspectiveCameraWorldPoint(Input.mousePosition);
    46.             Debug.Log(mousePosition);
    47.  
    48.             direction = (mousePosition - transform.position).normalized;
    49.             rb.velocity = new Vector2(direction.x * horizontalSpeed * (fallSpeed /2), 0 - fallSpeed);
    50.          
    51.             Vector3 viewPos = transform.position;
    52.             viewPos.x = Mathf.Clamp(viewPos.x, screenBounds.x * -1, screenBounds.x);
    53.             transform.position = viewPos;
    54.          
    55.         }
    56.         else {
    57.             rb.velocity = new Vector2(0, fallSpeed *-1);
    58.         }
    59.     }
    60.  
    61.     public Vector3 GetPerspectiveCameraWorldPoint(Vector3 screenPosition)
    62.     {
    63.         float distanceToPlane;
    64.         Ray ray = Camera.main.ScreenPointToRay(screenPosition);
    65.         Plane fakePlane = new Plane(Vector3.forward, new Vector3(0, 0, 0));
    66.         fakePlane.Raycast(ray, out distanceToPlane);
    67.         return ray.GetPoint(distanceToPlane);
    68.     }
    69.  
    70. }
    PS: Probably you already know this but, If you're using unity's physics it could be better to use AddForce instead of messing with the velocity,
     
  6. GearsofMotion

    GearsofMotion

    Joined:
    Sep 25, 2020
    Posts:
    5
    Thank you webox! This worked instantly, i'm so happy :). I had been stuck on this for so many days!
    I did not know about AddForce being better than velocity. Thanks for the heads up!
     
    webox likes this.
  7. webox

    webox

    Joined:
    Aug 27, 2015
    Posts:
    72
    Awesome! I'm glad it worked as you expected! I put the fake plane in z=0, if you start moving stuff in Z take that into account, make the plane match the z of your player

    Code (CSharp):
    1. Plane fakePlane = new Plane(Vector3.forward, new Vector3(0, 0, 0));