인텔리킴의 Unity Studying & Game Analysis
13. 유니티 2D 게임 제작 - 몬스터 AI 구현 본문
기본 세팅
먼저 애니메이터를 편집해 기본적인 매개변수 및 트랜지션을 설정함
기본적인 이동 구현
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyMove : MonoBehaviour
{
Rigidbody2D rigid;
void Awake()
{
rigid = GetComponent<Rigidbody2D>();
}
void FixedUpdate()
{
rigid.velocity = new Vector2(-1, rigid.velocity.y);
}
}
플레이어의 방향키 없이 움직여도 되기 때문에
rigid.velocity를 이용해 간단하게 구현
행동 결정 로직
public class EnemyMove : MonoBehaviour
{
Rigidbody2D rigid;
public int nextMove;
void Awake()
{
rigid = GetComponent<Rigidbody2D>();
Invoke("Think", 5);
}
void FixedUpdate()
{
rigid.velocity = new Vector2(-1, rigid.velocity.y);
}
//재귀함수
void Think()
{
nextMove = Random.Range(-1, 2);
Debug.Log(nextMove);
Invoke("Think", 5);
}
}
Random.Range(int , int) : 앞 숫자 이상 뒷 숫자 미만의 랜덤한 숫자 하나를 불러옴
Invoke() : 주어진 시간이 지난 뒤에 지정된 함수를 실행하는 함수
재귀함수 : 자기 자신을 불러오는 함수
일정시간마다 랜덤한 숫자를 불러오고 자기자신을 불러오는 새로운 Think() 재귀함수를 작성
레이캐스트가 오브젝트의 앞에서 아래를 향해 발사되야함
이 값은 nextMove 변수가 가지고 있음
Vector2 frontVector = new Vector2(nextMove + rigid.position.x, rigid.position.y);
자기의 앞을 확인하는 벡터값을 하나 제작
//이동
rigid.velocity = new Vector2(nextMove, rigid.velocity.y);
//지형 체크
Vector2 frontVector = new Vector2(nextMove + rigid.position.x, rigid.position.y);
RaycastHit2D rayHit = Physics2D.Raycast(frontVector, Vector2.down, 1, LayerMask.GetMask("Platform"));
if (rayHit.collider == null)
{
Debug.Log("이 앞은 낭떠러지");
}
오브젝트의 앞에서 레이가 발사되어
레이가 바닥의 플랫폼과 닿지 않으면 디버그 메세지를 출력하는 코드를 작성
void FixedUpdate()
{
//이동
rigid.velocity = new Vector2(nextMove, rigid.velocity.y);
//지형 체크
Vector2 frontVector = new Vector2(nextMove + rigid.position.x, rigid.position.y);
RaycastHit2D rayHit = Physics2D.Raycast(frontVector, Vector2.down, 1, LayerMask.GetMask("Platform"));
Debug.DrawRay(frontVector,Vector3.down ,new Color(0, 1, 0));
if (rayHit.collider == null)
{
Debug.Log("이 앞은 낭떠러지");
nextMove = nextMove * -1;
CancelInvoke();
Invoke("Think", 5);
}
}
CancelInvoke() : 지금 진행중인 Invoke()를 취소하는 함수
만약 앞으로 진행하는 방향에 낭떠러지가 있으면 반대 방향으로 이동
이동 애니메이션 설정
애니메이터 매개변수에 WalkSpeed int형 매개변수 작성
인스펙터의 int 매개변수는
Greater, Equal, NotEqual, Less 의 4가지로 나누어짐
WalkSpeed 매개변수가 0일때 가만히 있는 애니메이션이 나오도록 설정
만약 0이 아니라면 움직이는 애니메이션 재생
void Think()
{
//다음 움직임 생각
thinkTime = Random.Range(2, 5);
nextMove = Random.Range(-1, 1);
Debug.Log(nextMove);
//애니메이션 재생
animator.SetInteger("WalkSpeed", nextMove);
//애니메이션 방향 전환
if (nextMove != 0)
{
spriteRenderer.flipX = nextMove == 1;
}
//반복
Invoke("Think", thinkTime);
}
Think 함수 다시 작성
spriteRenderer.flipX = nextMove == 1; : nextMove를 1이면 전환(true면 반전)
하지만 그대로 코드를 실행하면 앞에 낭떠러지가 있을경우 애니메이션이 반전되지 않는 문제가 발생함
if (nextMove != 0)
{
spriteRenderer.flipX = nextMove == 1;
}
이 구문이 한번더 낭떠러지 확인 조건문 안에 들어가야하지만 그러면 번거로우니 따로 함수로 한번더 작성
void Flip(int decideFlip)
{
if (decideFlip != 0)
{
spriteRenderer.flipX = decideFlip == 1;
}
}
Flip 함수로 작성
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyMove : MonoBehaviour
{
Rigidbody2D rigid;
int nextMove;
int thinkTime;
Animator animator;
SpriteRenderer spriteRenderer;
void Awake()
{
rigid = GetComponent<Rigidbody2D>();
Invoke("Think", 5);
animator = GetComponent<Animator>();
spriteRenderer = GetComponent<SpriteRenderer>();
}
void FixedUpdate()
{
//이동
rigid.velocity = new Vector2(nextMove, rigid.velocity.y);
//지형 체크
Vector2 frontVector = new Vector2(nextMove * 0.25f + rigid.position.x, rigid.position.y);
RaycastHit2D rayHit = Physics2D.Raycast(frontVector, Vector2.down, 1, LayerMask.GetMask("Platform"));
Debug.DrawRay(frontVector,Vector3.down ,new Color(0, 1, 0));
if (rayHit.collider == null)
{
Debug.Log("이 앞은 낭떠러지");
nextMove = nextMove * -1;
Flip(nextMove);
CancelInvoke();
Invoke("Think", 5);
}
}
//재귀함수
void Think()
{
//다음 움직임 생각
thinkTime = Random.Range(2, 5);
nextMove = Random.Range(-1, 2);
Debug.Log(nextMove);
//애니메이션 재생
animator.SetInteger("WalkSpeed", nextMove);
//애니메이션 방향 전환
Flip(nextMove);
//반복
Invoke("Think", thinkTime);
}
void Flip(int decideFlip)
{
if (decideFlip != 0)
{
spriteRenderer.flipX = decideFlip == 1;
}
}
}
최종적인 몬스터 이동 코드
추가 설명
spriteRenderer.flipX = nextMove == 1; : nextMove가 1이라면 전환(true면 전환)
이부분이 이해가 처음에 되지않아 추가설명을 함
몬스터 스프라이트가 기본적으로 왼쪽(-1)방향을 바라보고 있는데위 구문은 1일 경우(오른쪽으로 이동할 경우) 스프라이트를 반전시킴하지만 -1일 경우(왼쪽으로 이동할 경우) 스프라이트를 반전시키지 않음
한마디로스프라이트가 왼쪽을 바라보고 있을 때왼쪽으로 이동할 경우(-1일 때) 플립을 꺼서 스프라이트 그대로 왼쪽을 바라보게 하고오른쪽으로 이동할 경우(1일 때) 플립을 켜서 오른쪽을 바라보게함또한 0이 나온다면 아예 bool 값에서 오류가 날 수 있음그렇기 때문에 0이 아닐 경우의 조건문 또한 추가함
'게임 개발 일지 > 유니티 엔진 공부' 카테고리의 다른 글
15. 유니티 2D 게임 제작 - 문제 수정 및 밟기 공격 기능 구현 (0) | 2024.04.21 |
---|---|
14. 유니티 2D 게임 제작 - 플레이어 데미지 구현 (1) | 2024.04.20 |
12. 유니티 2D 게임 제작 - 타일맵으로 지형 만들기 (0) | 2024.04.19 |
11. 유니티 2D 게임 제작 - 점프 구현 (0) | 2024.04.19 |
10. 유니티 2D 게임 제작 - 이동 (0) | 2024.04.19 |