ImageHit, 화면을 뒤덮는 UI를 생성하여 Enemy에게 공격 당했을 때 깜빡이게 한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 태어날 때 ImageHit를 보이지 않게 하고싶다.
// 적이 플레이어를 공격했을 때 ImageHit를 깜빡이게 하고싶다.
public class HitManager : MonoBehaviour
{
public static HitManager instance;
private void Awake()
{
instance = this;
}
public GameObject imageHit;
// Start is called before the first frame update
void Start()
{
// 태어날 때 imageHit 를 보이지 않게 하고싶다.
imageHit.SetActive(false);
}
public void Hit()
{
// 깜빡거리고싶다.
StartCoroutine("IeHit");
}
IEnumerator IeHit()
{
// imgaHit를 보이게 하고 싶다
imageHit.SetActive(true);
// 0.1초 후에
yield return new WaitForSeconds(0.1f);
// imageHit를 안 보이게 하고 싶다.
imageHit.SetActive(false);
}
// Update is called once per frame
void Update()
{
}
}
코루틴(Coroutine) : IEnumerator
루틴이란 함수와 같은 개념
함께 동작하는 함수. 즉 "동시에 실행되는 함수" 라는 의미를 가지고 있다.
여러개의 진입점을 가진다.
Singleton 패턴
단 하나의 객체(인스턴스)를 생성해서 사용하는 디자인 패턴
미리 선언해둔 Hit함수를 Enemy에서 호출하고, 플레이어hp에서 AddDamage를 호출한다.
if (currentTime > attackTime)
{
// 현재시간을 초기화하고
currentTime = 0;
// 만약 target이 공격거리 밖에 있으면 Move상태로 전이하고싶다.
// 나와 target의 거리를 구해서
float distance = Vector3.Distance(transform.position, target.transform.position);
// 만약 그 거리가 공격거리보다 크다면
if (distance > attackDistance)
{
// Move상태로 전이하고싶다.
state = State.Move;
}
// 공격 성공
else
{
// 플레이어를 공격하고
php.AddDamage();
// HitManager의 Hit 함수를 호출하고싶다.
HitManager.instance.Hit();
}
}
Enemy 전문
더보기
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// FSM으로 상태를 제어하고싶다.
// 정지, 이동, 공격, 죽음
public class Enemy : MonoBehaviour
{
public float speed = 1;
public float findDistance = 5;
public float attackDistance = 1.5f;
public float traceDistance = 15;
enum State
{
Idle,
Move,
Attack,
Die,
Return
}
State state;
PlayerHP php;
GameObject target;
float currentTime;
float attackTime = 1;
Vector3 originPosition;
// Start is called before the first frame update
void Start()
{
state = State.Idle;
target = GameObject.Find("Player");
php = target.GetComponent<PlayerHP>();
// 최초 위치를 originPosition 변수에 저장한다.
originPosition = transform.position;
}
// Update is called once per frame
void Update()
{
if (state == State.Idle)
{
UpdateIdle();
}
else if (state == State.Move)
{
UpdateMove();
}
else if (state == State.Attack)
{
UpdateAttack();
}
else if (state == State.Return)
{
UpdateReturn();
}
}
private void UpdateIdle()
{
// 나와 target의 거리를 구해서
float distance = Vector3.Distance(transform.position, target.transform.position);
// 만약 그 거리가 감지거리보다 작으면
if (distance < findDistance)
{
// Move상태로 전이하고싶다.
state = State.Move;
}
}
private void UpdateMove()
{
// 현재 위치가 최대 추적 가능 거리를 넘어갔는지 여부를 판단한다.
float trace = Vector3.Distance(originPosition, transform.position);
// 만일, 최대 추적 가능 거리를 넘어갔다면 상태를 복귀 상태로 전환한다.
if (trace > traceDistance)
{
state = State.Return;
}
// target방향으로 이동하다가
Vector3 dir = target.transform.position - transform.position;
dir.Normalize();
transform.position += dir * speed * Time.deltaTime;
// 나와 target의 거리를 구해서
float distance = Vector3.Distance(transform.position, target.transform.position);
// 만약 그 거리가 공격거리보다 작으면
if (distance < attackDistance)
{
// Attack으로 전이하고싶다.
state = State.Attack;
}
}
private void UpdateAttack()
{
// 시간이 흐르다가
currentTime += Time.deltaTime;
// 만약 현재시간이 공격시간이 되면
if (currentTime > attackTime)
{
// 현재시간을 초기화하고
currentTime = 0;
// 만약 target이 공격거리 밖에 있으면 Move상태로 전이하고싶다.
// 나와 target의 거리를 구해서
float distance = Vector3.Distance(transform.position, target.transform.position);
// 만약 그 거리가 공격거리보다 크다면
if (distance > attackDistance)
{
// Move상태로 전이하고싶다.
state = State.Move;
}
// 공격 성공
else
{
// 플레이어를 공격하고
php.AddDamage();
// HitManager의 Hit 함수를 호출하고싶다.
HitManager.instance.Hit();
}
}
}
public void AddDamage (int damage)
{
Destroy(gameObject);
}
void UpdateReturn()
{
// 만일, 나의 현재 위치가 originPosition 위치에서 10센티미터 이상이라면
Vector3 dir = originPosition - transform.position;
if (dir.magnitude > 0.1f)
{
// originPosition 방향으로 이동한다.
transform.position += dir.normalized * speed * Time.deltaTime;
}
// 그렇지 않다면, 나의 위치를 originPosition으로 설정한다.
else
{
transform.position = originPosition;
// 상태를 다시 대기 상태로 전환한다.
state = State.Idle;
}
// 나와 target의 거리를 구해서
float distance = Vector3.Distance(transform.position, target.transform.position);
// 복귀 중 감지거리 안으로 Player가 들어오면
if (distance < findDistance)
{
// 상태를 Move 상태로 전이한다.
state = State.Move;
}
}
}
AddDamage 함수를 만들어줄 PlayerHP를 UI의 Slider로 만든다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
// 태어날때 체력을 최대체력으로 하고싶다.
// 적이 플레이어를 공격할 때 체력을 감소하고싶다.
// 체력이 변경되면 UI에도 반영하고싶다.
public class PlayerHP : MonoBehaviour
{
int hp;
public int maxHP = 3;
public Slider sliderHP;
// property
public int HP
{
get { return hp; }
set
{
hp = value;
sliderHP.value = value;
}
}
public void AddDamage()
{
HP -= 1;
}
// Start is called before the first frame update
void Start()
{
sliderHP.maxValue = maxHP;
HP = maxHP;
}
// Update is called once per frame
void Update()
{
}
}
'공부 > Unity 기초' 카테고리의 다른 글
3D FPS - 9 / 네비게이션 알고리즘으로 길찾기 (0) | 2022.05.21 |
---|---|
3D FPS - 8 / 게임 오버 처리 (0) | 2022.05.19 |
3D FPS - 6 / 위치 복귀 (0) | 2022.05.19 |
3D FPS - 5 / 상태머신 설계 (0) | 2022.05.18 |
3D FPS - 4 / 가리키는 대상 표시 (0) | 2022.05.18 |