private NavMeshAgent navMeshAgent; // 경로계산 AI 에이전트
public ParticleSystem hitEffect; // 피격시 재생할 파티클 효과 public AudioClip deathSound; // 사망시 재생할 소리 public AudioClip hitSound; // 피격시 재생할 소리
private Animator zombieAnimator; // 애니메이터 컴포넌트, 여기서는 사용안함 private AudioSource zombieAudioPlayer; // 오디오 소스 컴포넌트, 효과음 재생을 위 private Renderer zombieRenderer; // 렌더러 컴포넌트, 좀비 색을 변경시 사용
public float damage = 20f; // 공격력 public float timeBetAttack = 0.5f; // 공격 간격 private float lastAttackTime; // 마지막 공격 시점
추적할 대상이 존재하는지 알려주는 프로퍼티, targetEntity이고 죽지 않을 겨우만 true이므로 생명체를 체크할수 있음
// 추적할 대상이 존재하는지 알려주는 프로퍼티
private bool hasTarget {
get {
// 추적할 대상이 존재하고, 대상이 사망하지 않았다면 true
if (targetEntity != null && !targetEntity.dead) {
return true;
}
return false; // 그렇지 않다면 false
}
}
private void Awake() {} 사용할 컴포넌트들을 연결합니다.
public void Setup(ZombieData zombieData) {} 좀비의 능력치를 초기화 합니다.
private void Start( UpdatePath() ;) { // 게임 오브젝트 활성화와 동시에 AI의 추적 루틴 시작 }
private void Update() { // 추적 대상의 존재 여부에 따라 다른 애니메이션을 재생 }
private IEnumerator UpdatePath() { // 주기적으로 추적할 대상의 위치를 찾아 경로를 갱신 }
타겟도 이동중이므로 타겟이 존재한다면 타겟의 위치를 갱신한다.
// 추적 대상 존재 : 경로를 갱신하고 AI 이동을 계속 진행 navMeshAgent.isStopped = false; navMeshAgent.SetDestination(targetEntity.transform.position);
private IEnumerator UpdatePath() {
// 살아있는 동안 무한 루프
while (!dead)
{
if (hasTarget)
{
// 추적 대상 존재 : 경로를 갱신하고 AI 이동을 계속 진행
navMeshAgent.isStopped = false;
navMeshAgent.SetDestination(
targetEntity.transform.position);
}
else
{
// 추적 대상 없음 : AI 이동 중지
navMeshAgent.isStopped = true;
// 20 유닛의 반지름을 가진 가상의 구를 그렸을때, 구와 겹치는 모든 콜라이더를 가져옴
// 단, whatIsTarget 레이어를 가진 콜라이더만 가져오도록 필터링
Collider[] colliders =
Physics.OverlapSphere(transform.position, 20f, whatIsTarget);
// 모든 콜라이더들을 순회하면서, 살아있는 LivingEntity 찾기
for (int i = 0; i < colliders.Length; i++)
{
// 콜라이더로부터 LivingEntity 컴포넌트 가져오기
LivingEntity livingEntity = colliders[i].GetComponent<LivingEntity>();
// LivingEntity 컴포넌트가 존재하며, 해당 LivingEntity가 살아있다면,
if (livingEntity != null && !livingEntity.dead)
{
// 추적 대상을 해당 LivingEntity로 설정
targetEntity = livingEntity;
// for문 루프 즉시 정지
break;
}
}
}
// 0.25초 주기로 처리 반복
yield return new WaitForSeconds(0.25f);
}
}
public override void OnDamage(float damage, } // 데미지를 입었을때 실행할 처리
public override void Die() { // LivingEntity의 Die()를 실행하여 기본 사망 처리 실행}
private void OnTriggerStay(Collider other) { // 자신이 사망하지 않았으며, // 최근 공격 시점에서 timeBetAttack 이상 시간이 지났다면 공격 가능 }
Player를 선택하고Layer를 PLAYER로 바꿉니다. 모든 child에 적용할거냐는 질문에 No 합니다.
using UnityEngine;
using UnityEngine.UI; // UI 관련 코드
// 플레이어 캐릭터의 생명체로서의 동작을 담당
public class PlayerHealth : LivingEntity {
public Slider healthSlider; // 체력을 표시할 UI 슬라이더
public AudioClip deathClip; // 사망 소리
public AudioClip hitClip; // 피격 소리
public AudioClip itemPickupClip; // 아이템 습득 소리
private AudioSource playerAudioPlayer; // 플레이어 소리 재생기
private Animator playerAnimator; // 플레이어의 애니메이터
private PlayerMovement playerMovement; // 플레이어 움직임 컴포넌트
private PlayerShooter playerShooter; // 플레이어 슈터 컴포넌트
private void Awake() {
// 사용할 컴포넌트를 가져오기
playerAnimator = GetComponent<Animator>();
playerAudioPlayer = GetComponent<AudioSource>();
playerMovement = GetComponent<PlayerMovement>();
playerShooter = GetComponent<PlayerShooter>();
}
protected override void OnEnable() {
// LivingEntity의 OnEnable() 실행 (상태 초기화)
base.OnEnable();
// 체력 슬라이더 활성화
healthSlider.gameObject.SetActive(true);
// 체력 슬라이더의 최대값을 기본 체력값으로 변경
healthSlider.maxValue = startingHealth;
// 체력 슬라이더의 값을 현재 체력값으로 변경
healthSlider.value = health;
// 플레이어 조작을 받는 컴포넌트들 활성화
playerMovement.enabled = true;
playerShooter.enabled = true;
}
// 체력 회복
public override void RestoreHealth(float newHealth) {
// LivingEntity의 RestoreHealth() 실행 (체력 증가)
base.RestoreHealth(newHealth);
// 체력 갱신
healthSlider.value = health;
}
// 데미지 처리
public override void OnDamage(float damage, Vector3 hitPoint,
Vector3 hitDirection) {
if (!dead)
{
// 사망하지 않은 경우에만 효과음을 재생
playerAudioPlayer.PlayOneShot(hitClip);
}
// LivingEntity의 OnDamage() 실행(데미지 적용)
base.OnDamage(damage, hitPoint, hitDirection);
// 갱신된 체력을 체력 슬라이더에 반영
healthSlider.value = health;
}
// 사망 처리
public override void Die() {
// LivingEntity의 Die() 실행(사망 적용)
base.Die();
// 체력 슬라이더 비활성화
healthSlider.gameObject.SetActive(false);
// 사망음 재생
playerAudioPlayer.PlayOneShot(deathClip);
// 애니메이터의 Die 트리거를 발동시켜 사망 애니메이션 재생
playerAnimator.SetTrigger("Die");
// 플레이어 조작을 받는 컴포넌트들 비활성화
playerMovement.enabled = false;
playerShooter.enabled = false;
}
private void OnTriggerEnter(Collider other) {
// 아이템과 충돌한 경우 해당 아이템을 사용하는 처리
// 사망하지 않은 경우에만 아이템 사용가능
if (!dead)
{
// 충돌한 상대방으로 부터 Item 컴포넌트를 가져오기 시도
IItem item = other.GetComponent<IItem>();
// 충돌한 상대방으로부터 Item 컴포넌트가 가져오는데 성공했다면
if (item != null)
{
// Use 메서드를 실행하여 아이템 사용
item.Use(gameObject);
// 아이템 습득 소리 재생
playerAudioPlayer.PlayOneShot(itemPickupClip);
}
}
}
}