Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

3D Top Down Shooter Aiming Issue

Discussion in 'Editor & General Support' started by camerontownsend, Oct 31, 2021.

  1. camerontownsend

    camerontownsend

    Joined:
    Mar 7, 2019
    Posts:
    14
    Hello superior coders,

    I’m in the process of building a 3rd person 3D top-down (3/4) perspective shooter system in which the player aims toward the cursor and fires upon clicking.

    However, though the player aims toward the mouse just fine for the most part, the aim starts to be askew from the actual cursor location when aiming diagonally.

    Here is a visual of my issue below:

    https://drive.google.com/file/d/1bQdMbYy8t7Vh4vGPXM5H2pZTB-W_erYh/view?usp=sharing
    (For the record, if any of you know how to post gifs here that would be nice as well)


    As you can see, the player rotates to follow the mouse and can shoot blasts toward the mouse just fine for the most part (particularly when aiming toward the upper half of the screen), but when aiming diagonally, particularly in the lower half of the screen, the shots are way off.

    The player character is using a character controller, and she is tracking the camera with this piece of code:


    Code (CSharp):
    1. float h = Input.mousePosition.x - Screen.width / 2;
    2. float v = Input.mousePosition.y - Screen.height / 2;
    3. float angler = -Mathf.Atan2(v, h) * Mathf.Rad2Deg;
    4.  
    5. transform.rotation = Quaternion.Euler(0, (angler + 90), 0);


    The blasts simply fly in a straight line from where the character was facing when the player clicks.

    The camera is a cinemachine free look camera, but I don’t think the camera code is the problem because this issue persists even when the camera is static, and even if I try using orthographic projection.

    Lastly, I'm aware that there is a technique to raycast from the mouse to the surface of the ground and use the raycast hit location as the destination for the player to rotate toward, but I would also like the player to be able to aim off cliffs and across chasms - places where the raycast hit technique probably wouldn't work right at a 3/4 angle like this.

    I just want the player to rotate on her y axis to face the mouse exactly.

    Help me, superior coders. You’re my only hope.
     
    Last edited: Oct 31, 2021
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    First find out if your mouse-to-world is correct. When you click, call GameObject.CreatePrimitive() and make a sphere, place it at the world position of your click. Is it correct? If not, fix that.

    Whatever the issue is, you must find a way to get the information you need in order to reason about what the problem is.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is

    To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also put in Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    If you are running a mobile device you can also view the console output. Google for how on your particular mobile target.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494
     
    camerontownsend likes this.
  3. camerontownsend

    camerontownsend

    Joined:
    Mar 7, 2019
    Posts:
    14
    Thank you so much for your reply! I'm going to look into all of this as soon as I can and try to see if I can't figure out the issue.
     
  4. camerontownsend

    camerontownsend

    Joined:
    Mar 7, 2019
    Posts:
    14
    SOLVED:

    I always hate looking up an issue on the forums and seeing that the original poster found the solution but didn't post it, so I'll post mine. In case any unfortunate souls have this same issue, I was able to resolve it by the following means:

    I referred to my GAMEMASTER object (I'm sure you have one, it's that all-seeing, invisible object that controls everything in the game behind the scenes, some people call it GameManager, WorldControl, etc) and added a public static Vector3 to track the mouse position like so:

    Code (CSharp):
    1. public static Vector3 mouseWorldPosition;
    Then I added this raycasting code in the update method:

    Code (CSharp):
    1. void Update()
    2. {
    3. Plane plane = new Plane(Vector3.up, 0);
    4.  
    5. float distance;
    6. Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    7. if (plane.Raycast(ray, out distance))
    8. {
    9. mouseWorldPosition = ray.GetPoint(distance);
    10. }
    11. }
    It uses a raycast and a virtual plane to calculate the mouse position in 3D space relative to the camera's distance/depth. This may not work for games with complex terrain.

    I then added an invisible empty gameobject in the world called Mouse3D and had it constrain its position to the gamemaster's stored public static Vector3 mouseWorldPosition by giving the empty object these two variables:

    Code (CSharp):
    1.     //To track position in Vector3 form
    2.     public static Vector3 Position;
    3.     //To track transform
    4.     public static Transform SelfTransform;
    And then adding this code in the update method:


    Code (CSharp):
    1.     void Update()
    2.     {
    3.         transform.position = GAMEMASTER.mouseWorldPosition;
    4.         SelfTransform = transform;
    5.         Position = transform.position;
    6.     }
    Finally I simply went to my player character and had her LookAt my new mouse position with this piece of code:

    Code (CSharp):
    1.                     transform.LookAt(Mouse3D.SelfTransform, Vector3.up);
    2.  
    Now it works. It may not be as optimized as physically possible, but it works. Hopefully if anyone came across this issue, this solution could help them.
     
    Kurt-Dekker likes this.