2023. 11. 14. 17:18ㆍSKKU DT
적 상태 설정
적 생성 -Capsule Collider 제거, Character Controller 추가
적 스크립트 추가 -EnemyFSM 스크립트 생성
enum으로 상태 생성, switch문으로 상태 구별
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyFSM : MonoBehaviour
{
//적 상태 상수 6개 생성
enum EnemyState
{
Idle,
Move,
Attack,
Return,
Damaged,
Die
}
//적 상태 변수
EnemyState m_State;
//플레이어 발견 범위
public float findDistance = 10f;
//플레이어 Transform Component 적이 많이 생성되면 끌어 넣는게 비어있을 수 있다. Find로 찾아서 적용
Transform player;
void Start()
{
//플레이어 Transform Component 할당
player = GameObject.Find("Player").transform;
//최초의 적 상태를 대기로 설정
m_State = EnemyState.Idle;
}
void Update()
{
//적의 상태를 체크해서 상태별로 정해진 기능을 수행 Switch문
switch (m_State)
{
case EnemyState.Idle:
Idle();
break;
case EnemyState.Move:
//Move();
break;
}
}
void Idle()
{
//만약 플레이어와 적의 거리가 발견 범위 이내라면 Move 상태로 전환
if(Vector3.Distance(transform.position, player.position) < findDistance)
{
m_State = EnemyState.Move;
Debug.Log("발견!");
}
}
}
Idle 함수를 만들어서 Debug.Log로 범위 내에 들어오면 Console에 "발견!" 메시지가 호출되는지 확인한다.
AttackDistance 생각하기, 적 이동
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyFSM : MonoBehaviour
{
//적 상태 상수 6개 생성
enum EnemyState
{
Idle,
Move,
Attack,
Return,
Damaged,
Die
}
//적 상태 변수
EnemyState m_State;
//플레이어 발견 범위
public float findDistance = 10f;
//플레이어 Transform Component 적이 많이 생성되면 끌어 넣는게 비어있을 수 있다. Find로 찾아서 적용
Transform player;
//공격 범위
public float attackDistance = 4f;
//적 이동 속도
public float moveSpeed = 5f;
//적 캐릭터 컨트롤러 컴포넌트
CharacterController cc;
//적 공격 누적 시간
float currentTime = 0;
//적 공격 딜레이 시간
float attackDelay = 2f;
void Start()
{
//플레이어 Transform Component 할당
player = GameObject.Find("Player").transform;
//최초의 적 상태를 대기로 설정
m_State = EnemyState.Idle;
//적 캐릭터 컨트롤러 컴포넌트 할당
cc = GetComponent<CharacterController>();
}
void Update()
{
//적의 상태를 체크해서 상태별로 정해진 기능을 수행 Switch문
switch (m_State)
{
case EnemyState.Idle:
Idle();
break;
case EnemyState.Move:
Move();
break;
case EnemyState.Attack:
Attack();
break;
}
}
void Idle()
{
//만약 플레이어와 적의 거리가 발견 범위 이내라면 Move 상태로 전환
if(Vector3.Distance(transform.position, player.position) < findDistance)
{
m_State = EnemyState.Move;
Debug.Log("발견!");
}
}
void Move()
{
//만약 플레이어와 적의 거리가 공격 범위보다 크다면 플레이어를 향해 이동
if (Vector3.Distance(transform.position, player.position) > attackDistance)
{
//이동 방향
Vector3 dir = (player.position - transform.position).normalized;
//이동
cc.Move(dir * moveSpeed * Time.deltaTime);
}
else
{
m_State = EnemyState.Attack;
Debug.Log("공격!");
//공격이 바로 안되므로 공격 딜레이 시간 만큼 미리 진행을 시켜놓아야 한다.
currentTime = attackDelay;
}
}
void Attack()
{
//플레이어와 적의 거리가 공격 범위 이내라면 공격
if(Vector3.Distance(transform.position, player.position) < attackDistance)
{
//일정 시간마다 플레이어 공격
currentTime += Time.deltaTime;
if(currentTime > attackDelay)
{
print("공격!");
currentTime = 0;
}
}
//그렇지 않다면, Move();
else
{
m_State = EnemyState.Move;
Debug.Log("이동");
currentTime = 0;
}
}
}
일정 거리 계산과 적 공격에 딜레이를 부여
응용(미니맵 추가)
https://yoonstone-games.tistory.com/111
미니맵 용 카메라 추가
프로젝트 안에 Render Texture를 하나 만든 후 미니맵 카메라 안에 [Target Texture]에 넣는다.
캔버스 - Raw Image를 만든 후 [Texture]에 만들었던 Render Texture를 넣는다.
미니맵에 크게 잘 보이도록 플레이어 마크를 하나 넣고
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CamFollow : MonoBehaviour
{
//CamPosition의 Transform 컴포넌트
public Transform camTarget;
void Update()
{
//카메라 위치를 타겟 위치에 일치시키기
transform.position = camTarget.position;
}
}
카메라가 플레이어를 잘 따라다닐 수 있도록 미니맵 카메라에도 스크립트를 넣는다.
플레이어 HP 추가
-PlayerMove 스크립트에서 설정한 후 EnemyFSM 스크립트에서 적용할 예정(PlayerMove에서 체력을 설정하는 이유는 체력 바로 표현할 예정이기 때문)
-플레이어 체력 변수, DamageAction 추가
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMove : MonoBehaviour
{
public float moveSpeed = 7f;
//캐릭터 컨트롤러 컴포넌트 변수
CharacterController cc;
//중력 변수
float gravity = -20f;
//수직 속력 변수 초기화
float yVelocity = 0;
//점프력 변수
public float jumpPower = 7f;
//점프 상태 변수 처음엔 점프 안하므로 0
int isJumping = 0;
//플레이어 체력 변수
public int hp = 100;
private void Start()
{
//컴포넌트 변수는 Start 함수에서 할당을 해주어야 한다.
cc = GetComponent<CharacterController>();
}
void Update()
{
//키보드 입력 받기
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
//이동 방향 설정
Vector3 dir = new Vector3(horizontal, 0, vertical);
dir = dir.normalized;
//바라보는 기준 방향으로 움직이기
dir = Camera.main.transform.TransformDirection(dir);
//캐릭터가 바닥에 착지 했다면 = 바닥면이 닿았다면 상태 초기화
if(cc.collisionFlags == CollisionFlags.Below)
{
isJumping = 0;
yVelocity = 0;
}
//점프 후 중력값 적용을 위해 중력 값 적용 위에 쓴다. Space 누르면 점프
if (Input.GetButtonDown("Jump"))
{
if(isJumping == 0 || isJumping == 1)//만약 0또는 1인 상태이면 뛴다.
{
yVelocity = jumpPower;
isJumping += 1;
}
}
//수직 속도에 중력 값 적용
yVelocity += gravity * Time.deltaTime;
dir.y = yVelocity;
//이동
cc.Move(dir * moveSpeed * Time.deltaTime);
}
//플레이어 피격 함수
public void DamageAction(int damage) //argument로 int 형의 damage를 받아 온다.
{
//적의 공력력 만큼 플레이어 체력 감소
hp -= damage;
//체력이 음수이면 0으로 초기화
if(hp < 0)
{
hp = 0;
}
Debug.Log("플레이어 체력: " + hp);
}
}
EnemyFSM 스크립트에서는 적 공격력 변수 설정, PlayerMove 스크립트에서 DamageAction 함수 가져오기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyFSM : MonoBehaviour
{
//적 상태 상수 6개 생성
enum EnemyState
{
Idle,
Move,
Attack,
Return,
Damaged,
Die
}
//적 상태 변수
EnemyState m_State;
//플레이어 발견 범위
public float findDistance = 10f;
//플레이어 Transform Component 적이 많이 생성되면 끌어 넣는게 비어있을 수 있다. Find로 찾아서 적용
Transform player;
//공격 범위
public float attackDistance = 4f;
//적 이동 속도
public float moveSpeed = 5f;
//적 캐릭터 컨트롤러 컴포넌트
CharacterController cc;
//적 공격 누적 시간
float currentTime = 0;
//적 공격 딜레이 시간
float attackDelay = 2f;
//적 공격력
public int attackPower = 10;
void Start()
{
//플레이어 Transform Component 할당
player = GameObject.Find("Player").transform;
//최초의 적 상태를 대기로 설정
m_State = EnemyState.Idle;
//적 캐릭터 컨트롤러 컴포넌트 할당
cc = GetComponent<CharacterController>();
}
void Update()
{
//적의 상태를 체크해서 상태별로 정해진 기능을 수행 Switch문
switch (m_State)
{
case EnemyState.Idle:
Idle();
break;
case EnemyState.Move:
Move();
break;
case EnemyState.Attack:
Attack();
break;
}
}
void Idle()
{
//만약 플레이어와 적의 거리가 발견 범위 이내라면 Move 상태로 전환
if(Vector3.Distance(transform.position, player.position) < findDistance)
{
m_State = EnemyState.Move;
Debug.Log("발견!");
}
}
void Move()
{
//만약 플레이어와 적의 거리가 공격 범위보다 크다면 플레이어를 향해 이동
if (Vector3.Distance(transform.position, player.position) > attackDistance)
{
//이동 방향
Vector3 dir = (player.position - transform.position).normalized;
//이동
cc.Move(dir * moveSpeed * Time.deltaTime);
}
else
{
m_State = EnemyState.Attack;
Debug.Log("공격!");
//공격이 바로 안되므로 공격 딜레이 시간 만큼 미리 진행을 시켜놓아야 한다.
currentTime = attackDelay;
}
}
void Attack()
{
//플레이어와 적의 거리가 공격 범위 이내라면 공격
if(Vector3.Distance(transform.position, player.position) < attackDistance)
{
//일정 시간마다 플레이어 공격
currentTime += Time.deltaTime;
if(currentTime > attackDelay)
{
player.GetComponent<PlayerMove>().DamageAction(attackPower);
print("공격!");
currentTime = 0;
}
}
//그렇지 않다면, Move();
else
{
m_State = EnemyState.Move;
Debug.Log("이동");
currentTime = 0;
}
}
}
적이 특정 위치에서 멀어지면 다시 돌아가기
-Move() 함수에서 오리지널 좌표와 현재 좌표의 거리가 특정 거리보다 커지면 다시 오리지널 위치로 돌아가게 한다. Return 함수 생성
-오리지널 좌표는 Start 함수에 넣는다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyFSM : MonoBehaviour
{
//적 상태 상수 6개 생성
enum EnemyState
{
Idle,
Move,
Attack,
Return,
Damaged,
Die
}
//적 상태 변수
EnemyState m_State;
//플레이어 발견 범위
public float findDistance = 10f;
//플레이어 Transform Component 적이 많이 생성되면 끌어 넣는게 비어있을 수 있다. Find로 찾아서 적용
Transform player;
//공격 범위
public float attackDistance = 4f;
//적 이동 속도
public float moveSpeed = 5f;
//적 캐릭터 컨트롤러 컴포넌트
CharacterController cc;
//적 공격 누적 시간
float currentTime = 0;
//적 공격 딜레이 시간
float attackDelay = 2f;
//적 공격력
public int attackPower = 10;
//적이 다시 되돌아갈 초기 위치 저장
Vector3 originPos;
//적 이동 가능 범위
public float moveDistance = 20f;
void Start()
{
//플레이어 Transform Component 할당
player = GameObject.Find("Player").transform;
//최초의 적 상태를 대기로 설정
m_State = EnemyState.Idle;
//적 캐릭터 컨트롤러 컴포넌트 할당
cc = GetComponent<CharacterController>();
//적의 초기 위치 저장
originPos = transform.position;
}
void Update()
{
//적의 상태를 체크해서 상태별로 정해진 기능을 수행 Switch문
switch (m_State)
{
case EnemyState.Idle:
Idle();
break;
case EnemyState.Move:
Move();
break;
case EnemyState.Attack:
Attack();
break;
case EnemyState.Return:
Return();
break;
}
}
void Idle()
{
//만약 플레이어와 적의 거리가 발견 범위 이내라면 Move 상태로 전환
if(Vector3.Distance(transform.position, player.position) < findDistance)
{
m_State = EnemyState.Move;
Debug.Log("발견!");
}
}
void Move()
{
//만약 현재 위치와 초기 위치 거리가 이동 가능 범위보다 크면 복귀
if(Vector3.Distance(transform.position, originPos) > moveDistance)
{
m_State = EnemyState.Return;
Debug.Log("상태 전환");
}
//만약 플레이어와 적의 거리가 공격 범위보다 크다면 플레이어를 향해 이동
else if (Vector3.Distance(transform.position, player.position) > attackDistance)
{
//이동 방향
Vector3 dir = (player.position - transform.position).normalized;
//이동
cc.Move(dir * moveSpeed * Time.deltaTime);
}
else
{
m_State = EnemyState.Attack;
Debug.Log("공격!");
//공격이 바로 안되므로 공격 딜레이 시간 만큼 미리 진행을 시켜놓아야 한다.
currentTime = attackDelay;
}
}
void Attack()
{
//플레이어와 적의 거리가 공격 범위 이내라면 공격
if(Vector3.Distance(transform.position, player.position) < attackDistance)
{
//일정 시간마다 플레이어 공격
currentTime += Time.deltaTime;
if(currentTime > attackDelay)
{
player.GetComponent<PlayerMove>().DamageAction(attackPower);
print("공격!");
currentTime = 0;
}
}
//그렇지 않다면, Move();
else
{
m_State = EnemyState.Move;
Debug.Log("이동");
currentTime = 0;
}
}
void Return()
{
//오리지널 방향으로 돌아가기 특정 좌표값보다 범위로 나타내는게 에러가 덜 날 가능성이 높다.
if(Vector3.Distance(transform.position, originPos) > 0.1f)
{
//방향 구하기 (목적지 - 내 위치)
Vector3 dir = (originPos - transform.position).normalized;
//이동하기
cc.Move(dir * moveSpeed * Time.deltaTime);
}
else //그렇지 않다면 적 위치를 초기 위치로 조정하고, 대기 상태로 전환한다.
{
transform.position = originPos;
m_State = EnemyState.Idle;
Debug.Log("상태 전환: Return -> Idle");
}
}
}
피격 상태 구현 -Coroutine 2초동안 기다려 같은 Delay
yield return이 적어도 1개는 있어야한다.
사용을 위해서는 코루틴 함수를 따로 만들어야 한다.
맞았을 때 피 이미지 등장 깜빡 2초 뒤에 Set.Active(false)로 꺼지게 한다.
EnemyFSM 스크립트에 구현한다.
PlayerFire 스크립트에서 EnemyFSM 적 체력에 접근하여 체력을 줄일 예정.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyFSM : MonoBehaviour
{
//적 상태 상수 6개 생성
enum EnemyState
{
Idle,
Move,
Attack,
Return,
Damaged,
Die
}
//적 상태 변수
EnemyState m_State;
//플레이어 발견 범위
public float findDistance = 10f;
//플레이어 Transform Component 적이 많이 생성되면 끌어 넣는게 비어있을 수 있다. Find로 찾아서 적용
Transform player;
//공격 범위
public float attackDistance = 4f;
//적 이동 속도
public float moveSpeed = 5f;
//적 캐릭터 컨트롤러 컴포넌트
CharacterController cc;
//적 공격 누적 시간
float currentTime = 0;
//적 공격 딜레이 시간
float attackDelay = 2f;
//적 공격력
public int attackPower = 10;
//적이 다시 되돌아갈 초기 위치 저장
Vector3 originPos;
//적 이동 가능 범위
public float moveDistance = 20f;
//적 체력 설정
public int hp = 50;
void Start()
{
//플레이어 Transform Component 할당
player = GameObject.Find("Player").transform;
//최초의 적 상태를 대기로 설정
m_State = EnemyState.Idle;
//적 캐릭터 컨트롤러 컴포넌트 할당
cc = GetComponent<CharacterController>();
//적의 초기 위치 저장
originPos = transform.position;
}
void Update()
{
//적의 상태를 체크해서 상태별로 정해진 기능을 수행 Switch문 / Damaged와 Die는 AnyState이기 때문에 case에 들어가지 않는다.
switch (m_State)
{
case EnemyState.Idle:
Idle();
break;
case EnemyState.Move:
Move();
break;
case EnemyState.Attack:
Attack();
break;
case EnemyState.Return:
Return();
break;
}
}
void Idle()
{
//만약 플레이어와 적의 거리가 발견 범위 이내라면 Move 상태로 전환
if(Vector3.Distance(transform.position, player.position) < findDistance)
{
m_State = EnemyState.Move;
Debug.Log("발견!");
}
}
void Move()
{
//만약 현재 위치와 초기 위치 거리가 이동 가능 범위보다 크면 복귀
if(Vector3.Distance(transform.position, originPos) > moveDistance)
{
m_State = EnemyState.Return;
Debug.Log("상태 전환");
}
//만약 플레이어와 적의 거리가 공격 범위보다 크다면 플레이어를 향해 이동
else if (Vector3.Distance(transform.position, player.position) > attackDistance)
{
//이동 방향
Vector3 dir = (player.position - transform.position).normalized;
//이동
cc.Move(dir * moveSpeed * Time.deltaTime);
}
else
{
m_State = EnemyState.Attack;
Debug.Log("공격!");
//공격이 바로 안되므로 공격 딜레이 시간 만큼 미리 진행을 시켜놓아야 한다.
currentTime = attackDelay;
}
}
void Attack()
{
//플레이어와 적의 거리가 공격 범위 이내라면 공격
if(Vector3.Distance(transform.position, player.position) < attackDistance)
{
//일정 시간마다 플레이어 공격
currentTime += Time.deltaTime;
if(currentTime > attackDelay)
{
player.GetComponent<PlayerMove>().DamageAction(attackPower);
print("공격!");
currentTime = 0;
}
}
//그렇지 않다면, Move();
else
{
m_State = EnemyState.Move;
Debug.Log("이동");
currentTime = 0;
}
}
void Return()
{
//오리지널 방향으로 돌아가기 특정 좌표값보다 범위로 나타내는게 에러가 덜 날 가능성이 높다.
if(Vector3.Distance(transform.position, originPos) > 0.1f)
{
//방향 구하기 (목적지 - 내 위치)
Vector3 dir = (originPos - transform.position).normalized;
//이동하기
cc.Move(dir * moveSpeed * Time.deltaTime);
}
else //그렇지 않다면 적 위치를 초기 위치로 조정하고, 대기 상태로 전환한다.
{
transform.position = originPos;
m_State = EnemyState.Idle;
Debug.Log("상태 전환: Return -> Idle");
}
}
//데미지 처리 Coroutine 함수
IEnumerator DamageProcess()
{
//피격 모션만큼 기다림 애니메이션 고려
yield return new WaitForSeconds(0.5f);
//이동 상태 전환
m_State = EnemyState.Move;
}
void Damaged()
{
//피격 코루틴 실행
StartCoroutine(DamageProcess());
}
//데미지 실행 함수
public void HitEnemy(int hitPower)
{
//플레이어의 공격력만큼 적 체력 감소
hp -= hitPower;
}
}
PlayerFire 스크립트에서 적 체력을 닳게 할 수 있다. (맞은 대상이 적이라면 체력을 깎아라 / Enemy Layer로 구분)
using System.Collections;
using System.Collections.Generic;
using System.Net;
using UnityEngine;
public class PlayerFire : MonoBehaviour
{
//폭탄 발사 위치 정하기
public GameObject firePosition;
//폭탄 오브젝트 가져오기
public GameObject bombs;
//투척 파워
public float throwPower = 10f;
//폭탄 제한 시간
float limitTime = 1f;
//폭탄 현재 시간
float currentTime = 0;
//총알 이펙트
public GameObject bulletEffect;
//파티클 시스템 가져오기
ParticleSystem ps;
//총 공격력
public int gunPower = 10;
//총 불꽃 위치
public GameObject gunFirePosition;
//총 불꽃 이펙트
public GameObject gunFires;
private void Start()
{
//총알 이펙트의 파티클 시스템 가져오기
ps = bulletEffect.GetComponent<ParticleSystem>();
}
void Update()
{
//마우스 오른쪽 버튼 입력
if(Input.GetMouseButtonDown(1) && currentTime > limitTime)
{
//폭탄 생성
GameObject bomb = Instantiate(bombs);
//폭탄의 위치를 발사 위치로 이동
bomb.transform.position = firePosition.transform.position;
//폭탄의 Rigid Body 컴포넌트를 가져옴
Rigidbody rb = bomb.GetComponent<Rigidbody>();
//카메라의 정면으로 폭탄에 힘을 가해서 던지기/ForceMode는 질량과 힘을 모두 생각함
rb.AddForce(Camera.main.transform.forward * throwPower, ForceMode.Impulse);
//현재 시간 초기화
currentTime = 0;
}
currentTime += Time.deltaTime;
//마우스 왼쪽 버튼 입력
if (Input.GetMouseButtonDown(0))
{
//Ray 생성 후 위치와 방향 설정
Ray ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward);
//Ray가 부딪힌 대상 저장
RaycastHit hitInfo = new RaycastHit();
//Ray를 발사한 후 부딪힌 물체가 있으면 총알 이펙트 생성
if(Physics.Raycast(ray, out hitInfo))
{
//만약 부딪힌 대상의 Layer가 Enemy라면
if (hitInfo.transform.gameObject.layer == LayerMask.NameToLayer("Enemy"))
{
//부딪힌 대상(=Enemy)의 EnemyFSM의 HitEnemy 함수를 실행
EnemyFSM eFSM = hitInfo.transform.GetComponent<EnemyFSM>();
eFSM.HitEnemy(gunPower);
}
bulletEffect.transform.position = hitInfo.point; //좌표 설정
bulletEffect.transform.forward = hitInfo.normal; //총알 효과를 Ray가 부딪힌 지점의 법선 벡터와 일치하도록 설정
ps.Play(); //파티클 플레이
}
//총구 화염
GameObject gunFire = Instantiate(gunFires);
gunFire.transform.position = gunFirePosition.transform.position;
}
}
}
Die 함수 추가 -Coroutine 사용(적이 쓰러지자마자 없어지는 것 방지)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyFSM : MonoBehaviour
{
//적 상태 상수 6개 생성
enum EnemyState
{
Idle,
Move,
Attack,
Return,
Damaged,
Die
}
//적 상태 변수
EnemyState m_State;
//플레이어 발견 범위
public float findDistance = 10f;
//플레이어 Transform Component 적이 많이 생성되면 끌어 넣는게 비어있을 수 있다. Find로 찾아서 적용
Transform player;
//공격 범위
public float attackDistance = 4f;
//적 이동 속도
public float moveSpeed = 5f;
//적 캐릭터 컨트롤러 컴포넌트
CharacterController cc;
//적 공격 누적 시간
float currentTime = 0;
//적 공격 딜레이 시간
float attackDelay = 2f;
//적 공격력
public int attackPower = 10;
//적이 다시 되돌아갈 초기 위치 저장
Vector3 originPos;
//적 이동 가능 범위
public float moveDistance = 20f;
//적 체력 설정
public int hp = 50;
void Start()
{
//플레이어 Transform Component 할당
player = GameObject.Find("Player").transform;
//최초의 적 상태를 대기로 설정
m_State = EnemyState.Idle;
//적 캐릭터 컨트롤러 컴포넌트 할당
cc = GetComponent<CharacterController>();
//적의 초기 위치 저장
originPos = transform.position;
}
void Update()
{
//적의 상태를 체크해서 상태별로 정해진 기능을 수행 Switch문 / Damaged와 Die는 AnyState이기 때문에 case에 들어가지 않는다.
switch (m_State)
{
case EnemyState.Idle:
Idle();
break;
case EnemyState.Move:
Move();
break;
case EnemyState.Attack:
Attack();
break;
case EnemyState.Return:
Return();
break;
}
}
void Idle()
{
//만약 플레이어와 적의 거리가 발견 범위 이내라면 Move 상태로 전환
if(Vector3.Distance(transform.position, player.position) < findDistance)
{
m_State = EnemyState.Move;
Debug.Log("발견!");
}
}
void Move()
{
//만약 현재 위치와 초기 위치 거리가 이동 가능 범위보다 크면 복귀
if(Vector3.Distance(transform.position, originPos) > moveDistance)
{
m_State = EnemyState.Return;
Debug.Log("상태 전환");
}
//만약 플레이어와 적의 거리가 공격 범위보다 크다면 플레이어를 향해 이동
else if (Vector3.Distance(transform.position, player.position) > attackDistance)
{
//이동 방향
Vector3 dir = (player.position - transform.position).normalized;
//이동
cc.Move(dir * moveSpeed * Time.deltaTime);
}
else
{
m_State = EnemyState.Attack;
Debug.Log("공격!");
//공격이 바로 안되므로 공격 딜레이 시간 만큼 미리 진행을 시켜놓아야 한다.
currentTime = attackDelay;
}
}
void Attack()
{
//플레이어와 적의 거리가 공격 범위 이내라면 공격
if(Vector3.Distance(transform.position, player.position) < attackDistance)
{
//일정 시간마다 플레이어 공격
currentTime += Time.deltaTime;
if(currentTime > attackDelay)
{
player.GetComponent<PlayerMove>().DamageAction(attackPower);
print("공격!");
currentTime = 0;
}
}
//그렇지 않다면, Move();
else
{
m_State = EnemyState.Move;
Debug.Log("이동");
currentTime = 0;
}
}
void Return()
{
//오리지널 방향으로 돌아가기 특정 좌표값보다 범위로 나타내는게 에러가 덜 날 가능성이 높다.
if(Vector3.Distance(transform.position, originPos) > 0.1f)
{
//방향 구하기 (목적지 - 내 위치)
Vector3 dir = (originPos - transform.position).normalized;
//이동하기
cc.Move(dir * moveSpeed * Time.deltaTime);
}
else //그렇지 않다면 적 위치를 초기 위치로 조정하고, 대기 상태로 전환한다.
{
transform.position = originPos;
m_State = EnemyState.Idle;
Debug.Log("상태 전환: Return -> Idle");
}
}
//데미지 처리 Coroutine 함수
IEnumerator DamageProcess()
{
//피격 모션만큼 기다림 애니메이션 고려
yield return new WaitForSeconds(0.5f);
//이동 상태 전환
m_State = EnemyState.Move;
}
void Damaged()
{
//피격 코루틴 실행
StartCoroutine(DamageProcess());
}
//데미지 실행 함수
public void HitEnemy(int hitPower)
{
//적이 피격 상태이면 플레이어를 때릴 수 없게
if(m_State == EnemyState.Damaged)
{
return;
}
//플레이어의 공격력만큼 적 체력 감소
hp -= hitPower;
//적 체력이 0보다 크면 피격
if(hp > 0)
{
m_State = EnemyState.Damaged;
Damaged(); //코루틴 호출
Debug.Log("적 체력 표시: " + hp);
}
//0보다 작으면 죽음
else
{
m_State = EnemyState.Die;
Debug.Log("죽음");
Die();
}
IEnumerator DieProcess()
{
//적 캐릭터 컨트롤러 컴포넌트 비활성화
cc.enabled = false;
//2초 대기
yield return new WaitForSeconds(3f);
//적 제거
Destroy(gameObject);
}
void Die()
{
//실행 중인 이전 Coroutine 중지
StopAllCoroutines();
//죽음 Coroutine 실행
StartCoroutine(DieProcess());
}
}
}
'SKKU DT' 카테고리의 다른 글
[SKKU DT] 13일차 -FPS 게임 만들기(5) -UI 데미지 입을 때, Ready,Go 텍스트 (0) | 2023.11.15 |
---|---|
[SKKU DT] 12일차 -FPS 게임 만들기(4) -체력 바 UI 구현 (0) | 2023.11.14 |
[SKKU DT] 11일차 -FPS 게임 만들기(2) -무기 만들기(폭탄, 총) (0) | 2023.11.13 |
[SKKU DT] 11일차 -FPS 게임 만들기(1) -캐릭터 이동 (0) | 2023.11.13 |
[SKKU DT] 10일차 -프로빌더 도면 기반 집만들기 (0) | 2023.11.10 |