새소식

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

[3D 액션게임] 12. 다양한 몬스터 만들기

  • -

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

🧷 1. 플레이어 피격 판정

- 플레이어 공격 받는 기능

/* Player script , 추가되는 부분만 넣었습니다. */

public class Player : MonoBehaviour
{
	bool isDamage;
	MeshRenderer[] meshs;

	void Awake()
    {
        meshs = GetComponentsInChildren<MeshRenderer>();
    }
    
    private void OnTriggerEnter(Collider other)
    {
        if(other.tag == "Item") { }
        
        else if (other.tag == "EnemyBullet") {
            if (!isDamage) {
                Bullet enemyBullet = other.GetComponent<Bullet>();
                health -= enemyBullet.damage;
                StartCoroutine(OnDamage());
            }
        }
    }
    
    IEnumerator OnDamage() 
    {
        isDamage = true;
        foreach(MeshRenderer mesh in meshs) {
            mesh.material.color = Color.yellow;
        }

        yield return new WaitForSeconds(1f);

        isDamage = false;
        foreach (MeshRenderer mesh in meshs)
        {
            mesh.material.color = Color.white;
        }
    }
}
  • isDamage라는 변수를 통해 공격 당할시 무적 시간을 줍니다.
  • MeshRenderer[]을 가져와 플레이어아래 메쉬들을 모두 가져옵니다
  • 공격 받을 시 OnDamage() 함수가 코루틴으로 실행되고, 1초동안 노란색으로 무적이 지속된후, 다시 해제 됩니다.
  • 공격 받을 시, bullet 데미지에 따라 플레이어 체력이 깎입니다.

 

🧷 2. 몬스터 이동보정

/* Enemy script , 추가되는 부분만 넣었습니다. */
public class Enemy : MonoBehaviour
{
    void Update()
    {
        if (nav.enabled) {
            nav.SetDestination(Target.position);
            nav.isStopped = !isChase;
        }   
    }
}
  • navigate가 켜져 있을때, 타겟의 경로를 수정해주도록 이동보정을 해주었습니다.

 

🧷 3. 일반형 몬스터

일반용 몬스터는 기본 몬스터로,  가까이 가면 근접공격을 합니다.

 

- 몬스터 피격용 범위 만들기

  • EnemyBullet이라는 비어있는 오브젝트에, Box Collider와 Bullet 스크립트를 넣어주었습니다.
  • Box Collider은 위와 같은 몬스터의 앞쪽 큐브형태로 만들었습니다. (적 공격 범위)

 

- 몬스터 공격 기능 만들기

/* Enemy script , 추가되는 부분만 넣었습니다. */
public class Enemy : MonoBehaviour
{
    public enum Type { A, B, C };
    public Type enemyType;
    public BoxCollider melleArea;

    public bool isAttack;



	void Targeting()
    {
        float targetRadius = 0;
        float targetRange = 0;

        switch (enemyType) {
            case Type.A:
                targetRadius = 1.5f;
                targetRange = 3f;
                break;

            case Type.B:
                break;

            case Type.C:
                break;
        }


        RaycastHit[] rayHits =
            Physics.SphereCastAll(transform.position,
                                   targetRadius,
                                   transform.forward,
                                   targetRange,
                                   LayerMask.GetMask("Player"));

        if(rayHits.Length > 0 && !isAttack) {
            StartCoroutine(Attack());
        }
    }

    IEnumerator Attack()
    {
        isChase = false;
        isAttack = true;
        anim.SetBool("isAttack", true);

        switch (enemyType) {
            case Type.A:
                yield return new WaitForSeconds(0.2f);
                melleArea.enabled = true;

                yield return new WaitForSeconds(1f);
                melleArea.enabled = false;
                break;

            case Type.B:
                break;

            case Type.C:
                break;
        }
        
        isChase = true;
        isAttack = false;
        anim.SetBool("isAttack", false);
    }

    void FixedUpdate()
    {
        Targeting();
    }
}
  • 미리 만들어 둔, EnemyBullet컴포넌트의 Box Collider를 담을 변수를 만들었습니다.
  • 공격 하기 전 Targeting()이라는 함수를 만들어, 몬스터가 플레이어가 공격범위에 들어오는지를 알기위해 레이를 사용합니다.
  • 각 몬스터 타입별로, 감지범위, 감지거리를 설정하고 SphereCastAll을 통하여, 레이를 쏴 범위에 안에 들어오면 Attack() 함수를 코루틴으로 실행하여 줍니다.
  • Attack()함수에선 각 코루틴으로 코드를 정지해가면서, Box Collider 변수인 melleArea가 활성화 되도록 만들어줍니다.

- 애니메이션

11강에서 만든 애니메이션을 그대로 사용합니다.

 

🧷 4. 돌격형 몬스터

돌격형 몬스터는,  플레이어가 탐지범위에 들어선 순간 돌격하며  공격합니다

 

- 몬스터 피격용 범위 만들기

  • 일반형 몬스터와 마찬가지로, 컴포넌트를 붙혀넣기 하여 똑같이 만들어줍시다.

 

- 몬스터 공격 기능 만들기

/* Enemy script , 추가되는 부분만 넣었습니다. */
public class Enemy : MonoBehaviour
{
	void Targeting()
    {
        switch (enemyType) {
            case Type.A:
                break;

            case Type.B:
                targetRadius = 1f;
                targetRange = 12f;
                break;

            case Type.C:
                break;
        }
        }
    }

    IEnumerator Attack()
    {
        switch (enemyType) {
            case Type.A:
                break;

            case Type.B:
                yield return new WaitForSeconds(0.1f);
                rigid.AddForce(transform.forward * 20, ForceMode.Impulse);
                melleArea.enabled = true;

                yield return new WaitForSeconds(0.5f);
                rigid.velocity = Vector3.zero;
                melleArea.enabled = false;

                yield return new WaitForSeconds(2f);
                break;

            case Type.C:
                break;
        }
    }
}
  • Trageting() 함수에서는, 좀더 좁은 탐지범위(tragetRadius)와, 긴 탐지길이(targetRange)를 갖도록 합니다.
  • 또 탐지가 될 경우에, Attack함수를 실행하는데, 이때 AddForce로, 몬스터가 가는 방향을 향해 힘을 가하도록 합시다. 돌격 후 몬스터는 다시 움직이기까지 쿨타임을 갖습니다.

 

- 애니메이션

11강에서 만든 애니메이션을 그대로 사용합니다.

 

🧷 5. 원거리형 몬스터

- 원거리형 전용 미사일 오브젝트 만들기

  • 에셋에서 Missile을 가져와, Box Collider와 Rigidbody(꼭 Use Gravity 해제 해 주어야합니다.), Bullet Script 까지 넣어줍니다.

  • Effect 컴포넌트를 만들어서, Particle System을 만들어 불꽃을 표현하여 줍니다.
  1. Renderer의 Material을 Default line으로 설정해줍니다.
  2. Size를 설정합니다
  3. Emission에서 파티클 갯수를 설정해줍니다.
  4. Size over Lifetime을 가면 갈 수록 적어지게 만들어줍니다
  5. Color over Lifetime을 통해 불꽃색을 표현해 줍니다.
  6. Shape에서 불꽃이 나가는 범위를 설정해줍시다

이후, 프리팹으로 저장해줍니다.

 

- 오브젝트 만들기

  • 몬스터 A, B와 같게 오브젝트를 설정을 해줍니다.
  • 꼭 미사일을 Bullet 변수에 넣어줍니다. (스크립트에 미리 설정해 있어야함)

  • 내비게이션의 스피드로 설정해줍니다.

 

- 미사일 공격 기능 만들기

/* Enemy script , 추가되는 부분만 넣었습니다. */
public class Enemy : MonoBehaviour
{
    public GameObject bullet;

    void Targeting()
    {
        switch (enemyType) {
            case Type.A:
                break;

            case Type.B:
                break;

            case Type.C:
                targetRadius = 0.5f;
                targetRange = 25f;
                break;
        }
    }

    IEnumerator Attack()
    {
        switch (enemyType) {
            case Type.A:
                break;

            case Type.B:
                break;

            case Type.C:
                yield return new WaitForSeconds(0.5f);
                GameObject instantBullet = Instantiate(bullet, transform.position, transform.rotation);
                Rigidbody rigidBullet = instantBullet.GetComponent<Rigidbody>();
                rigidBullet.velocity = transform.forward * 20;

                yield return new WaitForSeconds(2f);
                break;
        }
    }
}
  • 원거리 몬스터 C타입시, 미사일을 인스턴트 생성을 하여서, rigidbody 속력을 나아가는 방향으로 힘을 줍니다.
  • 탐지범위와, 거리는 원거리에 맞게 설정을 해줍니다.

 

- 애니메이션

  • 기존 Animator의 Enemy A, B타입과 다른 C타입 전용 애니메이션으로 바꿔줍니다.

 

-  레이어 설정

  • 미사일은 Tag와 Layer이 EnemyBullet으로 설정되고, 적과는 레이어가 충돌하지 않게 설정하여 주었습니다

 

🧷 6. 기타 점검사항

  • Enemy A, B, C 의 오브젝트의 Layer, Tag는 Enemy로
  • EnemyBullet 오브젝트는 Layer,Tag도 EnemyBullet으로 설정합니다.
  • 애니메이션 컨트롤러는 Mesh Object안에 각자 각각 애니메이션 컨트롤러를 달아줍니다.
  • Bullet 스크립트의 데미지를 설정해줍니다.
  • Enemy 타입별로 타입과 체력, Nav Mesh Agent의 속도, 가속도, 회전속도까지 입맛에 따라 맞춰줍니다.
public class Bullet : MonoBehaviour
{
    public int damage;
    public bool isMelee;

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

    void OnTriggerEnter(Collider other)
    {
        if (!isMelee && other.gameObject.tag == "Wall")
        {
            Destroy(gameObject);
        }
    }
}
  • Bullet 스크립트에서의 근접공격하는 범위는 벽이 닿아도, 사라지지 않도록 조건을 달아줍니다.

 

이번 강의에서는 플레이어가 공격을 헀을 때 처럼, 몬스터들고 공격시 피격범위와, 레이를 이용한 감지범위 또, 코루틴을 사용한 공격기능등을 다시금 알아 볼 수 있는 시간이였습니다.

 

 

 

출처: 골든메탈님 유튜브

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

 

Contents

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

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