3rd Person Look at Mouse Script

Ok, so I need a hand again. I’ve scoured YouTube videos, I’ve looked through the forums, and I can’t find any help. I have found plenty of 3rd Person Character Controller and 3rd Person Camera Controller scripts, but what I’m looking for specifically is a script that will cause the rotation of my character to follow the mouse point on the Y axis. Similar to the 2D LookAtMouse scripts, however when I enter those scripts into my game the capsule primitive just lays on it’s side and flaps like a flounder or it only tracks SOME of the mouse movement and inconsistently at that.

So this is what I have attached to my Main Camera –

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LookAtMouse : MonoBehaviour
{
    public GameObject crosshair;
    public GameObject player;
    private Vector3 target;

    void Start()
    {
       
    }

    void Update()
    {
        target = transform.GetComponent<Camera>().ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, transform.position.z));

        Vector3 diff = target - player.transform.position;
        float rotationY = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
        player.transform.rotation = Quaternion.Euler(0.0f, rotationY, 0.0f);
    }

}

–which results in a very inconsistent movement that doesn’t at all resemble the rotation tracking the mouse position.

And just a basic input script for x, z movement.

The game is in the style of Solomons Keep, using 3D character models and a semi top down fixed camera angle. The objective is to have the wizard(player) face the mouse at all times and have independent world space movement so that spells may be cast in all directions independent of movement.

1 Like

+1 for bringing fish into the discussion… well done!

If this is fundamentally a 2D-oriented 3D game, I suspect your flounder issue is because you are using your rotationY argument as the Y rotator, NOT as the Z rotator.

Assuming your camera is “default” for 2D, then the camera is looking primarily +Z, so that is also the axis around which you want to rotate.

Have you tried this for line 22:

player.transform.rotation = Quaternion.Euler(0.0f, , 0.0f, rotationY);

If that’s not right, it should be either 90 or -90 off.

1 Like

So, initially when I wrote the script, that instructor was using it for a 2D TRUE Top down game, so it was initially set up as–

        float rotationZ = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
        player.transform.rotation = Quaternion.Euler(0.0f, 0.0f, rotationZ);

but that caused the floundering. The capsule immediately loads on it’s side and spinning like a hotdog (this causes the “faceplate” child object [ a cube primitive] to flop around on the ground, hence the floundering :wink: {that’s 3 fish and a food for those following along}

Also, unrelated, I have floating movement and I’m not sure where that’s coming from…

At any rate, that’s where I’m stuck.

And this game is running in perspective not orthographic, so it has a camera transform of (P:x0,y8.5,z-5.5 R:x80,y0,z0 S:x1,y1,z1)
I’m not sure if that matters.

Okay, so basically nearly straight-down look onto the X/Z ground plane…gotcha.

In that case, line 18, which produces the target from the mouse position, would seem to be the first wrong step in the chain. Here’s why:

That third argument to ScreenToWorldPoint() is actually the distance from the Camera position forward into the scene.

That third argument is NOT your player position.z but rather whatever GameObject this script is on, so that might be one problem.

But even beyond that, this fixed distance means that as you move the mouse around, with a perspective camera, your target is going to move on a sphere shell ahead of the camera.

Try putting a cube and moving it around to target and you’ll see.

The question is, where do you want to map 2D mouse movement onto, the ground? If so, use a raycast at the ground, or else raycast to a plane. Remember there are three different ways to raycast:

https://discussions.unity.com/t/801152/2

1 Like

So you see the Capsule serves as the player, I want that capsule to rotate to face wherever the mouse is at all times…

Okay, we’re close. You actually DO want the rotationY, but the input (the target) you want is wrong from the calculations on line 18, for the reasons in my post directly above this. You want to raycast at the ground, probably to a mathematical Plane object.

1 Like

Crap. I haven’t even began to learn the raycast functions. I was thinking to begin with that’s probably what I would need. I saw a video earlier about particle effects and the creation thereof, and he coded a simple turret to look at mouse using Raycast, I haven’t been able to find it since though.

–Edit–
I just saw that you posted a link to a very informative reading on Raycasting. Thank you!

So you actually want the mouse “target” thingy to be on the ground regardless where the mouse is on screen, right? That’s super easy. Check it:

       // replace Vector3.zero with something else if your ground isn't AT Y == 0
        Plane p =  new Plane( Vector3.up, Vector3.zero);

/// ray into the scene where the mouse is
        var ray = transform.GetComponent<Camera>().ScreenPointToRay(Input.mousePosition);

// how far did it hit?
        float enter = 0;

// cast
        p.Raycast(ray, out enter);

// get!
        Vector3 target = ray.GetPoint(enter);

That should suffice as a replacement for line 18 above.

And best of all, you should put a no-collider cube in the scene and set its position to target each frame so you KNOW that’s where the mouse is, just for testing.

1 Like

So I’m placing all of these into the Update? Wouldn’t that create a bajillion planes? Secondary question, could I assign the parameters associated with my current “Ground” plane GameObject with that “p” var? so that the plane it is checking against is my actual ground plane?

This “Plane” is just a mathematical struct in memory.

It has no relationship to PrimitiveType.Plane, which is something Unity can construct and see in scene.

IF you want to hit the ground, then you probably want the first type of Raycast here:

https://discussions.unity.com/t/801152/2

With layers you can select for only the ground. There’s example code in the API as it is slightly different:

  • you use layers and layermasks to ONLY hit the ground
  • you use a RaycastHit object to get back from Raycast what you hit
  • inside RaycastHit would be a .point that you would use as your target.
1 Like

Actually, I used the script you recommended and it works!

With a slight catch.

6953732--818348--TS002.PNG.jpg

So I added the cube, removed its rigidbody, and assigned it to target within the LookAtMouse script. I added your script in place of line 18, utilizing the raycast method as opposed to a CameraToScreenPoint method.(I think I said that right?) Now, the capsule looks exactly 90 degress to the positive of the screen point target. I tried to implement a fix –

public float viewOffset = -90.0f

void Update()
{
...
float rotationY = MAthf.Atan2(diff.y, diff.x) * MathfRad2Deg - viewOffset;```

and it correctly rotates to the target. Unless the target is behind the capsule. How can I get it to correct the rotation by the offset, and still track movement behind the GameObject?

--Edit--
By "behind" I don't mean the space on the ground plane blocked by the character capsule, rather the space closest to the camera.
![6953732--818354--TS003.PNG|639x705](upload://bjv10TingVATX1pv8JbVGr4Yuh0.png)

So I looked at a few other sources and found a way to draw the ray from point to point. So I drew a ray from the character to the “target” variable, and this is what I got–6953879--818369--Screenshot (2).png
– I seem to only have about 180 degrees of rotation, and the ray does not line up to the “target”. If you zoom in, you’ll see a small white dot on the game and scene view, that is the “Pointer” cube primitive that has been assigned to the “crosshair” slot on the LookAtMouse class.

UPDATE – SOLVED

So with a little more research, and the help of Kurt-Dekker, I figured out a code that works. Here it is.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    // The variables that power the character/game interaction
    public float speed = 5.0f;
    private Rigidbody myRigidbody;

    private Vector3 moveInput;
    private Vector3 moveVelocity;

    public bool isCasting;
    public bool isPaused;

    private Camera mainCamera;

    // Start is called before the first frame update
    void Start()
    {
        // Delcares the variable as this GameObject's Rigidbody component
        myRigidbody = GetComponent<Rigidbody>();
        // Declares the camera in scene as the variable
        mainCamera = FindObjectOfType<Camera>();
    }

    // Update is called once per frame
    void Update()
    {
        moveInput = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
        moveVelocity = moveInput * speed;

        Ray cameraRay = mainCamera.ScreenPointToRay(Input.mousePosition);
        Plane ground = new Plane(Vector3.up, Vector3.zero);
        float rayLength;

        if(ground.Raycast(cameraRay, out rayLength))
        {
            Vector3 pointToLook = cameraRay.GetPoint(rayLength);
            Debug.DrawLine(cameraRay.origin, pointToLook, Color.blue);
            transform.LookAt(new Vector3(pointToLook.x, transform.position.y, pointToLook.z));
        }

        if (Input.GetKey(KeyCode.Mouse0) && !isPaused)
        {
            isCasting = true;
        }
        else
        {
            isCasting = false;
        }
    }

    void FixedUpdate()
    {
        myRigidbody.velocity = moveVelocity;
    }
}
3 Likes

Omg thank you so much you saved my day

1 Like

You are a hero!!!

1 Like

God Bless you man, this has been driving me nuts the past two days. I learned 2d rotation to follow the mouse fairly easy, but that doesn’t apply to 3d. May life give you boundless riches for your efforts. Thank you.

1 Like
using UnityEngine;

public class CursorLook : MonoBehaviour
{
    void Update()
    {
        Vector3 direction=Input.mousePosition-new Vector3(Screen.width/2,Screen.height/2,0);
        transform.LookAt(transform.position+new Vector3(direction.x,0,direction.y));
    }
}
3 Likes

I’m struggling with my character wanting to rotate horizontally to where the player must look, it either snaps back to the center or doesn’t move at all, here is my code:

using UnityEngine;

public class MouseLook : MonoBehaviour
{
public float mouseSensitivity = 100f; // Sensitivity of mouse movement

float xRotation = 0f; // Current rotation around the x-axis

public Transform playerBody; // Reference to the player’s body

void Start()
{
Cursor.lockState = CursorLockMode.Locked; // Lock cursor to center of screen
}

void Update()
{
// Get mouse input for rotation
float mouseX = Input.GetAxis(“Mouse X”) * mouseSensitivity * Time.deltaTime;
float mouseY = Input.GetAxis(“Mouse Y”) * mouseSensitivity * Time.deltaTime;

// Rotate the player horizontally (around the y-axis)
playerBody.Rotate(Vector3.up * mouseX);

// Calculate vertical (up/down) rotation
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, -90f, 90f); // Limit vertical rotation to prevent flipping

// Rotate the camera vertically (around the x-axis)
transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
}
}