적과 플레이어 간의 공통 요소를 만들기 위해 캐릭터라는 프리팹을 만들고
적과 플레이어는 캐릭터 프리팹이 들어간 중첩 프리팹으로 만들 것
프리팹은 게임 오브젝트를 모아놓은 것이고,
게임 오브젝트들에는 컴포넌트가 붙어있고,
프로퍼티 오버라이드가 기록된다
Transform 컴포넌트의 Parent 프로퍼티를 통해 계층 구조가 저장된다
프리팹 안에 프리팹 넣으면 인스턴스가 들어가고,
프리팹의 모든 요소를 가져오는게 아닌 수정사항들만 기록된다
Prefab Variant를 만들면 다른 프리팹을 기반으로 하는 프리팹을 만들 수 있다.
원본 프리팹이 변경되면 Prefab Variant도 변경된다.
Prefab Variant를 변경한 뒤 원본 프리팹에 Apply할 수도 있다.
Prefab Variant의 Prefab Variant를 만들 수도 있다.

Animator의 Any State는 '다른 모든 상태'를 의미한다.
Any State를 활용하면 애니메이션을 여러 개 연결하지 않고도 애니메이션을 관리할 수 있다.
private void Die()
{
if (!isDead) GetComponent<Animator>().SetTrigger("die");
isDead = true;
}
isDead bool 변수를 통해 죽는 애니메이션 여러 번 재생되지 않게 함
현재 Attack 애니메이션은 특별한 조건 없이 Has Exit Time을 통해,
공격 애니메이션이 전부 끝나면 다음 애니메이션으로 돌아가도록 되어 있다.
그래서 공격 도중에 이동을 하더라도 공격 애니메이션이 끝나지 않는다.
이를 해결하기 위해 우선 공격 애니메이션에서 이동 애니메이션으로 가는 전환 화살표를 하나 더 만든다.
그리고 새로 만든 전환에서 Has Exit Time을 체크 해제하고, 조건을 붙인다.
public void Cancel()
{
target = null;
GetComponent<Animator>().SetTrigger("stopAttack");
}
IAction()에 의해 구현해야 하는 Cancel()에서 해당 조건을 설정해준다.
동작이 중간에 멈추는 등 여러 버그가 발생할 수 있는데, 그건 앞으로 다룰 것.
(애니메이션 전환 새로 만드니까 어느 정도 해결되긴 함)
또한, 죽은 적에게도 계속 공격을 하게 된다.
bool isDead = false;
public bool IsDead()
{
return isDead;
}
우선 이전에 만든 isDead를 다른 메서드에서도 접근할 수 있게 한다.
Fighter에서 사용하고 있던 target의 자료형을 Transform에서 Health로 바꾸고,
target.position을 target.transform.position으로 바꿔주는 등 Health에 맞게 코드를 바꿔준다.
private void Update()
{
timeSinceLastAttack += Time.deltaTime;
if (target == null) return;
if (target.IsDead()) return;
Fighter.cs에서 target.IsDead() 을 호출하여 죽었다면 공격을 하지 않게 조건문을 만든다.
namespace RPG.Combat
{
[RequireComponent(typeof(Health))]
public class CombatTarget : MonoBehaviour
{
}
}
모든 Enemy는 Health를 갖고 있어야 하므로,
RequireComponent를 통해 Health라는 컴포넌트를 갖고 있도록 보장한다.

이제 CombatTarget.cs를 컴포넌트로 추가하면 Health.cs도 자동으로 추가된다.
삭제하려고 해도 삭제가 안된다. (원래 있던 오브젝트들에 사후적으로 반영되진 않는듯)
공격할 때 적을 바라보게 하기 위해 Transform.LookAt을 사용한다.
게임 오브젝트의 transform을 회전시켜서 그 오브젝트의 forward 벡터가 타겟의 현재 위치를 가리키게 한다.
죽은 적의 콜라이더가 클릭 가로막는 현상 해결하기
public bool CanAttack(CombatTarget combatTarget)
{
if (combatTarget == null) return false;
Health targetToTest = combatTarget.GetComponent<Health>();
return targetToTest != null && !targetToTest.IsDead();
}
왜 그런진 모르겠지만 굳이 Fighter.cs에 CanAttack()을 넣어주고
foreach (RaycastHit hit in hits)
{
CombatTarget combatTarget = hit.transform.GetComponent<CombatTarget>();
if (!GetComponent<Fighter>().CanAttack(combatTarget)) continue;
PlayerController.cs의 foreach 문에서 호출하여 continue를 결정한다.
분류상 공격에 속하니까 PlayerController에 넣으면 뭔가 이상하기도 하고 if문 추가로 엮기 위해서 Fighter.cs에 넣은듯
게임을 부수거나 짜증나게 하는 버그는 반드시 고치고 넘어가야 하겠지만,
보기에 안 좋아보일 뿐인 버그들은 적어놓고 나중에 시간이 나면 고쳐라.
아까 전환 화살표를 2개 만들 때 SetTrigger()을 통해 전환시키는 코드를 추가했는데,
공격 중간에 이동을 해버리면 트리거가 소비되지 않고 애니메이션이 전환되어버리기 때문에
다시 공격하면 공격 애니메이션이 곧바로 취소되어버린다.
공격할 때 ResetTrigger()을 호출하여 트리거를 비활성화시키면 된다.