Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
Tags
- 자료 구조
- 입문
- 유니티
- 개인 프로젝트
- 1월
- c++
- 2023년
- 유니티 심화과정
- 2022년
- 6월
- 7월
- 단계별로 풀어보기
- 4월
- 게임 엔진 공부
- 백준
- 5월
- 개인 프로젝트 - 런앤건
- 3월
- 2024년
- 프로그래머스
- C/C++
- 2025년
- 코딩 기초 트레이닝
- 다이나믹 프로그래밍
- 골드메탈
- 수학
- 2월
- 기초
- 코딩 테스트
- todolist
Archives
- Today
- Total
기록 보관소
[Unity/유니티] 기초-3D 쿼터뷰 액션 게임: 목표를 추적하는 AI 만들기[B48] 본문
개요
유니티 입문과 독학을 위해서 아래 링크의 골드메탈님의 영상들을 보며 진행 상황 사진 또는 캡처를 올리고 배웠던 점을 요약해서 적는다.
현재는 영상들을 보고 따라하고 배우는 것에 집중할 것이며, 영상을 모두 보고 따라한 후에는 개인 프로젝트를 설계하고 직접 만드는 것이 목표다.
https://youtube.com/playlist?list=PLO-mt5Iu5TeYI4dbYwWP8JqZMC9iuUIW2
유니티 강좌 기초 채널 Basic
유니티 개발을 처음 시작하시는 입문자 분들을 위한 기초 채널. [ 프로젝트 ] B00 ~ B12 (BE1) : 유니티 필수 기초 B13 ~ B19 (BE2) : 2D 플랫포머 B20 ~ B26 (BE3) : 2D 탑다운 대화형 RPG B27 ~ B37 (BE4) : 2D 종스크롤
www.youtube.com
3D 쿼터뷰 액션 게임: 목표를 추적하는 AI 만들기[B48]
1. 오브젝트 생성


//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>();
mat = GetComponentInChildren<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, false));
}
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, false));
}
}
public void HitByGrenade(Vector3 explosionPos) {
curHealth -= 100;
Vector3 reactVec = transform.position - explosionPos;
StartCoroutine(OnDamage(reactVec, true));
}
IEnumerator OnDamage(Vector3 reactVec, bool isGrenade) {
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; //Enemy Dead 레이어로 변경
if (isGrenade) {
reactVec = reactVec.normalized;
reactVec += Vector3.up * 5;
rigid.freezeRotation = false;
rigid.AddForce(reactVec * 5, ForceMode.Impulse);
rigid.AddTorque(reactVec * 15, ForceMode.Impulse);
}
else {
reactVec = reactVec.normalized;
reactVec += Vector3.up;
rigid.AddForce(reactVec * 5, ForceMode.Impulse);
}
Destroy(gameObject, 4);
}
}
}
- Material을 가져올때, Enemy A의 경우 자식 오브젝트 Mesh Object 아래에 있어서 GetComponentInChildren으로 변경해준다.
2. 네비게이션




- NavMesh : NavAgent가 경로를 그리기 위한 바탕. Static 오브젝트만 Bake 가능하다.




//Enemy 스크립트 파일
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Enemy : MonoBehaviour {
public int maxHealth;
public int curHealth;
public Transform target;
Rigidbody rigid;
BoxCollider boxCollider;
Material mat;
NavMeshAgent nav;
void Awake() {
rigid = GetComponent<Rigidbody>();
boxCollider = GetComponent<BoxCollider>();
mat = GetComponentInChildren<MeshRenderer>().material;
nav = GetComponent<NavMeshAgent>();
}
void Update() {
nav.SetDestination(target.position);
}
void FreezeVelocity() {
rigid.velocity = Vector3.zero;
rigid.angularVelocity = Vector3.zero;
}
void FixedUpdate() {
FreezeVelocity();
}
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, false));
}
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, false));
}
}
public void HitByGrenade(Vector3 explosionPos) {
curHealth -= 100;
Vector3 reactVec = transform.position - explosionPos;
StartCoroutine(OnDamage(reactVec, true));
}
IEnumerator OnDamage(Vector3 reactVec, bool isGrenade) {
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; //Enemy Dead 레이어로 변경
if (isGrenade) {
reactVec = reactVec.normalized;
reactVec += Vector3.up * 5;
rigid.freezeRotation = false;
rigid.AddForce(reactVec * 5, ForceMode.Impulse);
rigid.AddTorque(reactVec * 15, ForceMode.Impulse);
}
else {
reactVec = reactVec.normalized;
reactVec += Vector3.up;
rigid.AddForce(reactVec * 5, ForceMode.Impulse);
}
Destroy(gameObject, 4);
}
}
}
- NavMeshAgent : Navigation을 사용하는 인공지능 컴포넌트. NavMesh가 없으면 이동할 수 없다.
- Nav 관련 클래스는 UnityEngine.AI 네임 스페이스를 사용해야한다.
- .SetDestination(Vector3 target) : 도착할 목표 위치 지정 함수




3. 애니메이션



- bool형 매개변수 isWalk와 isAttack, Trigger형 매개변수 doDie를 추가하고 위 캡처와 같이 Transition을 설정하면 된다. 자세한 Transition 설정은 다음과 같다.
- 모든 Transition은 Has Exit Time 체크를 해제하고, Transition Duration을 0으로 설정
- AnyState -> Die : doDie
- Idle -> Walk : isWalk true
- Walk -> Idle : isWalk false
- Walk -> Attack : isAttack true
- Attack -> Walk : isAttack false
//Enemy 스크립트 파일
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Enemy : MonoBehaviour {
public int maxHealth;
public int curHealth;
public Transform target;
public bool isChase;
Rigidbody rigid;
BoxCollider boxCollider;
Material mat;
NavMeshAgent nav;
Animator anim;
void Awake() {
rigid = GetComponent<Rigidbody>();
boxCollider = GetComponent<BoxCollider>();
mat = GetComponentInChildren<MeshRenderer>().material;
nav = GetComponent<NavMeshAgent>();
anim = GetComponentInChildren<Animator>();
Invoke("ChaseStart", 2);
}
void ChaseStart() {
isChase = true;
anim.SetBool("isWalk", true);
}
void Update() {
if (isChase)
nav.SetDestination(target.position);
}
void FreezeVelocity() {
if (isChase) {
rigid.velocity = Vector3.zero;
rigid.angularVelocity = Vector3.zero;
}
}
void FixedUpdate() {
FreezeVelocity();
}
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, false));
}
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, false));
}
}
public void HitByGrenade(Vector3 explosionPos) {
curHealth -= 100;
Vector3 reactVec = transform.position - explosionPos;
StartCoroutine(OnDamage(reactVec, true));
}
IEnumerator OnDamage(Vector3 reactVec, bool isGrenade) {
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; //Enemy Dead 레이어로 변경
isChase = false;
nav.enabled = false;
anim.SetTrigger("doDie");
if (isGrenade) {
reactVec = reactVec.normalized;
reactVec += Vector3.up * 5;
rigid.freezeRotation = false;
rigid.AddForce(reactVec * 5, ForceMode.Impulse);
rigid.AddTorque(reactVec * 15, ForceMode.Impulse);
}
else {
reactVec = reactVec.normalized;
reactVec += Vector3.up;
rigid.AddForce(reactVec * 5, ForceMode.Impulse);
}
Destroy(gameObject, 4);
}
}
}





'유니티 프로젝트 > 3D 쿼터뷰 액션게임' 카테고리의 다른 글
[Unity/유니티] 기초-3D 쿼터뷰 액션 게임: 다양한 패턴을 구사하는 보스 만들기[B50] (0) | 2022.04.07 |
---|---|
[Unity/유니티] 기초-3D 쿼터뷰 액션 게임: 다양한 몬스터 만들기[B49] (0) | 2022.04.03 |
[Unity/유니티] 기초-3D 쿼터뷰 액션 게임: 수류탄 구현하기[B47] (0) | 2022.04.02 |
[Unity/유니티] 기초-3D 쿼터뷰 액션 게임: 피격 테스터 만들기[B46] (0) | 2022.03.30 |
[Unity/유니티] 기초-3D 쿼터뷰 액션 게임: 플레이어 물리 문제 고치기[B45] (0) | 2022.03.27 |