안녕하세요 유랑입니다.
실력향상을 위해 오늘도 유튜브와 함께 공부하겠습니다.
궁금하신 사항은 댓글로 남겨주세요^^
1. 탑다운 촬영 따라하기
이 강의 이것은 Sebastian Lague가 만든 예입니다.
자세한 내용은 YouTube를 시청하면 알 수 있습니다.
유튜브 사이트 => 유튜브
1-1) 게임 종료
이번에는 캐릭터가 죽으면 적의 움직임이
조정합시다.
1-2) 스크립트 작성 –㉠Idamageable
Idamageable 스크립트에 TakeDamage라는 메서드를 추가해 보겠습니다.
TakeHit의 기능이 있지만 레이캐스트 정보를 받지 않을때 사용할 생각입니다!!
1-3) 스크립트 작성 -㉡LivingEntity
Idamageable에서 상속되는 LivingEntity 스크립트
TakeHit 및 TakeDamage에 대한 기능을 정의합니다.
1-4) 스크립트 작성 -㉢Enemy
Enemy 스크립트에서 플레이어에게 피해를 주는 부분과
플레이어가 죽을 때 움직임에 대해 뭔가를 추가해 봅시다.
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
[RequireComponent(typeof(NavMeshAgent))]
public class Enemy : LivingEntity
{
// 상태 (기본, 추격, 공격)
public enum State{Idle, Chasing, Attacking};
State currentState; // 현재 상태
NavMeshAgent pathfinder;
Transform target;
LivingEntity targetEntity;
Material skinMaterial;
Color originColor;
float attackDistanceThreshold = 0.5f; // 공격 사정거리
float timeBetweenAttacks = 1; // 공격 딜레이
float damage = 1; // 공격 데미지
float nextAttackTime; // 다음 공격이 가능한 시간
float myCollisionRadius; // 자신의 충돌 범위
float targetCollisionRadius; // 목표의 충돌 범위
bool hasTarget; // 공격 타겟의 여부
protected override void Start()
{
base.Start();
pathfinder = GetComponent<NavMeshAgent>();
skinMaterial = GetComponent<Renderer>().material;
originColor = skinMaterial.color;
if (GameObject.FindGameObjectWithTag("Player") != null)
{
currentState = State.Chasing;
hasTarget = true;
target = GameObject.FindGameObjectWithTag("Player").transform;
targetEntity = target.GetComponent<LivingEntity>();
targetEntity.OnDeath += OnTargetDeath;
myCollisionRadius = GetComponent<CapsuleCollider>().radius;
targetCollisionRadius = target.GetComponent<CapsuleCollider>().radius;
StartCoroutine(UpdatePath());
}
}
// 타겟 사망시 정지
void OnTargetDeath()
{
hasTarget = false;
currentState = State.Idle;
}
void Update()
{
if (hasTarget)
{
if (Time.time > nextAttackTime)
{
// (목표 위치 - 자신의 위치) 제곱을 한 수
float sqrDstToTarget = (target.position - transform.position).sqrMagnitude;
if (sqrDstToTarget < Mathf.Pow(attackDistanceThreshold + myCollisionRadius + targetCollisionRadius, 2))
{
nextAttackTime = Time.time + timeBetweenAttacks;
StartCoroutine(Attack());
}
}
}
}
// 적 공격
IEnumerator Attack()
{
currentState = State.Attacking;
pathfinder.enabled = false; // 네비게이션 추적 종료
Vector3 originalPosition = transform.position;
Vector3 dirToTarget = (target.position - transform.position).normalized;
Vector3 attackPosition = target.position - dirToTarget * (myCollisionRadius);
float attackSpeed = 3;
float percent = 0;
skinMaterial.color = Color.red;
bool hasAppliedDamage = false; // 데미지를 적용하는 도중인가
while (percent <= 1)
{
if(percent >= 0.5f && !hasAppliedDamage)
{
hasAppliedDamage = true;
targetEntity.TakeDamage(damage);
}
percent += Time.deltaTime * attackSpeed;
float interpolation = (-Mathf.Pow(percent, 2) + percent) * 4;
transform.position = Vector3.Lerp(originalPosition, attackPosition, interpolation);
yield return null;
}
skinMaterial.color = originColor;
currentState = State.Chasing;
pathfinder.enabled = true; // 네비게이션 추적 시작
}
// 적 추적
IEnumerator UpdatePath()
{
float refreshRate = 0.25f;
while (hasTarget)
{
if (currentState == State.Chasing)
{
Vector3 dirToTarget = (target.position - transform.position).normalized;
Vector3 targetPosition = target.position - dirToTarget * (myCollisionRadius + targetCollisionRadius + attackDistanceThreshold/2);
if (!dead)
{
pathfinder.SetDestination(targetPosition); // 네비게이션 목표 설정
}
}
yield return new WaitForSeconds(refreshRate);
}
}
}
Target이 죽었는지 감지하기 위해 LivingEntity 스크립트 정보를 가져옵니다.
그리고 공격 데미지와 공격 대상 유무에 대한 정보,
대상이 죽으면 OnTargetDeath라는 메서드가 실행됩니다. 그럴게요.
OnTargetDeath는 대상이 죽으면 멈추도록 정의되어 있으며,
업데이트에서 대상이 없으면 공격하지 않도록 넣어둡니다.
물론 적을 추격하는 코드에 적이 없으면 안되도록 넣어두겠습니다^^
마지막으로 데미지 적용 여부에 따라 데미지를 추가하는 코드를 추가하겠습니다.
이제 플레이어를 손상시킬 수 있습니다.
테스트를 위해 플레이어 건강을 3으로 변경합니다.
적에게 3번 맞으면 플레이어는 죽거나 사라집니다.
적은 유휴 상태에서 유휴 상태로 유지됩니다.
1-5) 스크립트 작성 -㉣Projectile
총알이 사라지고 적을 관통하지 않도록 하는 코드를 추가해 보겠습니다.
적이 빨리 오면 충돌 감지가 제대로 작동하지 않을 수 있습니다.
skinWidth를 통해 오차 범위에 적용됩니다.
그리고 총알이 생성될 때 이미 적과 겹치는 경우
Physics.OverlapSphere를 통해 겹치는 오브젝트에 손상이 적용됩니다.
충돌체에 대한 손상 방법도 만들겠습니다!!
총알 없음,
플레이어는 적에게 맞은 후 사라졌습니다.
2. 마침
오늘 강의는 여기서 마치겠습니다.
탑다운 슈팅을 카피하면서 게임을 끝내버렸습니다.
감사합니다
수업 자료: 탑다운 슈팅 튜토리얼 #7 게임 종료