Implementing Weapon Zoom in our FPS

Any questions regarding our implementation of weapon zoom?

Ok, I played a little with the zoom and the BroadcastMessage(), and the result is a magical zoom with “sonar”:

9 Likes

Whoa, that’s a totally different look, @Munsa. Nice work!

I had a go at refactoring my zooming code into a generic method to handle both zoom in and zoom out. It works perfectly if you only half the sensitivity on zoom in but not any other fraction. There’d be a cleaner way to do that (without using magic numbers…maybe const, but that wouldn’t work if the player adjusted the sensitivity in player settings, right?), I’m not smart enough to figure that out.

private void AdjustZoom(float zoomFov, float zoomMultiplier)
	{
		_isZoomedIn = !_isZoomedIn;
		_camera.fieldOfView = zoomFov;
		_rbFps.mouseLook.XSensitivity *= zoomMultiplier;
		_rbFps.mouseLook.YSensitivity *= zoomMultiplier;
	}
1 Like

I don’t know exactly what is the problem with your zoom, perhaps in your zoom out? Have you tried to save the zoomFov before you zoom in? Then you can use it to zoom out (or to zoom in with another zoomMultiplier).

So because I’m using a multiplier instead of magic number I can only make those multipliers half or double to make sure they always end up the same as the original value in this generic method.

My ideology of using a multiplier is what’s bringing me down, but I want to know how to use it as I know it’ll be more versatile in the future when it comes to play testing.

Hi all
Have a bit of a problem , can’t wrap my head around it and google gives me nothing.
Would appreciate any suggestions.

I get an error in Visual Studio - UnityStandardAssets could not be found.
I see the script , I opened it , namespace is correct, it’s in my standard assets but it still throws an error.
I am really confused.



image

I added an animation to the zoom of our weapon, it was really cool and interactive

FieldOFViewWeapon

2 Likes

when converting to .gif the image was very bad but the idea is very visible

OK, [SOLVED]

I figured out how to Hack a solution - but it’s a bit of a mess:
The “problem” is that in the new version of Unity (2019.3) and the new Asset Pack, the MouseLook is no longer in the RigidBody Component. So you can’t access it. If you try accessing the FirstPersonController component directly, it also won’t work, as the MouseLook inside of it is private
So, if you want to fix this, you need to do the following:
First, find the location of the FirstPersonController.cs file (which you have, above). Open it in VisualStudio.
Go down to line 21
[SerializeField] private MouseLook m_MouseLook;
Change it to: [SerializeField] public MouseLook m_MouseLook;

You can now publicly (externally) access the MouseLook class, which is a seperate file labeled MousLook.cs (which you found).

Now, in your code for WeaponZoom, declare your variable of type FirstPersonController:
FirstPersonController fp;

Then, in the Start() function, initialize it:
fp = GetComponent<FirstPersonController>();

Now you can directly access the m_MouseLook class from this variable, since you’ve made it public. So in your zoomToggle If statement, put in terms like this:

fp.m_MouseLook.XSensitivity = zoomedInSensitivity;
fp.m_MouseLook.YSensitivity = zoomedInSensitivity;

It will work, but the Inspector won’t show the changes during runtime, so you’ll have to manually adjust them.

1 Like

My approach! Uses an array of zoom multipliers and cycles between different FoVs and mouse sensitivities, and animates for aiming down sights (thanks for the inspiration @Matheus_Alves)!
It’s also made as a modular component for each weapon, so a rifle can have a single zooming level while a sniper could have more.

void Start()
{
    Zooms2FovsAndSensitivities();

    void Zooms2FovsAndSensitivities()
    {
        numZoomLevels = zoomMultipliers.Length + 1;
        fieldsOfView = new float[numZoomLevels];
        sensitivities = new (float x, float y)[numZoomLevels];

        fieldsOfView[0] = camera.m_Lens.FieldOfView;
        sensitivities[0] = (fpController.mouseLook.XSensitivity, fpController.mouseLook.YSensitivity);

        for (int i = 1; i < numZoomLevels; i++)
        {
            fieldsOfView[i] = Mathf.Clamp(fieldsOfView[0] / zoomMultipliers[i - 1], MinFieldOfView, MaxFieldOfView);
            sensitivities[i] = (sensitivities[0].x / zoomMultipliers[i - 1], sensitivities[0].y / zoomMultipliers[i - 1]);
        }
    }
}

// Update is called once per frame
void Update()
{
    if (Input.GetButtonDown("Fire3"))
    {
        currentZoomIdx = (currentZoomIdx + 1) % numZoomLevels;
        AnimateAim();
        camera.m_Lens.FieldOfView = fieldsOfView[currentZoomIdx];
        (fpController.mouseLook.XSensitivity, fpController.mouseLook.YSensitivity) = sensitivities[currentZoomIdx];
    }

    void AnimateAim()
    {
        bool zoomed = currentZoomIdx > 0;
        gunAnimator.SetBool(zoomBool, zoomed);
        reticle.gameObject.SetActive(!zoomed);
    }
}

I made a method to set sensitivity by current FOV and min/max parameters, used in every update:

private void SetSensitivityByFOV()
{
   mouseLook.YSensitivity = mouseLook.XSensitivity =
           (camera.fieldOfView - zoomedInFOV) / (zoomedOutFOV - zoomedInFOV) 
           * (zoomOutSensitivity - zoomInSensitivity) 
           + zoomInSensitivity;
}

my whole class is here:

public class WeaponZoom : MonoBehaviour
{
    [SerializeField] Camera camera;
    [SerializeField] RigidbodyFirstPersonController fpController;

    [SerializeField] int zoomedInFOV = 25;
    [SerializeField] float zoomInSpeed = 1f;
    [SerializeField] float zoomInSensitivity = 1f;

    [SerializeField] int zoomedOutFOV = 60;
    [SerializeField] float zoomOutSpeed = 5f;
    [SerializeField] float zoomOutSensitivity = 2f;

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButton(1))
        {
            ZoomIn();
        }
        else
        {
            ZoomOut();
        }

        SetSensitivityByFOV();
    }

    private void ZoomOut()
    {
        camera.fieldOfView = Mathf.Clamp(
           camera.fieldOfView + zoomOutSpeed * Time.deltaTime, 
           zoomedInFOV, 
           zoomedOutFOV);
    }

    private void ZoomIn()
    {
        camera.fieldOfView = Mathf.Clamp(
           camera.fieldOfView - zoomInSpeed * Time.deltaTime,
           zoomedInFOV,
           zoomedOutFOV);
    }

    private void SetSensitivityByFOV()
    {
        fpController.mouseLook.YSensitivity = 
        fpController.mouseLook.XSensitivity =
            (camera.fieldOfView - zoomedInFOV) / (zoomedOutFOV - zoomedInFOV)
            * (zoomOutSensitivity - zoomInSensitivity)
            + zoomInSensitivity;
    }
}

Out of all the updates, this one is the most important and potentially game-changing. It’s been several years since the last update, and there’s still no word on a new release. The team has been silent on the matter, and as far as I can tell, there’s no end in sight. It’s frustrating as I’m sure many people would love to see some action on this front. It’s up to us, the users, to keep pushing this issue forward. With this new zoom update, I have more FPS. You can check yours using this fps tester. I hope there will be more nice updates.

i’m having trouble with the mouse zoom. I keep having the NullReferenceException: Object reference not set to an instance of an object error in unity. I can’t trace the problem in my code even witht the error line they’re giving me (line 51 and line 45) here’s my code :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.Characters.FirstPerson;

public class Zoom : MonoBehaviour
{
    [SerializeField] Canvas sniperScope;
    [SerializeField] Canvas regularCrosshair;

    [SerializeField] float zoomOutSensitivity = 2f;
    [SerializeField] float zoomInSensitivity = 0.5f;
    float noZoom = 60f;
    float zoom = 40f;
    Canvas scope;
    Camera cameraZoom;

    RigidbodyFirstPersonController fpsController;
    private void Start()
    {
        //scope.GetComponent<Canvas>();
        cameraZoom = GetComponent<Camera>();
        fpsController = GetComponent<RigidbodyFirstPersonController>();
    }
    void Update()
    {
        // add and if statement that gonna work with a bool that the sniper will set to enable the scope canvas

        if (Input.GetButton("Fire2"))
        {
            Zooming();


        }
        else
        {
            NotZooming();
        }

    }

    void Zooming()
    {
        cameraZoom.fieldOfView = zoom;
        fpsController.mouseLook.XSensitivity = zoomOutSensitivity;
        fpsController.mouseLook.YSensitivity = zoomInSensitivity;
    }
    void NotZooming()
    {
        cameraZoom.fieldOfView = noZoom;
        fpsController.mouseLook.XSensitivity = zoomOutSensitivity;
        fpsController.mouseLook.YSensitivity = zoomOutSensitivity;
    }
}

anyone can see something wrong in here ? thanks ! 

i have many errors from RigidBodyFirstPersonController Script
how to solve this?? plz reply

Hi,
Im having problem with the zoom. The code works fine, but for some reason the Filed of View in the MainCamera doesn’t change. I tried to change it by hand just for test and it still didn’t work. Someone knows how to fix that?

Because the Starter Assests Pack is quite different from the old Standard Assests Pack. Your Main Camera now seems to be overridden by a CinemachineVirtualCamera, you can find it in the PlayerCameraRoot gameObject->PlayerFollowCamera, inside your Player prefab. Then in code, you need a reference to that Camera instead of the Main Camera itself (remember using Cinemachine namespace) and change your logic to something like this:

        > if(!zoomedInToggle)
        {
            zoomedInToggle = true;
            cvCamera.m_Lens.FieldOfView = zoomedInPOV;
        }
        else
        {
            zoomedInToggle = false;
            cvCamera.m_Lens.FieldOfView = zoomedOutPOV;
        }

Privacy & Terms