상세 컨텐츠

본문 제목

유니티 플레이어 무기 교체(키입력, 마우스휠), 오류 해결

유니티/기능

by MJ_119 2024. 9. 14. 00:21

본문

- 플레이어 무기 교체

 

@ 에러 : 무기 교체를 빠르게 하면서(1,2,3 빠르게 왔다갔다 교체) 총을 발사하면 총알이 안나가는 상태가 발생.

 

@ 해결 : 

무기 교체 중 Shoot 코루틴의 상태 유지: 무기 교체 중에도 코루틴이 진행 중이라면 무기가 바뀌어도 발사 시도가 계속됩니다. 현재 코드에서 Shoot()이 한 번 실행되면 무기 교체 후에도 계속 진행될 수 있습니다. 이를 방지하려면, 무기를 교체할 때 canShoot 상태를 초기화해야 합니다.

        // 무기 교체 시 사격 가능 상태 초기화
        GetComponentInChildren<RayCast>().canShoot = true;

 

 다른 해결 방법 :

- RayCast(총 쏘는 스크립트)에 스크립트가 활성화 될때 기본 상태가 true로 변경되도록 한다.

- 원인은 총을 쏘고 재장전(코루틴)중에 스크립트가 비활성화 되면서 canShoot = false; 된 상태로 계속 유지되고 다시 스크립트가 활성화(Enable) 됐을 때에도 false로 유지되고 있기 때문.

    private void OnEnable()
    {
        canShoot = true;
    }

 

 

 

 

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

public class WeaponSwitch : MonoBehaviour
{
    [SerializeField] int currentWeapon = 0;

    void Start()
    {
        SetActiveWeapon();
    }

    void Update()
    {
        // 이전 무기와 현재 무기가 같은 값을 가진다는 뜻.
        int previousWeapon = currentWeapon;

        // 키 입력을 받아 currentWeapon을 바꿈
        ProcessKeyInput();

        if ( previousWeapon != currentWeapon )
        {
            //무기 교체
            SetActiveWeapon();
        }
    }

    private void SetActiveWeapon()
    {
        int weaponIndex = 0;

        foreach (Transform weapon in transform)
        {
            if (weaponIndex == currentWeapon)
            {
                weapon.gameObject.SetActive(true);
            }
            else
            {
                weapon.gameObject.SetActive(false);
            }
            weaponIndex++;
        }
        
        // 무기 교체 시 사격 가능 상태 초기화
        GetComponentInChildren<RayCast>().canShoot = true;
    }

    private void ProcessKeyInput()
    {
        if (Input.GetKey(KeyCode.Alpha1))
        {
            currentWeapon = 0;
        }
        if (Input.GetKey(KeyCode.Alpha2))
        {
            currentWeapon = 1;
        }
        if (Input.GetKey(KeyCode.Alpha3))
        {
            currentWeapon = 2;
        }
    }
}

 

 

- 총 발사 코드

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

public class RayCast : MonoBehaviour
{
    [SerializeField] Camera mainCam;
    [SerializeField] float range = 100f;
    [SerializeField] float gunDamage = 30f;
    [SerializeField] ParticleSystem gunFlash;
    [SerializeField] GameObject gunTargetHit;
    [SerializeField] Ammo ammo; // 플레이어가 가지고있는 총알 확인
    [SerializeField] float weaponDelayTime;

    public bool canShoot = true;

    void Update()
    {
        if(Input.GetMouseButtonDown(0) && canShoot == true)
        {
            if (ammo.GetCurrentAmmo() > 0)
            {
                
                StartCoroutine(Shoot());
                
            }
        }
    }

    void GunTargetHit(RaycastHit raycastHit)
    {
        // 총 맞은 부위에 이펙트 생성
        //GameObject hitEffect = Instantiate(gunTargetHit, raycastHit.transform);
        GameObject hitEffect = Instantiate(gunTargetHit, raycastHit.point, Quaternion.LookRotation(raycastHit.normal));

        // 1초뒤 파티클 삭제
        Destroy(hitEffect, 1f);
    }

    void GunFlash()
    {
        gunFlash.Play();
    }

    IEnumerator Shoot()
    {
        canShoot = false;

        GunFlash();
        ProcessRayCast();
        ammo.ReduceCurrentAmmo();

        yield return new WaitForSeconds(weaponDelayTime);

        canShoot = true;
    }

    private void ProcessRayCast()
    {
        RaycastHit hit;
        if (Physics.Raycast(mainCam.transform.position, mainCam.transform.forward, out hit, range))
        {
            print(" hit : " + hit.transform.name);

            // 총 맞은 곳에 파티클 생성
            GunTargetHit(hit);

            //Raycast로 충돌한 오브젝트에서 EnemyHealth라는 컴포넌트를 찾아서, 그 컴포넌트를 가져옴.
            EnemyHealth target = hit.transform.GetComponent<EnemyHealth>();

            if (target == null)
            {
                return;
            }

            target.TakeDamage(gunDamage);
            print(target.Hp);
        }
    }
}

 

 

 

- 마우스 휠로 무기 교체하기

 - 캐릭터가 죽어서 게임오버 상태에서도 무기 변경이 가능하니 Player_Death 스크립트를 수정해준다.

 - 캐릭터가 죽으면 WeaponSwitch 스크립트를 찾아서 비활성화 시킨다.

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

public class WeaponSwitch : MonoBehaviour
{
    [SerializeField] int currentWeapon = 0;

    void Start()
    {
        SetActiveWeapon();
    }

    void Update()
    {
        // 이전 무기와 현재 무기가 같은 값을 가진다는 뜻.
        int previousWeapon = currentWeapon;

        // 키 입력을 받아 currentWeapon을 바꿈
        ProcessKeyInput();

        // 마우스휠 입력을 받아 currentWeapon을 바꿈
        ProcessMouseWheel();

        if ( previousWeapon != currentWeapon )
        {
            //무기 교체
            SetActiveWeapon();
        }
    }

    private void ProcessMouseWheel()
    {
        if (Input.GetAxis("Mouse ScrollWheel") > 0)
        {
            if (currentWeapon >= transform.childCount - 1)
            {
                currentWeapon = 0;
            }
            else
            {
                currentWeapon++;
            }
        }
        if (Input.GetAxis("Mouse ScrollWheel") < 0)
        {
            if (currentWeapon <= 0)
            {
                currentWeapon = transform.childCount - 1;
            }
            else
            {
                currentWeapon--;
            }
        }
    }

    private void SetActiveWeapon()
    {
        int weaponIndex = 0;

        foreach (Transform weapon in transform)
        {
            if (weaponIndex == currentWeapon)
            {
                weapon.gameObject.SetActive(true);
            }
            else
            {
                weapon.gameObject.SetActive(false);
            }
            weaponIndex++;

        }

        // 무기 교체 시 사격 가능 상태 초기화
        GetComponentInChildren<RayCast>().canShoot = true;
    }

    private void ProcessKeyInput()
    {
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            currentWeapon = 0;
        }
        if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            currentWeapon = 1;
        }
        if (Input.GetKeyDown(KeyCode.Alpha3))
        {
            currentWeapon = 2;
        }
    }
}

 

 

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

public class Player_Death : MonoBehaviour
{
    [SerializeField] Canvas death_UI_Canvas;

    void Start()
    {
        death_UI_Canvas.enabled = false;
    }

    public void DeathState()
    {
        death_UI_Canvas.enabled = true;
        Time.timeScale = 0;
        FindObjectOfType<WeaponSwitch>().enabled = false;
        Cursor.lockState = CursorLockMode.None;
        Cursor.visible = true;
    }
}

관련글 더보기