Relaoding while aiming problem

Hello all! I cant figure out how to set when Im reloading to my hands and gun go back to normal not aim position and reload there and when its done with reloading to come back to aiming? Someone can help? Thanks in advance! :slight_smile:
How ti looks(1st picture):

This is how i want to trasnform to normal no aim position to reload there (2nd picture)

Here is the code:
using System.Collections;
using UnityEngine;
using UnityEngine.UI;

public class Weapon : MonoBehaviour
{
[Header(“Gun Settings”)]
public float fireRate = 0.1f;
public int clipSize = 30;
public int reservedAmmoCapacity = 270;

public float damage = 10f;
public float range = 100;
public float impactForce = 30f;



public Camera fpsCam;
public ParticleSystem muzzleFlash;
public GameObject impactEffect;
public GameObject Crosshair;




//Variable that change throughout code
bool _canShoot;
int _currentAmmoInClip;
int _ammoInReserve;

//Aiming
public Vector3 normalLocalPosition;
public Vector3 aimingLocalPosition;

public float aimSmoothing = 10;

//Weapon Recoil

public bool randomizeRecoil;
public Vector2 randomRecoilConstraints;

public Vector2 recoilPattern;

[Header("Mouse settins")]
public float mouseSensitivity = 1;
Vector2 _currentRotation;

private void Start()
{
    _currentAmmoInClip = clipSize;
    _ammoInReserve = reservedAmmoCapacity;
    _canShoot = true;
}

private void Update()
{
    DetermineAim();
    if (Input.GetMouseButton(0) && _canShoot && _currentAmmoInClip > 0)
    {
        _canShoot = false;
        _currentAmmoInClip--;
        StartCoroutine(ShootGun());
    }

    else if (Input.GetKeyDown(KeyCode.R) && _currentAmmoInClip < clipSize && _ammoInReserve > 0)
    {
        int amountNeeded = clipSize - _currentAmmoInClip;

        if (amountNeeded >= _ammoInReserve)
        {
            _currentAmmoInClip += _ammoInReserve;
            _ammoInReserve -= amountNeeded;
        }
        
        else
        {
            _currentAmmoInClip = clipSize;
            _ammoInReserve -= amountNeeded;

        }


    }

    //When click "reload button" disable shooting and then set back to can shoot after x seconds
    bool reloading = (Input.GetKeyDown(KeyCode.R));

    if (reloading)
    {
        _canShoot = false;
        StartCoroutine(StopShooting());
    }

    IEnumerator StopShooting()
    {
        yield return new WaitForSeconds(1.4f);
        _canShoot = true;

    }

}



void DetermineRecoil()
{
    transform.localPosition -= Vector3.forward * 0.1f;

    if (randomizeRecoil)
    {
        float xRecoil = Random.Range(-randomRecoilConstraints.x, randomRecoilConstraints.x);
        float yRecoil = Random.Range(-randomRecoilConstraints.y, randomRecoilConstraints.y);

        Vector2 recoil = new Vector2(xRecoil, yRecoil);

        
    }

    else
    {
        int currentStep = clipSize + 1 - _currentAmmoInClip;
        

        
    }
}



void DetermineAim()
{
    bool Aiming = (Input.GetKey(KeyCode.Mouse1));
    Vector3 target = normalLocalPosition;
    if (Input.GetMouseButton(1)) target = aimingLocalPosition;

    Vector3 desiredPosition = Vector3.Lerp(transform.localPosition, target, Time.deltaTime * aimSmoothing);

    transform.localPosition = desiredPosition;

    if(Aiming)
    {
        Crosshair.SetActive(false);
    }
    
}



IEnumerator ShootGun()
{
    DetermineRecoil();
    yield return new WaitForSeconds(fireRate);
    _canShoot = true;

    muzzleFlash.Play();

    RaycastHit hit;
    if (Physics.Raycast(fpsCam.transform.position, fpsCam.transform.forward, out hit, range))
    {

        Enemy enemy = hit.transform.GetComponent<Enemy>();
        if (enemy != null)
        {
            enemy.TakeDamage(damage);
        }

        if (hit.rigidbody != null)
        {
            hit.rigidbody.AddForce(-hit.normal * impactForce);
        }

        GameObject impactGO = Instantiate(impactEffect, hit.point, Quaternion.LookRotation(hit.normal));
        Destroy(impactGO, 2f);

    }

}

}

I understand you like Coroutines, but for this case I would do the following - The idea is, you split your possible gun actions into states (shooting, aiming, reloading, etc.) Each state has an exit condition (reloading would have a timer/or end of an animation, while aiming would transit to shooting when player presses a button). Here is an example with 3 states, but you can expand on this very easily:

enum GunState
    {
        Null,
        Aiming,
        Shooting,
        Reloading,
    }

    float actionTimer;
   

    float shoot_time = .5f;
    float reload_time = 2f;

    GunState _state;
    GunState State { get => _state;
        set
        {
            if (_state != value)
            {
                _state = value;
                OnStateChanged();
            }
        }
    }

    void OnStateChanged()
    {
        Debug.Log("State changed to: "+State );

        //Here we do anything that happens at the moment we change states
        switch (_state)
        {
            case GunState.Aiming:
                //Here we activate our aim
                break;
            case GunState.Shooting:
                //We shoot our ray and check if target hit
                actionTimer = shoot_time;
                break;
            case GunState.Reloading:
                //Here you start playing the reload animation
                //You can add more states if needed, like for example: GunState.StartingToReload
                //In this state, we would lerp the player's camera to the target position, then we would go to GunState.Reloading. Possibilities are endless!
                actionTimer = reload_time;
                break;
        }
    }


    private void Update()
    {
        switch (State)
        {
            case GunState.Aiming:
                //Everything you have in your aim code goes here, player has control. When he shoots we call Shoot()
                break;

            case GunState.Shooting:
                //Here we can wait, or have an animation
                //The animation can also be made to make us go to next state
                actionTimer -= Time.deltaTime;
                if (actionTimer <= 0)
                {
                    State = GunState.Reloading;
                }
                break;
            case GunState.Reloading:
                {
                    //Same comment as for shooting
                    actionTimer -= Time.deltaTime;
                    if (actionTimer <= 0)
                    {
                        State = GunState.Aiming;
                    }
                }
                break;
        }
    }

I tried to make it as barebone as possible for simplicity, but you can add more states if you want more intricate actions:

    enum GunState
     {
         Null,

         MovingToAimPosition,
         Aiming,
         Shooting,
         FailingToShoot,
         MovingToReloadPosition,
         Reloading,
     }

This solution avoids the complexity of keeping track of Coroutines, as you always know what state you are in, and what made the call to change states!

Hello. I tried with your script and now it looks like this:
But now I cant even aim and my gun does not play animation as I made script to do, to go forward-backward when press left mouse button
Can you help?
Im sry if I made some stupid mistakes, im still at learning :smiley:

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

public class Weapon20 : MonoBehaviour
{

[Header("Gun Settings")]
public float fireRate = 0.1f;
public int clipSize = 30;
public int reservedAmmoCapacity = 270;

public float damage = 10f;
public float range = 100;
public float impactForce = 30f;

public Camera fpsCam;
public ParticleSystem muzzleFlash;
public GameObject impactEffect;
public GameObject Crosshair;

//Variable that change throughout code
bool _canShoot;
int _currentAmmoInClip;
int _ammoInReserve;

//Aiming
public Vector3 normalLocalPosition;
public Vector3 aimingLocalPosition;

public float aimSmoothing = 10;

//Weapon Recoil

public bool randomizeRecoil;
public Vector2 randomRecoilConstraints;

public Vector2 recoilPattern;

[Header("Mouse settins")]
public float mouseSensitivity = 1;
Vector2 _currentRotation;

enum GunState
{
    Null,
    Aiming,
    Shooting,
    Reloading,
}

float actionTimer;

float shoot_time = .5f;
float reload_time = 2f;

GunState _state;
GunState State
{
    get => _state;
    set
    {
        if (_state != value)
        {
            _state = value;
            OnStateChanged();
        }
    }
}

void OnStateChanged()
{
    Debug.Log("State changed to: " + State);

    //Here we do anything that happens at the moment we change states
    switch (_state)
    {
        case GunState.Aiming:
            //Here we activate our aim
            break;
        case GunState.Shooting:
            //We shoot our ray and check if target hit
            actionTimer = shoot_time;
            break;
        case GunState.Reloading:
            //Here you start playing the reload animation
            //You can add more states if needed, like for example: GunState.StartingToReload
            //In this state, we would lerp the player's camera to the target position, then we would go to GunState.Reloading. Possibilities are endless!
            actionTimer = reload_time;
            break;
    }
}

private void Start()
{
    _currentAmmoInClip = clipSize;
    _ammoInReserve = reservedAmmoCapacity;
    _canShoot = true;
}

private void Update()
{
    switch (State)
    {
        case GunState.Aiming:
            //Everything you have in your aim code goes here, player has control. When he shoots we call Shoot()
            if (Input.GetMouseButton(0) && _canShoot && _currentAmmoInClip > 0)
            {
                _canShoot = false;
                _currentAmmoInClip--;
                
            }

            else if (Input.GetKeyDown(KeyCode.R) && _currentAmmoInClip < clipSize && _ammoInReserve > 0)
            {
                int amountNeeded = clipSize - _currentAmmoInClip;

                if (amountNeeded >= _ammoInReserve)
                {
                    _currentAmmoInClip += _ammoInReserve;
                    _ammoInReserve -= amountNeeded;
                }

                else
                {
                    _currentAmmoInClip = clipSize;
                    _ammoInReserve -= amountNeeded;

                }

            }
            bool Aiming = (Input.GetKey(KeyCode.Mouse1));
            Vector3 target = normalLocalPosition;
            if (Input.GetMouseButton(1)) target = aimingLocalPosition;

            Vector3 desiredPosition = Vector3.Lerp(transform.localPosition, target, Time.deltaTime * aimSmoothing);

            transform.localPosition = desiredPosition;

            if (Aiming)
            {
                Crosshair.SetActive(false);
            }
            break;

        case GunState.Shooting:
            //Here we can wait, or have an animation
            //The animation can also be made to make us go to next state
            
            _canShoot = true;

            muzzleFlash.Play();

            transform.localPosition -= Vector3.forward * 0.1f;

            if (randomizeRecoil)
            {
                float xRecoil = Random.Range(-randomRecoilConstraints.x, randomRecoilConstraints.x);
                float yRecoil = Random.Range(-randomRecoilConstraints.y, randomRecoilConstraints.y);

                Vector2 recoil = new Vector2(xRecoil, yRecoil);

            }

            else
            {
                int currentStep = clipSize + 1 - _currentAmmoInClip;

            }

            RaycastHit hit;
            if (Physics.Raycast(fpsCam.transform.position, fpsCam.transform.forward, out hit, range))
            {

                Enemy enemy = hit.transform.GetComponent<Enemy>();
                if (enemy != null)
                {
                    enemy.TakeDamage(damage);
                }

                if (hit.rigidbody != null)
                {
                    hit.rigidbody.AddForce(-hit.normal * impactForce);
                }

                GameObject impactGO = Instantiate(impactEffect, hit.point, Quaternion.LookRotation(hit.normal));
                Destroy(impactGO, 2f);

            }
            actionTimer -= Time.deltaTime;
            if (actionTimer <= 0)
            {
                State = GunState.Reloading;
            }
            break;

        case GunState.Reloading:
            {
                //Same comment as for shooting
                actionTimer -= Time.deltaTime;
                if (actionTimer <= 0)
                {
                    State = GunState.Aiming;
                }
            }
            break;
    }
}

}