[XR 전문 인력 과정] 유니티 타워디펜스 만들기(3) -HDRI 적용, AINavMeshAgent 적용, 적이 타워를 공격하게 하기

2023. 11. 29. 21:18Unity

728x90
반응형

HDRI 적용

 

Kloppenheim 06 (Pure Sky) HDRI • Poly Haven

Download this free HDRI from Poly Haven

polyhaven.com

적절한 HDRI를 찾아서 적용한다.

 

 

적용 전과 적용 후. 해가 지는 느낌을 표현하기 위해 그에 맞는 HDRI를 선정하였다.

 

 

HDRI를 적용해도 Game Scene에서는 적용한 HDRI가 보이지 않는데, 이럴 경우 카메라 Inspector를 확인하면 된다.

[Camera] - [Clear Flags] - [Solid Color]를 [Skybox]로 바꾼다.

 

 


 

 

적 구현하기

적이 생성되고, 2초 뒤에 타워를 향해서 움직이고(AI 사용) 일정 거리 안쪽으로 들어오면 타워를 공격하게 만든다.

AI가 장애물을 알아서 피하가게 만들 예정. 적을 배치할 때 평지에 배치하는 것이 좋다.

 

 

적이 될 비행기를 씬에 배치한다.

 

 

EnemyAI 스크립트 생성

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyAI : MonoBehaviour
{
    //상태 상수 정의
    enum EnemyState
    {
        Idle, Move, Attack, Damage, Die
    }
    //초기 시작 상태 설정
    EnemyState state = EnemyState.Idle;
    //대기 지속 시간
    public float idleDelayTime = 2f;
    //경과 시간
    float currentTime = 0;
    void Start()
    {
        
    }
    void Update()
    {
        switch (state)
        {
            case EnemyState.Idle:
                Idle();
                break;
        }
    }
    void Idle()
    {
        //시간의 경과
        currentTime += Time.deltaTime;
        if(currentTime > idleDelayTime)
        {
            //일정 시간 이상 지나면 이동 상태로 전환
            state = EnemyState.Move;
            print("이동 상태");
        }
    }
}

 

 


 

 

AINavMeshAgent 사용

맵 요소를 모두 모아놨던 Environment 그룹을 누르고 우측 상단의 [Static] 적용을 한다.

 

NavMesh를 사용하기 위해 [Package Manager] - [AI Navigation]을 설치한다.

 

[Window] - [AI] - [Navigation (Obsolete)] 선택

 

[Bake]를 하면, 씬에 갈 수 있는 부분이  파랗게 표시된다.

 

Enemy에 [Nav Mesh Agent] 컴포넌트를 추가한다.

 

 

EnemyAI 스크립트 수정

NavMesh 적용하기

네임스페이스 추가

using UnityEngine.AI;

 

변수 3개 추가

//이동 속도
public float moveSpeed = 5f;
//타워 위치
Transform tower;
//네비게이션 메시 에이전트 가져오기
NavMeshAgent agent;

 

Start 함수에 변수 초기화 등

void Start()
{
    //타워를 이름으로 가져오기
    tower = GameObject.Find("TowerObject").transform;
    agent = GetComponent<NavMeshAgent>();
    //처음 상태에서는 비활성화 되어야한다.
    agent.enabled = false;
    agent.speed = moveSpeed;
}

 

EnemyState.Move 상태 추가, Movement() 함수 추가

void Update()
{
    switch (state)
    {
        case EnemyState.Idle:
            Idle();
            break;
        case EnemyState.Move:
            Movement();
            break;
    }
}
void Movement()
{
    agent.SetDestination(tower.position);
}

 

Idle() 함수에서 agent.enabled = true; 활성화

void Idle()
{
    //시간의 경과
    currentTime += Time.deltaTime;
    if(currentTime > idleDelayTime)
    {
        //일정 시간 이상 지나면 이동 상태로 전환
        state = EnemyState.Move;
        print("이동 상태");
        //에이전트 활성화
        agent.enabled = true;
    }
}

 

현재까지 EnemyAI 전체 코드

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class EnemyAI : MonoBehaviour
{
    //상태 상수 정의
    enum EnemyState
    {
        Idle, Move, Attack, Damage, Die
    }
    //초기 시작 상태 설정
    EnemyState state = EnemyState.Idle;
    //대기 지속 시간
    public float idleDelayTime = 2f;
    //경과 시간
    float currentTime = 0;
    //이동 속도
    public float moveSpeed = 5f;
    //타워 위치
    Transform tower;
    //네비게이션 메시 에이전트 가져오기
    NavMeshAgent agent;
    void Start()
    {
        //타워를 이름으로 가져오기
        tower = GameObject.Find("TowerObject").transform;
        agent = GetComponent<NavMeshAgent>();
        //처음 상태에서는 비활성화 되어야한다.
        agent.enabled = false;
        agent.speed = moveSpeed;
    }
    void Update()
    {
        switch (state)
        {
            case EnemyState.Idle:
                Idle();
                break;
            case EnemyState.Move:
                Movement();
                break;
        }
    }
    void Idle()
    {
        //시간의 경과
        currentTime += Time.deltaTime;
        if(currentTime > idleDelayTime)
        {
            //일정 시간 이상 지나면 이동 상태로 전환
            state = EnemyState.Move;
            print("이동 상태");
            //에이전트 활성화
            agent.enabled = true;
        }
    }
    void Movement()
    {
        agent.SetDestination(tower.position);
    }
}

타워 쪽으로 자동으로 움직이는 것을 볼 수 있다.(신기방기)

 

 


 

 

적이 일정 거리 안으로 왔을 때 공격 상태로 전환

EnemyAI 스크립트 수정

변수 선언

//공격 범위
public float attackRange = 30f;

 

Movement() 함수 수정

void Movement()
{
    agent.SetDestination(tower.position);

    //공격 범위 안에 들어오면 공격 상태로 전환
    if(Vector3.Distance(transform.position, tower.position) < attackRange)
    {
        state = EnemyState.Attack;
        //공격 상태일 때는 NavMesh 비활성화
        agent.enabled = false;
    }
}

 

현재까지 EnemyAI 전체 스크립트

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class EnemyAI : MonoBehaviour
{
    //상태 상수 정의
    enum EnemyState
    {
        Idle, Move, Attack, Damage, Die
    }
    //초기 시작 상태 설정
    EnemyState state = EnemyState.Idle;
    //대기 지속 시간
    public float idleDelayTime = 2f;
    //경과 시간
    float currentTime = 0;
    //이동 속도
    public float moveSpeed = 5f;
    //타워 위치
    Transform tower;
    //네비게이션 메시 에이전트 가져오기
    NavMeshAgent agent;
    //공격 범위
    public float attackRange = 30f;
    void Start()
    {
        //타워를 이름으로 가져오기
        tower = GameObject.Find("TowerObject").transform;
        agent = GetComponent<NavMeshAgent>();
        //처음 상태에서는 비활성화 되어야한다.
        agent.enabled = false;
        agent.speed = moveSpeed;
    }
    void Update()
    {
        switch (state)
        {
            case EnemyState.Idle:
                Idle();
                break;
            case EnemyState.Move:
                Movement();
                break;
        }
    }
    void Idle()
    {
        //시간의 경과
        currentTime += Time.deltaTime;
        if(currentTime > idleDelayTime)
        {
            //일정 시간 이상 지나면 이동 상태로 전환
            state = EnemyState.Move;
            print("이동 상태");
            //에이전트 활성화
            agent.enabled = true;
        }
    }
    void Movement()
    {
        agent.SetDestination(tower.position);

        //공격 범위 안에 들어오면 공격 상태로 전환
        if(Vector3.Distance(transform.position, tower.position) < attackRange)
        {
            state = EnemyState.Attack;
            //공격 상태일 때는 NavMesh 비활성화
            agent.enabled = false;
        }
    }
}

 

타워 앞에서 멈춘다.

 

 


 

 

공격 상태로 전환된 적이 공격

공격에 2초 정도 지연 시간을 준다.

변수 선언

//공격 지연 시간
public float attackDelayTime = 2f;

 

EnemyState.Attack 공격 상태 추가

void Update()
{
    switch (state)
    {
        case EnemyState.Idle:
            Idle();
            break;
        case EnemyState.Move:
            Movement();
            break;
        case EnemyState.Attack:
            Attack();
            break;
    }
}

 

Attack() 함수 추가

void Attack()
{
    currentTime += Time.deltaTime;
    if(currentTime > attackDelayTime)
    {
        Debug.Log("공격!");
        currentTime = 0;
    }
}

 

현재는 적이 공격 범위에 들어오자마자 공격한다. Idle() 함수에서 currentTime을 0으로 초기화 했으면 공격 범위에 들어온 후 2초 뒤에 공격한다.

 

현재까지 EnemyAI 스크립트 전체 코드

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class EnemyAI : MonoBehaviour
{
    //상태 상수 정의
    enum EnemyState
    {
        Idle, Move, Attack, Damage, Die
    }
    //초기 시작 상태 설정
    EnemyState state = EnemyState.Idle;
    //대기 지속 시간
    public float idleDelayTime = 2f;
    //경과 시간
    float currentTime = 0;
    //이동 속도
    public float moveSpeed = 5f;
    //타워 위치
    Transform tower;
    //네비게이션 메시 에이전트 가져오기
    NavMeshAgent agent;
    //공격 범위
    public float attackRange = 30f;
    //공격 지연 시간
    public float attackDelayTime = 2f;
    void Start()
    {
        //타워를 이름으로 가져오기
        tower = GameObject.Find("TowerObject").transform;
        agent = GetComponent<NavMeshAgent>();
        //처음 상태에서는 비활성화 되어야한다.
        agent.enabled = false;
        agent.speed = moveSpeed;
    }
    void Update()
    {
        switch (state)
        {
            case EnemyState.Idle:
                Idle();
                break;
            case EnemyState.Move:
                Movement();
                break;
            case EnemyState.Attack:
                Attack();
                break;
        }
    }
    void Idle()
    {
        //시간의 경과
        currentTime += Time.deltaTime;
        if(currentTime > idleDelayTime)
        {
            //일정 시간 이상 지나면 이동 상태로 전환
            state = EnemyState.Move;
            print("이동 상태");
            //에이전트 활성화
            agent.enabled = true;
        }
    }
    void Movement()
    {
        agent.SetDestination(tower.position);

        //공격 범위 안에 들어오면 공격 상태로 전환
        if(Vector3.Distance(transform.position, tower.position) < attackRange)
        {
            state = EnemyState.Attack;
            //공격 상태일 때는 NavMesh 비활성화
            agent.enabled = false;
        }
    }
    void Attack()
    {
        currentTime += Time.deltaTime;
        if(currentTime > attackDelayTime)
        {
            Debug.Log("공격!");
            currentTime = 0;
        }
    }
}
728x90
반응형