0
\$\begingroup\$

For one segment of my game, the player is in a fixed position (no movement) and has to aim and shoot at enemies in a first person 3D perspective using the Mouse. The player is holding a wand that shoots projectiles (which I have working) and I need it to rotate and aim towards the cursor as an aiming reticle. I also want to limit how much the player can rotate, so they can look around, but can't turn more than 180 degrees (sort of like this). However, I'm a designer and am having trouble programming this myself. I haven't been able to find a proper solution.

So far, I've been able to cobble the following code together, but the aiming is super wonky and doesn't properly point to the mouse position, making it impossible to actually aim at anything. I would really appreciate some help with figuring this out.

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

public class PlayerShoot : MonoBehaviour {

public float magnifier = 0.5f;
public Rigidbody shotPrefab;
public Transform barrelEnd;
public float shotSpeed = 500;
public Rigidbody sparkPrefab;


// Update is called once per frame
void Update () {

    Ray mouseRay = Camera.main.ScreenPointToRay (Input.mousePosition);
    float midPoint = (transform.position - Camera.main.transform.position).magnitude * magnifier;

    transform.LookAt (mouseRay.origin + mouseRay.direction * midPoint*magnifier);

    if (Input.GetButtonDown("Fire1"))
    {
        Rigidbody shotInstance;
        shotInstance = Instantiate(shotPrefab, barrelEnd.position, barrelEnd.rotation) as Rigidbody;
        shotInstance.AddForce(barrelEnd.forward * shotSpeed);
        sparkBlast();

    }
}
// Particle recoil effect
void sparkBlast () {
    Rigidbody shotSparks;
    shotSparks = Instantiate(sparkPrefab, barrelEnd.position, barrelEnd.rotation) as Rigidbody;
    Destroy (shotSparks,0.5f);
}

}
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

Usually for an FPS style interface, we'd want to hide and lock the mouse cursor to the middle of the screen, so the player isn't distracted by the cursor zipping around disconnected from their aiming reticle, and doesn't accidentally click outside the window and interrupt the game.

We can do that something like this:

public class SimpleTurretCamera : MonoBehaviour {

    [Tooltip("Speed multiplier for horizontal & vertical rotation.")]
    public Vector2 turnSpeed = new Vector2(1, 1);

    [Tooltip("Maximum rotation from the initial orientation.")]
    public Vector2 degreeClamp = new Vector2(90, 80);

    [Tooltip("Check this box if you want forward input to look downward.")]
    public bool invertY;

    // Orientation state.
    Quaternion _initialOrientation;
    Vector2 _currentAngles;   

    // Cached cursor state.
    CursorLockMode _previousLockState;
    bool _wasCursorVisible;

    void OnEnable () {
        // Cache our starting orientation as our center point.
        _initialOrientation = transform.localRotation;

        // Cache the previous cursor state so we can restore it later.
        _previousLockState = Cursor.lockState;
        _wasCursorVisible = Cursor.visible;

        // Hide & lock the cursor for that FPS experience
        // and to avoid distractions / accidental clicks
        // from the mouse cursor moving around.
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }

    void Update () {
        // Collect relative motion of mouse since last frame.
        Vector2 motion = new Vector2(
                            Input.GetAxis("Mouse X"), 
                            Input.GetAxis("Mouse Y"));

        // Scale it by the turn speed, add it to our current angle, and clamp.
        motion = Vector2.Scale(motion, turnSpeed);
        _currentAngles += motion;
        _currentAngles = Vector2.Min(_currentAngles, degreeClamp);
        _currentAngles = Vector2.Max(_currentAngles, -degreeClamp);

        // Rotate to look in this direction, relative to our initial orientation.
        Quaternion look = Quaternion.Euler(
                            -_currentAngles.y,                       // Yaw
                            (invertY ? -1f : 1f) * _currentAngles.x, // Pitch
                            0);                                      // Roll

        transform.localRotation = _initialOrientation * look;
    }

    void OnDisable () {
        // When switched off, put everything back the way we found it.
        Cursor.visible = _wasCursorVisible;
        Cursor.lockState = _previousLockState;
        transform.localRotation = _initialOrientation;
    }
}
\$\endgroup\$
4
  • \$\begingroup\$ This is working so far, but personally, I want the actual object shooting projectiles (a wand) to move and I would like the player to be able to see the cursor as a reticle. I have rectified the cursor and added a reticle to this code on my own, but I still don't have the wand moving properly. It's not pointing towards where it needs to aim and I can't really aim it forward. How do I make it always point and shoot towards the cursor? \$\endgroup\$
    – JSparks
    Commented Dec 30, 2017 at 10:37
  • \$\begingroup\$ Ohhhh. That detail should probably be added to your question then. ;) Nothing in the text mentions that you want to rotate both the player perspective and a weapon that tracks the cursor within that perspective frame. Remember that we've never seen your game, so when you say "first person mouse aiming," folks are likely to assume you're describing conventional FPS controls. Is it safe to assume you want the view to rotate when the cursor approaches the edge of the screen? Or do you control the perspective separately? \$\endgroup\$
    – DMGregory
    Commented Dec 30, 2017 at 15:31
  • \$\begingroup\$ Apologies for not mentioning that. My main focus though is getting the aiming working. I need my wand to always aim towards where my cursor/reticle is. I would like for the player camera to slightly rotate when the cursor gets to the edges of the screen if possible, but without allowing the player to look fully look around 360. \$\endgroup\$
    – JSparks
    Commented Dec 30, 2017 at 19:30
  • \$\begingroup\$ Edit your question to describe what you need. I'll be able to provide an updated answer later tonight, if nobody beats me to it. \$\endgroup\$
    – DMGregory
    Commented Dec 30, 2017 at 20:04
0
\$\begingroup\$

Okay, so I got a bit of help elsewhere and mostly solved the issue. I'll post my code here for people to see in case someone else has the same issue, but surprisingly it had a lot to do with changing transform.forward into transform.up.

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

public class PlayerShoot : MonoBehaviour {

public float magnifier = 0.5f;
public Rigidbody shotPrefab;
public Transform barrelEnd;
public float shotSpeed = 500;
public Rigidbody sparkPrefab;
public Rigidbody sparkBurst;

public Texture2D reticle;
public CursorMode cursorMode = CursorMode.Auto;
public Vector2 hotSpot = Vector2.zero;

public int RayLength = 100;

// Update is called once per frame
void Update () 
{
          // Aiming Mechanic
    var vMousePosition = Input.mousePosition;
    vMousePosition.z = Camera.main.nearClipPlane;

    var vPosition = Camera.main.ScreenToWorldPoint(vMousePosition);

    var vForward = (vPosition-Camera.main.transform.position).normalized;
    var ray = new Ray(Camera.main.transform.position, vForward);

    var targetPosition = ray.origin + (ray.direction * RayLength); // 100 is arbitary, but should be roughly equal to wand length

    transform.up = (targetPosition - transform.position).normalized;

    //Firing
            if (Input.GetButtonDown("Fire1"))
    {
        Rigidbody shotInstance;
        shotInstance = Instantiate(shotPrefab, barrelEnd.position, barrelEnd.rotation) as Rigidbody;
        shotInstance.AddForce(barrelEnd.forward * shotSpeed);
        sparkBlast();

    }
}
// Particle recoil effect
void sparkBlast () {
    Rigidbody shotSparks;
    Rigidbody shotBurst;
    shotSparks = Instantiate(sparkPrefab, barrelEnd.position, barrelEnd.rotation) as Rigidbody;
    shotBurst = Instantiate(sparkPrefab, barrelEnd.position, barrelEnd.rotation) as Rigidbody;
    Destroy (shotSparks,0.5f);
}

}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .