How can I make a simple automatic shoot function for a gun in Unity?

542 Views Asked by At

I am trying to create a procedural gun controller, but I can't find why my gun behaves so weird when I change the fire mod to automatic. To understand this better, I will give an example: when I try to shoot by pressing the "Mouse0" key, on semi auto mod it works fine, it behaves like I want it to (the bolt kicks back when I shoot, the front barrel kicks back - I animate them with code instead of frame animations from Unity or a 3rd party soft like Blender), but..., when I change to automatic, the problem is not that I get errors, The animations of the moving pieces don't work as they should and are not triggered correctly.

I tried to use different methods for shooting(using the WaitForSeconds() and WaitForSecondsRealtime() while using coroutines). It didn't work. I tried using the time function with scaled and unscaled time in the update function. I still got the same results.

What should I do to?

This is the shoot function untill now:

void GunFireManagement()
{
    if (fireType == fireMethod.single)
    {
        foreach (BlowBack anim in animations)
        {
            if (Input.GetKeyDown(KeyCode.Mouse0))
            {
                gunSoundClone = Instantiate(gunShootSound, this.transform.position, Quaternion.identity) as GameObject;
                anim.piece.transform.position = anim.kickbackState.transform.position;
            }

            if (anim.piece.transform.position != anim.initialPosition.transform.position)
            {
                anim.piece.transform.position = Vector3.Lerp(anim.piece.transform.position, anim.initialPosition.transform.position, anim.speed);
            }
            Destroy(gunSoundClone, 0.5f);
        }
    }
    if (fireType == fireMethod.auto)
    {
        foreach (BlowBack anim in animations)
        {
            if (Input.GetKey(KeyCode.Mouse0) && Time.time - lastFired > 1f/autoFireRate)
            {
                lastFired = Time.time;
                gunSoundClone = Instantiate(gunShootSound, this.transform.position, Quaternion.identity) as GameObject;
                anim.piece.transform.position = anim.kickbackState.transform.position;
            }

            if (anim.piece.transform.position != anim.initialPosition.transform.position)
            {
                anim.piece.transform.position = Vector3.Lerp(anim.piece.transform.position, anim.initialPosition.transform.position, anim.speed);
            }
            Destroy(gunSoundClone, 0.5f);
        }
    }
}
1

There are 1 best solutions below

0
Sisus On

The issue is how you are using Vector3.Lerp. The first two arguments you pass to the method are supposed to be the start and end positions of the animation, and the third one, t, is supposed to be the progress of the animation from the start towards the end, as a value between 0 and 1.

You can calculate the value of t by dividing the time since the shot started with the duration of the animation. For example if the length of the animation is 2 seconds, and the short started 1 second ago, then t should be 0.5.

    if(isFiring)
    {
        float timeSinceShotStart = Time.deltatime - lastFired;
    
        // t = s / v
        float animationDuration = 1f / anim.speed;

        UpdateBlockBackAnimationState(timeSinceShotStart / animationDuration);
    }   
}

private void SetBlowBackAnimationState(float progress01)
{
    foreach(BlowBack anim in animations)
    {
        Vector3 initialPosition = anim.initialPosition.transform.position;
        Vector3 finalPosition = anim.finalPosition.transform.position;
        anim.piece.transform.position = Vector3.Lerp(initialPosition, finalPosition, progress01);
    }
}

I recommend you try to split up your code into smaller methods that are easier to understand. You are trying to do so many things in one generic "GunFireManagement" method that it becomes pretty difficult to keep track of all the different pieces :)

I also recommend considering using a tweening framework such as DOTween to make it easier to animate things over time.