말감로그

2024.10.04 Unity - 수류탄 효과, 몬스터 AI (NavMeshAgent) 본문

TIL

2024.10.04 Unity - 수류탄 효과, 몬스터 AI (NavMeshAgent)

habbn 2024. 10. 4. 17:57
728x90

 

통통 튀는 효과를 주기 위해 PhysicsMaterial 을 생성해서 추가한다.

Mesh Object > Trail Render 컴포넌트 추가

폭발 파티클 자식 오브젝트에 추가

 

 

코루틴을 사용해서 수류탄 터지는 효과를 구현하고 

SphereCastAll 레이캐스팅을 사용하여 수류탄과 충돌한 모든 오브젝트(Enemy)를 가져와 넉백 효과를 준다.

void Start()
{
    StartCoroutine(Explosion());
}

IEnumerator Explosion()
{
    yield return new WaitForSeconds(3f);

    //물리적 속도를 모두 0으로 초기화
    // rigid.velocity = Vector3.zero;
    // rigid.angularVelocity = Vector3.zero;
    rigid.isKinematic = true;

    meshObj.SetActive(false);
    effectObj.SetActive(true);

    // SphereCastAll : 구체 모양의 레이캐스팅(모든 오브젝트를 다 가져옴)
    RaycastHit[] rayHits = Physics.SphereCastAll(transform.position, 15, Vector3.up, 0f, LayerMask.GetMask("Enemy"));

    foreach(RaycastHit hitObj in rayHits)
    {
        hitObj.transform.GetComponent<Enemy>().HitByGrenade(transform.position);
    }
    Destroy(gameObject, 5);
}

 

골드메탈님은 주석친 부분과 같이 직접적으로 velocity와 augularVelocity를 Vector3.zero로 설정해서 물리 효과를 받지 않도록 했는데, isKinematic으로 설정해도 된다는 댓글을 봐서 isKinematic으로 수정하였다.

 

 

몬스터 AI - NavMeshAgent

 

Enemy에 Nav Mesh Agent 컴포넌트를 추가하고 스크립트에서 가져와야함

using UnityEngine.AI;

 

네임스페이스를 추가해야 NavMeshAgent 사용 가능

void Update() 
{
    if(isChase)
        nav.SetDestination(target.position);  //도착할 목표 위치 지정 함수 
}

 

SetDestination() : 도착할 목표 위치 지정 함수를 사용해서 타겟을 따라가도록 한다.

 

Window > AI > Navigation(Obstacle) > Bake 해야 Nav Mesh가 만들어진다. 

 

 

근접 / 돌격 / 원거리

 

플레이어를 타겟팅 하고 각 공격 스타일에 맞게 공격하도록 한다. 모두 다 코루틴 사용

void Targeting()
{
    if (!isDead && enemyType != Type.D)
    {
        float targetRadius = 1.5f;
        float targetRange = 3f;

        switch (enemyType)
        {
            case Type.B:
                targetRadius = 1f;
                targetRange = 12f;
                break;
            case Type.C:
                targetRadius = 0.5f;
                targetRange = 25f;
                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);
            meleeArea.enabled = true;

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

            yield return new WaitForSeconds(1f);
            break;

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

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

            yield return new WaitForSeconds(2f);
            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;
    }

    isChase = true;
    isAttack = false;
    anim.SetBool("isAttack", false);
}

 

 

728x90