Player 사망-Event 처리, 몬스터 사망
특정 레이어간 충돌 감지
-Monster_Body, Monster_Punch 레이어를 추가후 Physics에서 셋팅을 변경시켜주면 collider간 충돌을 방지할 수 있다.
본구조의 최적화
https://docs.unity3d.com/kr/2021.1/Manual/FBXImporter-Rig.html
몬스터 공격중지
https://learn.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/event
-멀티캐스트와 대리자 결합을 참고하자
*이벤트는 멀티캐스트 대리자이다.
몬스터 사망 구현
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UIElements;
public class MonsterController : MonoBehaviour
{
public enum eState
{//몬스터 상태 정의
IDLE, TRACE, ATTACK, DIE
}
public eState state = eState.IDLE;//몬스터의 현재 상태
private bool isDie=false;//몬스터의 사망 여부
private NavMeshAgent agent;
private Transform playerTrans;
private Animator anim;
private readonly int hashTrace = Animator.StringToHash("IsTrace");//Animator 파라미터의 해시값 추출
private readonly int hashAttack = Animator.StringToHash("IsAttack");
private readonly int hashGotHit = Animator.StringToHash("GotHit");
private readonly int hashDance = Animator.StringToHash("Dance");
private readonly int hashSpeed = Animator.StringToHash("Speed");
private readonly int hashDie = Animator.StringToHash("Die");
private GameObject bloodEffectPrefab;//혈흔 효과 프리팹
[SerializeField]private float traceDistance = 10.0f;//추적 사거리
[SerializeField]private float attackDistance = 2f;//공격 사거리
//--Data----------------------------------------------------
private float initHp = 100f;
private float currHp;
// Start is called before the first frame update
void Start()
{
this.currHp = this.initHp;
this.bloodEffectPrefab = Resources.Load<GameObject>("BloodSprayEffect");
this.anim = GetComponent<Animator>();
this.agent = this.GetComponent<NavMeshAgent>();//agent 컴포넌트 가져옴
GameObject playerGo = GameObject.FindGameObjectWithTag("Player");
this.playerTrans = playerGo.GetComponent<Transform>();
// Vector3 playerPosition = playerTrans.position;
// this.agent.destination = playerPosition;//destination 속성을 사용해 이동할 좌푯값 지정
StartCoroutine(this.CheckState());//상태 갱신
StartCoroutine(this.MonsterAction());//상태에따라 몬스터 행동 수행
}
// Update is called once per frame
void Update()
{
}
private IEnumerator CheckState()
{//상태 갱신 코루틴 함수: 일정 간격으로 몬스터의 행동상태 체크
while (!isDie)
{
yield return new WaitForSeconds(0.3f);
if (this.state == eState.DIE) yield break;
float distance = Vector3.Distance(this.transform.position, this.playerTrans.position);
// Debug.Log(distance);
//Debug.Log(this.state);
if (distance <= this.traceDistance)//추적 사거리에 들어왔다면
{
this.state = eState.TRACE;//추적상태로 변경
if (distance <= this.attackDistance) //공격 사거리에 들어왔다면
{
this.state = eState.IDLE;
yield return null;
this.state = eState.ATTACK;//공격상태로 변경
}
}
else//멈춤
{
this.state = eState.IDLE;
}
}
}
private IEnumerator MonsterAction()
{
while (!isDie)
{
switch (this.state)
{
case eState.IDLE:
this.agent.isStopped = true;//추적 중지
//this.anim.SetBool("IsTrace", false);
this.anim.SetBool(this.hashTrace, false);
this.anim.SetBool(this.hashAttack,false);
break;
case eState.TRACE:
this.agent.SetDestination(this.playerTrans.position);
this.agent.isStopped = false;
this.anim.SetBool(this.hashTrace, true);
this.anim.SetBool(this.hashAttack, false);
break;
case eState.ATTACK:
this.anim.SetBool(this.hashAttack, true);
this.anim.SetBool(this.hashTrace, false);
break;
case eState.DIE:
this.isDie = true;
this.agent.isStopped = true;
this.anim.SetTrigger(this.hashDie);
GetComponent<CapsuleCollider>().enabled = false;//몬스터의 collider 비활성화
break;
}
yield return new WaitForSeconds(0.3f);
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.collider.CompareTag("Bullet"))
{
ContactPoint contactPoint = collision.GetContact(0);//첫 번째 충돌 지점
//DrawArrow.ForDebug(contactPoint.point, -contactPoint.normal, 5f, Color.white);
//point:위치, normal:법선, 법선 반대로 그려보기
Quaternion rotation = Quaternion.LookRotation(-contactPoint.normal);//바라볼 방향
//충돌 지점의 법선 벡터를 쿼터니언 타입으로 변환
GameObject go = Instantiate(this.bloodEffectPrefab,contactPoint.point,rotation,this.transform);
//go.transform.position = contactPoint.point;
//go.transform.rotation = rotation;//법선 벡터로 회전
// Debug.LogErrorFormat("{0}",contactPoint.point);
Destroy(collision.gameObject);//remove bullet
Destroy(go, 0.5f);//remove blood Effect
this.anim.SetTrigger(this.hashGotHit);
this.currHp -= 30.0f;
// Debug.Log(this.state);
if(this.currHp <= 0)
{//몬스터 사망
this.state = eState.DIE;
}
}
}
private void OnEnable()
{//이벤트 발생 시 수행할 함수 연결
PlayerController.OnPlayerDie += this.OnPlayerDie;
}
private void OnDisable()
{//기존에 연결된 함수 해제
PlayerController.OnPlayerDie -= this.OnPlayerDie;
}
void OnPlayerDie()
{
StopAllCoroutines();
this.agent.isStopped = true;
this.anim.SetFloat(this.hashSpeed, Random.Range(0.8f, 1.2f));
this.anim.SetTrigger(this.hashDance);
}
private void OnDrawGizmos()
{
if(this.state == eState.TRACE)
{
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(this.transform.position, traceDistance);
}
else if(this.state == eState.ATTACK)
{
Gizmos.color= Color.green;
Gizmos.DrawWireSphere(this.transform.position,attackDistance);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class PlayerController : MonoBehaviour
{
public Vector3 cameraPosition;
private Vector3 moveDir;
private Vector3 aPosition;
private Animation anim;
//delegate 선언
public delegate void PlayerDieHandler();//타입 정의
//event
public static event PlayerDieHandler OnPlayerDie;//대리자 타입의 변수 정의
[SerializeField]private float moveSpeed = 1f;
[SerializeField] private float turnSpeed =80f;
//data----------------------------------------------
private readonly float initHp = 100.0f;//초기 생명값
public float currHp;//현재 체력
IEnumerator Start()
{
this.currHp = this.initHp;//체력 초기화
this.anim = GetComponent<Animation>();
anim.Play("Idle");//시작 시 Idle
this.turnSpeed = 0.0f;
yield return new WaitForSeconds(0.3f);
this.turnSpeed = 80.0f;
}
private void Update()
{
//키보드 이동
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
float r = Input.GetAxis("Mouse X");//마우스를 왼쪽으로 움직이면 음수, 오른쪽 양수 반환
moveDir = (Vector3.forward * v) + Vector3.right * h;
this.transform.Translate(moveDir.normalized * this.moveSpeed * Time.deltaTime);//이동
// Debug.LogFormat("{0} , {1}", moveDir, moveDir.normalized);
// DrawArrow.ForDebug(this.transform.position, moveDir, 5f, Color.red);
Vector3 angle = Vector3.up * turnSpeed * Time.deltaTime * r;
// Vector3 angle2 = Vector3.up * turnSpeed * r;//Time.deltaTime을 빼보았다.
// Debug.LogFormat("angle2:{0},r:{1}",angle2,r );
this.transform.Rotate(angle);//Vector3.up을 축으로 회전
PlayAnim(h,v);
}
private void OnDrawGizmos()
{
DrawArrow.ForGizmo(this.transform.position, this.transform.forward , Color.red);
Gizmos.color = Color.white;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, 1);
DrawArrow.ForGizmo(this.transform.position, -this.transform.forward * 3, Color.yellow);
this.aPosition = this.transform.position + (-this.transform.forward * 3);//a지점의 위치
DrawArrow.ForGizmo(this.aPosition, Vector3.up * 2, Color.green);//카메라의 위치를 의미한다.
this.cameraPosition = this.aPosition+ (Vector3.up*2);
}
private void PlayAnim(float h,float v)//키보드 입력값을 기준으로 애니메이션 play
{
if (v >= 0.1f)//x축 : 전,후
{
anim.CrossFade("RunF", 0.25f);//전진
}
else if (v <= -0.1f)
{
anim.CrossFade("RunB", 0.25f);//후진
}
else if (h >= 0.1f)//z축 : 좌, 우
{
anim.CrossFade("RunR", 0.25f);
}
else if (h <= -0.1f)
{
anim.CrossFade("RunL", 0.25f);
}
else
{
anim.CrossFade("Idle", 0.25f);//정지 시 Idle
}
}
private void OnTriggerEnter(Collider coll)
{
if(this.currHp >= 0.0f && coll.CompareTag("Punch"))
{
Debug.Log(coll.tag);
this.currHp -= 10.0f;
if(this.currHp < 0.0f)
{
PlayerDie();
}
}
}
private void PlayerDie()
{
Debug.Log("Player Die!!");
//GameObject[] arrMonstersGo = GameObject.FindGameObjectsWithTag("Monster");
////monster 태그를 가진 모든 게임 오브젝트를 찾아옴
//foreach(GameObject monster in arrMonstersGo)
//{
// monster.SendMessage("OnPlayerDie",SendMessageOptions.DontRequireReceiver);
//}
OnPlayerDie();//Player 사망 이벤트 발생(Notification)- 대리자 호출
}
}
'유니티 심화' 카테고리의 다른 글
Unity UI-버튼-애니메이션, Play씬에서 HpBar 생성 (0) | 2023.08.25 |
---|---|
Unity-UI 시스템-IMGUI, UI Toolkit,Unity UI(UGUI) (0) | 2023.08.25 |
몬스터 수정- 해시값 전달, 몬스터의 공격, 피격시 혈흔 효과, Player 수정 (0) | 2023.08.24 |
FindGameObjectWithTag, FindWithTag (0) | 2023.08.24 |
메카님 애니메이션 제어,내비게이션-길찾기, 유한상태머신(FSM) (0) | 2023.08.23 |