Using ScriptableObjects to Create Dynamic Recoil System

Howdy! I’ve currently been working on a prototype weapon system that has a dynamic recoil system. Currently, all the variables needed are in place but it’s just a matter of figuring out out to make it function on a per weapon basis. Currently, the recoil system is attached and it’s variables are attached to the PlayerCamera. I’m using a ScriptableObject to store the variables so it’s easier to drag and drop different values quickly instead of having to type them in every time I want to change them.
8473988--1126241--upload_2022-9-28_15-31-34.png
Because of how it’s implemented, I can only use the recoil data of one ScriptableObject that’s dragged in because the “Recoil Data” variable only holds one of the ScriptableObject assets at a time and doesn’t seem like it can be switched dynamically. My idea is that I instead hold the modifiers of the recoil on the weapon GameObjects instead of the PlayerCamera while still calling the actual “RecoilFire” function from the camera itself. In it’s current form, the Recoil script which is attached to the camera looks like this.

{

    //Rotation
    private Vector3 currentRotation;
    private Vector3 targetRotation;

    public RecoilData recoilData;

    void Start()
    {
       
    }


    void Update()
    {
        targetRotation = Vector3.Lerp(targetRotation, Vector3.zero, recoilData.returnSpeed * Time.deltaTime);
        currentRotation = Vector3.Slerp(currentRotation, targetRotation, recoilData.snap * Time.fixedDeltaTime);
        transform.localRotation = Quaternion.Euler(currentRotation);
    }

    public void RecoilFire()
    {
        targetRotation += new Vector3(recoilData.recoilX, Random.Range(-recoilData.recoilY, recoilData.recoilY), Random.Range(-recoilData.recoilZ, recoilData.recoilZ));
    }
}

with the ScriptableObject script that holds the values looking like this

{

    public new string name;

    [Header("HipRecoil")]
    public float recoilX;
    public float recoilY;
    public float recoilZ;

    [Header("Settings")]
    public float snap;
    public float returnSpeed;
}

What I’m attempting to do is continue to store the variables in the ScriptableObjects script, have another script that I can drag the values into that sits on my weapon GameObjects, and continue to execute the “RecoilFire” function through the camera.

I currently am trying to implement the variables from the ScriptableObject into a script on the weapons that looks like this

{

    private Vector3 currentRotation;
    private Vector3 targetRotation;

    public RecoilData recoilData;

    void Start()
    {
       
    }

    void Update()
    {
        targetRotation = Vector3.Lerp(targetRotation, Vector3.zero, recoilData.returnSpeed * Time.deltaTime);
        currentRotation = Vector3.Slerp(currentRotation, targetRotation, recoilData.snap * Time.fixedDeltaTime);
        transform.localRotation = Quaternion.Euler(currentRotation);
    }
}

and the values are held on the weapons like this

8473988--1126250--upload_2022-9-28_15-44-53.png

Obviously, the duplicate code would be deleted once implemented fully, but I have it there on the camera’s recoil script so I at least keep the recoil functionality in the meantime.

But I’m not sure how exactly I should call those values to the camera’s “RecoilFire” function, I think it has something to do with referencing the Camera GameObject, but I’ve tried a few approaches and it doesn’t seem to work how I’m intending it to. Any suggestions on implementation?

8473988--1126241--upload_2022-9-28_15-31-34.png
8473988--1126241--upload_2022-9-28_15-31-34.png

Moving the recoil data into the weapon makes sense.

But why not move up one level and have a MasterWeaponConfiguration ScriptableObject?

It could have fields for everything!

  • the prefab
  • the recoil data
  • the damage it deals
  • how heavy it is
  • is it 2-handed

etc.

I would still make recoil data a separate ScriptableObject and slot it in, because that keeps you from having to duplicate a lot of data, such as perhaps having identical recoil on all pistols of a given size / caliber.

With the above system, EVERYTHING would only access weapons through a MasterWeaponConfiguration instance.

Yep, great idea! In fact, I already have a separate script that does that exactly. And this recoil script is already separated for the same reasons you just mentioned, it’s all just a matter of implementation.

Oh man, I absolutely love saying that at the end of our technical discussion meetings.