새소식

🎮 Game Dev (게임개발)/PC (데스크탑, 노트북, 터치패널)

[3D 액션게임] 09. 피격 테스터 만들기

  • -

🔔 유튜브 크리에이터 골든메탈님의 유니티강의 3D 쿼터뷰 액션게임 [BE5] 를 보고 공부하여 작성한 게시글입니다! 🔔

 

Enemy 스크립트 전체보기

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    public int maxHealth;
    public int curHealth;

    Rigidbody rigid;
    BoxCollider boxCollider;
    Material mat;

    void Awake()
    {
        rigid = GetComponent<Rigidbody>();
        boxCollider = GetComponent<BoxCollider>();

        // Material은 Mesh Renderer 컴포넌트에서 접근가능합니다.
        mat = GetComponent<MeshRenderer>().material;
    }

    void OnTriggerEnter(Collider other)
    {
        if(other.tag == "Melee"){
            Weapon weapon = other.GetComponent<Weapon>();
            curHealth -= weapon.damage;
            Vector3 reactVec = transform.position - other.transform.position;

            StartCoroutine(OnDamage(reactVec));
        }
        else if(other.tag == "Bullet"){
            Bullet bullet = other.GetComponent<Bullet>();
            curHealth -= bullet.damage;
            Vector3 reactVec = transform.position - other.transform.position;

            Destroy(other.gameObject);

            StartCoroutine(OnDamage(reactVec));
        }
    }

    IEnumerator OnDamage(Vector3 reactVec)
    {
        mat.color = Color.red;
        yield return new WaitForSeconds(0.1f);

        if(curHealth > 0) {
            mat.color = Color.white;
        }
        else {
            mat.color = Color.gray;
            gameObject.layer = 12;

            // 죽었을 시, 넉백
            reactVec = reactVec.normalized;
            reactVec += Vector3.up;
            rigid.AddForce(reactVec * 5, ForceMode.Impulse);

            Destroy(gameObject, 4);
        }
    }
}

 

🧷 1. 테스트 객체 만들기

  • 테스트용 3D 박스 오브젝트를 넣습니다.
  • 물리효과를 받기위한 Rigidbody를 추가 후, X축, Z축에 대한 회전을 동결해 주었습니다(Constraints- Freeze Rotation X, Z 체크)

 

 

🧷 2. Enemy 스크립트 피격 기능 구현

- 적 최대 체력, 현재 체력

/* Enemy script */
public class Enemy : MonoBehaviour
{
    public int maxHealth;
    public int curHealth;

    Rigidbody rigid;
    BoxCollider boxCollider;


    void Awake()
    {
        rigid = GetComponent<Rigidbody>();
        boxCollider = GetComponent<BoxCollider>();
    }

    void OnTriggerEnter(Collider other)
    {
        if(other.tag == "Melee"){
            Weapon weapon = other.GetComponent<Weapon>();
            curHealth -= weapon.damage;
            
        }
        else if(other.tag == "Bullet"){
            Bullet bullet = other.GetComponent<Bullet>();
            curHealth -= bullet.damage;

            Destroy(other.gameObject);
        }
    }
}

 

  • 최대 체력과, 현재 체력 변수를 넣었습니다.
  • OnTriigerEnter 이벤트로 근접무기, 총알(총이 아닙니다!)에 닿을 경우, 데미지를 받게 끔 해줍니다.

 

  • 만든 prefabs 의 총알과, 현재 들고있는 무기의 태그를 확인해 줍시다. 
  • 총알은 Bullet, 망치는 Melee 태그를 가지고 있습니다.

 

- 인스턴트 총알 사라지도록

  • 총알은 Collider에 is Trigger이 켜있고, 중력을 안받기위해 Rigidbody의 Use Gravity 체크를 끄도록 합니다.

 

/* Bullet Script */
public class Bullet : MonoBehaviour
{
    public int damage;

    void OnCollisionEnter(Collision collision)
    {
        if(collision.gameObject.tag == "Floor") {
            Destroy(gameObject, 3);
        }
        
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag == "Wall")
        {
            Destroy(gameObject);
        }
    }
}
  • OnCollistionEnter에 있었떤 벽 피격시 오브젝트 사라지는 코드를 OnTriggerEnter로 바꿔줍시다.

 

Destroy(other.gameObject);
  • Enemy script에서 총알이 적에 맞을 시, 관통 못하게 총알이 사라지는 코드도 꼭 적어줍시다.

 

🧷 3. Enemy 피격 후 이벤트

- 피격 시 색 변화

public class Enemy : MonoBehaviour
{

    Material mat;

    void Awake()
    {
        // Material은 Mesh Renderer 컴포넌트에서 접근가능합니다.
        mat = GetComponent<MeshRenderer>().material;
    }

    void OnTriggerEnter(Collider other)
    {
        if(other.tag == "Melee"){
            Weapon weapon = other.GetComponent<Weapon>();
            curHealth -= weapon.damage;
            
            StartCoroutine(OnDamage(reactVec));
        }
        else if(other.tag == "Bullet"){
            Bullet bullet = other.GetComponent<Bullet>();
            curHealth -= bullet.damage;
            Destroy(other.gameObject);

            StartCoroutine(OnDamage(reactVec));
        }
    }

    IEnumerator OnDamage()
    {
        mat.color = Color.red;
        yield return new WaitForSeconds(0.1f);

        if(curHealth > 0) {
            mat.color = Color.white;
        }
        else {
            mat.color = Color.gray;
            Destroy(gameObject, 4);
        }
    }
}
  • 오브젝트의 Material을 통해 적 피격 시 빨간색으로 만들 것 입니다.
  • 안죽으면 원래색으로 돌아오고, 죽으면 그레이 색이 됩니다.
  • Material은 Mesh Renderer 컴포넌트를 통해 접근해야합니다.
  • 색 변화는 코루틴을 통해 넣어줍니다.

 

- 적 죽은 상태

  • 유니티를 통해 새로운 Layer을 만들어 둔 뒤, 적은 Enemy 레이어로, 죽은 상태는 번호를 잘 기억해 놓읍시다. (저는 12번이 죽은 상태 레이어입니다.)
    IEnumerator OnDamage(Vector3 reactVec)
    {
        mat.color = Color.red;
        yield return new WaitForSeconds(0.1f);

        if(curHealth > 0) {
            mat.color = Color.white;
        }
        else {
            mat.color = Color.gray;
            gameObject.layer = 12;
        }
    }
  • 코루틴에서 죽을 시 gameObject.layer = 12; 즉 죽은 상태 레이어로 바꿔줍시다.

 

  • 유니티의 Edit - Project Settings - Physics의 Layer Collision Martix를 들어갑니다
  • EnemyDead에 관한 레이어가 Floor, Wall, EnemyDead 빼고 다 닿지 않게 만들어줍시다.

 

- 적 죽을 때, 살짝 밀려나는 이벤트

/* Enemy script, 추가되는 부분만 작성하였습니다. */
public class Enemy : MonoBehaviour
{
    void OnTriggerEnter(Collider other)
    {
        if(other.tag == "Melee"){
            Vector3 reactVec = transform.position - other.transform.position;

            StartCoroutine(OnDamage(reactVec));
        }
        else if(other.tag == "Bullet"){
            Vector3 reactVec = transform.position - other.transform.position;

            StartCoroutine(OnDamage(reactVec));
        }
    }

    IEnumerator OnDamage(Vector3 reactVec)
    {
        if(curHealth > 0) {
        }
        else {
            // 죽었을 시, 넉백
            reactVec = reactVec.normalized;
            reactVec += Vector3.up;
            rigid.AddForce(reactVec * 5, ForceMode.Impulse);
        }
    }
}
  • 적이 데미지를 받는 코루틴 OnDamage() 함수를 실행할 때 Vector3값도 매개변수로 전달해줬습니다.
  • 이 reactVec 값은 적과 무기의 사이의 거리벡터입니다.
  • 적이 죽었을 시 Normalized된 reactVec 값에, 약간 UP값을 주며, AddForce 해 주었습니다. (normalized 함수는, 길이를 1로 변환해줍니다.)

 

이번 시간에는 적이 피격 될 시  Enemy 스크립트를 배웠는데,

trigger 이벤트함수 뿐만아니라, 태그나 레이어를 잘 활용 해야된다고 느꼈습니다.

 

이 강의에서 더 추가해보고 싶은 기능은, 무기 데미지에 따라서 적이 안죽더라도 넉백이 되는 기능을 추가할까 합니다.

 

 

출처: 골든메탈님 유튜브

https://www.youtube.com/watch?v=IoaPxcSHwEM&list=PLO-mt5Iu5TeYkrBzWKuTCl6IUm_bA6BKy&index=9 

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.