인생유니티/FPS게임

FPS Game 제작 - 프로토 - 무기 제작

유니티런 2025. 4. 21. 19:41

수류탄 제작

구체를 추가하고 Bomb으로 변경합니다. Radius를 0.5로 합니다.

이번에는 중력을 직접 구현하지 않고 리지드보디 컴포넌트를 이용해 적용합니다. AddComponent > Rigidbody를 추가합니다.

다른 물체와 충돌시 수류탄이 사라지게 BomAction이라는 스크립트를 생성 추가합니다.

유니티는 OnCollisionEnter()함수에서 충돌을 감지합니다. bombEffect 변수를 만들어 Instaiate로 만들어서 현재 bomb의 위치에서 터트려 줍고 폭탄은 Destroy해줍니다. bombEffect는 Assets Store에서 FX Explosion Pack을 다운>import> 받아 적용시킵니다. 폭발 속도를 빠르게 하기 위해 Simulation Speed를 2배로 변경합니다.

Physics를 이용할예정이므로 Rigidbody, Collider를 추가합니다.

using UnityEngine;

public class BombAction : MonoBehaviour
{
    public GameObject bombEffect;
    // Start is called once before the first execution of Update after the MonoBehaviour is created
    private void OnCollisionEnter(Collision collision)
    {
        GameObject eff = Instantiate(bombEffect);
        eff.transform.position = transform.position;
        Destroy(gameObject);
    }
}

폭탄이 땅바닥에 떨어진후 폭발 효과가 없어지지 않으면 다음 DestroyEffect.cs 스크립트를  만들어 효과 프리팹에 넣어줍니다.

using UnityEngine;

public class DestroyEffect : MonoBehaviour
{
    public float destroyTime = 1.5f;
    float currentTime = 0;

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (currentTime > destroyTime)
        {
            Destroy(gameObject);
        }
        currentTime += Time.deltaTime;
    }
}

수류탄이 플레이어와 충돌하면 안되므로 Player, Bomb  레이어를 만들어 Project Settings Physics에서 Collision Matrix에서 Player-Bomb를 체크해제 합니다.

Bomb을 Prefab폴더를 만들고 끌어다 놔 프리팹화 합니다. 하이라키의 Bomb은 지워줍니다.

 

수류탄을 던지기 위해 PlayerFire 스크립을 만들고 Player 게임오브젝트에 컴포넌트로 끌어다 놓습니다.

좌클릭을 하면 Ray()를 쏴서 화염 이펙트를 발생시키고, 우클릭을 하면 Instantiate()로 Bomb을 발생시켜  firePosition에 위치시키고 rb.addForce()로 힘을 추가해 앞으로 나아가게 합니다.(물리적인 힘을 이용)

 

Input.GetMouseButtonDown(n)  좌클릭 n=0, 우클릭 n=1, 가운데클릭 n=2 입니다.

using UnityEngine;

public class PlayerFire : MonoBehaviour
{
    public GameObject firePosition;
    public GameObject bombFactory;
    public GameObject bulletEffect;
    public int weaponPower = 5;
    ParticleSystem ps;
    public float throwPower = 15f;
    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        ps = bulletEffect.GetComponent<ParticleSystem>();
    }

    // Update is called once per frame
    void Update()
    {
        if (GameManager.gm.gState != GameManager.GameState.Run)
        {
            return;
        }
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward);
            RaycastHit hitInfo = new RaycastHit();
            if (Physics.Raycast(ray, out hitInfo))
            {
                if (hitInfo.transform.gameObject.layer == LayerMask.NameToLayer("Enemy"))
                {
                    EnemyFSM eFSM = hitInfo.transform.gameObject.GetComponent<EnemyFSM>();
                    eFSM.HitEnemy(weaponPower);
                }
                else
                {
                    bulletEffect.transform.position = hitInfo.point;
                    bulletEffect.transform.forward = hitInfo.normal;
                    ps.Play();
                }
            }
        }
        if(Input.GetMouseButtonDown(1))
        {
            GameObject bomb = Instantiate(bombFactory);
            bomb.transform.position = firePosition.transform.position;
            Rigidbody rb = bomb.GetComponent<Rigidbody>();
            rb.AddForce(Camera.main.transform.forward * throwPower, ForceMode.Impulse);
        }
    }
}

firePosition 빈오브젝트를 만들고 Player 눈 앞정도에 배치하고 스크립트 컴포넌트의 Fire Position변수에 끌어다 놓습니다. 기타 다른 변수들도 연결해 줍니다. Bomb이 터지는 효과도 적당히 연결합니다. Ray()가 충돌시 발생하는 BulletEffect도 연결합니다. particleSystem은 play()해줘서 발생 시킵니다.

좌클릭을 하면 Physics.Raycast()를 이용해 광선을 발사합니다. 인자로 ray와 hitinfo를 넣는데 ray는 타겟을 향하는 광선이고 hitinfo 구조체에는 충돌 정보가 들어 있습니다. 

hitInfo.normal을 사용하면 충돌한 표면의 법선방향을 얻을수 있어 충돌체가 반사하는 듯한 효과를 줄수 있습니다.

bulletEffect.transform.position = hitInfo.point;
bulletEffect.transform.forward = hitInfo.normal;
ps.Play();