인생유니티/FPS게임

무기 모드 추가및 효과 적용

유니티런 2025. 4. 24. 23:01

발사를 담당하는 PlayerFire.cs를 열어 무기 모드 변수를 추가합니다.

public class PlayerFire : MonoBehaviour
{
	enum WeaponMode
    {
        Normal, Sniper
    }
    WeaponMode wMode;

    void Start()
    {
생략
        wMode = WeaponMode.Normal;
    }

스나이퍼 모드에서 우클릭을 하면 화면을 확대 다시클릭하면 축소를 위한 ZoomMode 변수를 추가하고

우클릭시 수류탄을 발사했던 코드를 무기 모드에 따라 동작이 다르게 실행되도록 switch 문을 추가합니다. 

bool ZoomMode = false;  //전역변수
void Update()
{
//생략
    // 마우스 오른쪽 버튼 입력을 받는다.
    if (Input.GetMouseButtonDown(1))
    {
        switch(wMode)
        {
            case WeaponMode.Normal:
                // 수류탄 오브젝트를 생성하고, 수류탄의 생성 위치를 발사 위치로 한다.
                GameObject bomb = Instantiate(bombFactory);
                bomb.transform.position = firePosition.transform.position;

                // 수류탄 오브젝트의 Rigidbody 컴포넌트를 가져온다.
                Rigidbody rb = bomb.GetComponent<Rigidbody>();

                // 카메라의 정면 방향으로 수류탄에 물리적인 힘을 가한다.
                rb.AddForce(Camera.main.transform.forward * throwPower, ForceMode.Impulse);
                break;
            case WeaponMode.Sniper:
                break;
        }
    }

이제 스나이퍼모드에서 화면의 확대축소를 카메라의 FOV시야각을 이용해 조절합니다. 위 case WeaponMode.Sniper에 코드를 추가합니다.

case WeaponMode.Sniper:
    if(!ZoomMode)
    {
        Camera.main.fieldOfView = 15f;
        ZoomMode = true;
    }
    else
    {
        Camera.main.fieldOfView = 50f;
        ZoomMode = false ;
    }
    break;

Update() 함수 아래부분에 숫자키 1이 눌리면 Normal 아니면 Sniper모드로 되게 해줍니다.

if (Input.GetKeyDown(KeyCode.Alpha1))
{
    wMode = WeaponMode.Normal;
    Camera.main.fieldOfView = 60f;
} else if(Input.GetKeyDown(KeyCode.Alpha2))
{
    wMode = WeaponMode.Sniper;
}

모드에 따라서 UI를 표시하게 해주겠습니다. 좌측하단 Slide옆에 위치하게 하고

폰트크기를 20 Bold로 합니다.

PlayerFire.cs에서 Text를 처리해주고

using UnityEngine.UI;

public class PlayerFire : MonoBehaviour
{
    public Text wModeText;
    void Start()
    {
생략
        wMode = WeaponMode.Normal;
    }

    void Update()
    {
    생략
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
생략
            wModeText.text = "Normal Mode";
        } else if(Input.GetKeyDown(KeyCode.Alpha2))
        {
생략
            wModeText.text = "SniperMode";
        }

저장후 Text_WeaponMode를 UI에서 끌어다 연결해줍니다.

 

무기효과적응

총을 쏠때 총구에서 불꽃이 튀는 효과를 주고 싶다. Asset Store에서 Easy FPS 에셋을 다운로드 임포트 합니다.

아래 폴더에 5개의 이펙트가 있습니다.

이 다섯개 프리팹을 하이라키로 끌어다 놓고 전부 선택해서 스크립트를 한꺼번에 리무브해줍니다.

MuzzlePosition 빈오브젝트를 만들어 위 효과를 자식으로 만듭니다.

Player자식인 Soldier_demo> Spline아래 손가락인 Bip001 R Finger0 Numb아래 MuzzlePoint를 끌어다 놓습니다. MuzzlePosition과 효과들의 위치는 Reset해줘야 손가락 끝으로 모입니다.

화면이 손가락 끝에 있기때문에 총구로 옮기기 위해 플레이후 포즈한후 Local모드에서 회전 이동시켜 총구로 맞춰줍니다.

정지하기 전 transform 컴포넌트를 카피합니다. 오른쪽 삼점을 누르면 됩니다.

교재에서는 맞추준후 효과들을 Muzzle Position으로 등록후 위치를 초기화 해주네요. 플레이를 정지시키고 Muzzle Position 오브젝트의 Transform 컴포넌트를 Paste해줍니다.  이펙트가 너무 크므로 0.4로 줄여줍니다

총을 쏠때 마다 5개의 이펙트를 랜던하게 골라서 표시해보겠습니다. 효과가 5개이므로 배열을 이용하겠습니다.

사격에 관련된 PlayerFire.cs 스크립트에 public GameObject[] eff_Flash;를 추가합니다.

public class PlayerFire : MonoBehaviour
{
    public GameObject[] eff_Flash;
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
        생략
             StartCoroutine(ShootEffectOn(0.05f));
        }
    }
    IEnumerator ShootEffectOn(float duration)
    {
        int num = Random.Range(0,eff_Flash.Length);
        eff_Flash[num].SetActive(true);
        yield return new WaitForSeconds(duration);
        eff_Flash[num].SetActive(false);
    }

 하이라키의 효과는 전부 꺼줍니다.

Player>PlayerFire>Eff_Flash어레이에 머즐효과5개를 끌어다 놓습니다. 락을 걸어놓고 하면 편합니다.

플레이 해서 발사해보면 총구에서 효과가 나옵니다.

 

수류탄 모델링 교체및 폭발 데미지

Asset Store에서 Grenade를 Free로 찾아 Grenade DM51A1 을 다운 받습니다.

찾아 보니 없엇 용량이 작은걸 찾아 다운 받았습니다.

FBX를 끌어다 Bomb Prefab의 자식으로 합니다.

스피어가 안보이도록 Mesh Renderer를 끄고 Sphere collider의 센터와 Radious를 조정해주고

Grenader의 Transform을 리셋후 Scale를 2배로 해줍니다.

 

변경된 프리팹을 적용시키기 위해 오버라이드 항목을 선택 Apply All을 하라는데 Unity6에서는 그런 메뉴가 없네요

실험 삼아 Bomb을 Player앞에 놔봤씁니다. 사이즈가 적당한것 같네요. 확인후 지워줍니다.

게임을 플레이해 노멀모드에서 마우스 우클릭으로 수류탄을 던져보겟습니다. 모델링과 폭발효과를 확인합니다.

이제는 수류탄의 폭발 반경안에 들어온 에너미에 데미지를 주는 기능을 구현해 보겠습니다.

BombAction.cs에 코드를 구현합니다.

Physics.OverlapSphere()함수를 이용 반경내 오브젝트를 찾는데 1<<10 레이어를 사용해서 적만 찾습니다.

cols배열에 찾은 적이 있으므로 순환문을 이용해 각각 HitEnemy()함수를 실행합니다.

public class BombAction : MonoBehaviour
{
생략
    public float explosionRadius = 5f;
    // 충돌했을 때의 처리
    private void OnCollisionEnter(Collision collision)
    {
        Collider[] cols = Physics.OverlapSphere(transform.position, explosionRadius, 1<<10);
        for(int i=0; i<cols.Length; i++)
        {
            cols[i].GetComponent<EnemyFSM>().HitEnemy(attackPower);
        }

 

1<<10을 사용하는 이유는 Enemy의 레이어 번호가 10이기 때문입니다.

적을 여러명 만들기 위해 Enemy를 Prefab폴더로 끌어다 놓고 Prefab으로 만듭니다. 다시 프로팹을 몇개 배치하고 플레이해서 수류탄을 던져보겠습니다.

적들이 동시에 피해를 입어야 합니다.

적을 프리팹으로 만들었더니 HPBar UI billboard Script에서 Camera를 바라봤던 부분이 문제가 되는군요 Prefab에서는 하이라키의 게임오브젝트를 참조하지 못하는것 같습니다. 따라서 Billboard.cs에서 Start() 함수에서 Camera의 참조를 코드로 수행했습니다.

public class Billboard : MonoBehaviour
{
    public Transform target;
    private void Start()
    {
        target = Camera.main.transform;
    }