3D 콘텐츠 제작
zombero- boss
노재두내
2023. 10. 10. 10:46
public enum eState
{
IDLE = 0,
TRACE,
CLOSE_ATTACK, //근거리 공격
LONG_ATTACK, //원거리 공격
DIE,
}
[SerializeField]
private float closeAttackRange = 2.0f;
[SerializeField]
private float traceRange = 30.0f;
[SerializeField]
private float longAttackRange = 10.0f;
private readonly int hashState = Animator.StringToHash("State");
private Player target;
private void OnDrawGizmos()
{
if (state == eState.TRACE)
{
Gizmos.color = Color.blue;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.traceRange);
}
else if (state == eState.CLOSE_ATTACK)
{
Gizmos.color = Color.red;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.closeAttackRange);
}
else if (state == eState.LONG_ATTACK)
{
Gizmos.color = Color.yellow;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.longAttackRange);
}
}
오늘 할 거
보스 총알에 맞으면 색이 변하기
원거리 공격하기
보스 공격에 맞으면 플레이어 색 변경 ?
총알 오브젝트 풀링
using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AI;
public class BossController : MonoBehaviour
{
public enum eState
{
IDLE,
TRACE,
CLOSE_ATTACK, //근거리 공격
DIE,
LONG_ATTACK //원거리 공격
}
public eState state;
[SerializeField]
private float attackRange = 2.0f;
[SerializeField]
private float traceRange = 10.0f;
private float monsterHp = 100.0f;
public bool isDie;
private Animator anim;
private Transform bossTrans;
private NavMeshAgent agent;
private readonly int hashTrace = Animator.StringToHash("IsTrace");
private readonly int hashAttack = Animator.StringToHash("IsAttack");
private readonly int hashLongAttack = Animator.StringToHash("IsLongAttack");
private Coroutine stateCoroutine; //상태 코루틴 : 하나의 행동에 하나의 코루틴만 돌아감
private Player target;
private void Start()
{
this.Init(); //test , Main에서 Init해주기
}
public void Init()
{
this.agent = this.GetComponent<NavMeshAgent>();
this.bossTrans = this.GetComponent<Transform>();
this.anim = this.GetComponent<Animator>();
this.target = GameObject.FindWithTag("Player").GetComponent<Player>();
this.stateCoroutine = null;
this.ChageState(eState.IDLE);
this.CheckTimeToLongAttack();
}
private void CheckTimeToLongAttack()
{
this.StartCoroutine(this.CoCheckTimeToLongAttack());
}
[SerializeField]
private float delta = 0;
private float timeToLongAttack = 3f; //n초에 한번씩 원거리 공격
private IEnumerator CoCheckTimeToLongAttack()
{
while (true)
{
this.delta += Time.deltaTime;
if (this.delta >= timeToLongAttack)
{
if (this.state == eState.CLOSE_ATTACK || this.state == eState.LONG_ATTACK)
{
this.ResetTimeToLongAttack();
continue;
}
else
{
//Idle or Trace
this.ResetTimeToLongAttack();
this.ChageState(eState.LONG_ATTACK);
}
}
yield return null;
}
}
private void ResetTimeToLongAttack()
{
this.delta = 0;//다시 0초로 바꾸기
this.timeToLongAttack = UnityEngine.Random.Range(3.0f, 6.0f);
}
private void ChageState(eState state)
{
Debug.LogFormat("{0} -> {1}", this.state, state);
if (this.state != state)
{
this.state = state;
switch (this.state)
{
case eState.IDLE:
this.Idle();
break;
case eState.CLOSE_ATTACK:
break;
case eState.LONG_ATTACK:
this.LongAttack();
break;
case eState.TRACE:
this.Trace();
break;
case eState.DIE:
break;
}
}
}
//private IEnumerator CheckMonsterState()
//{
// while (!isDie)
// {
// yield return new WaitForSeconds(0.3f);
// if (this.state == eState.DIE) yield break;
// float distance = Vector3.Distance(this.playerTrans.position, this.bossTrans.position);
// if (distance <= attackRange)
// {
// state = eState.CLOSE_ATTACK;
// }
// else if (distance <= traceRange)
// {
// state = eState.TRACE;
// }
// else
// {
// state = eState.IDLE;
// }
// }
//}
//private IEnumerator MonsterAction()
//{
// while (this.isDie == false)
// {
// switch (this.state)
// {
// case eState.IDLE:
// this.Idle();
// break;
// case eState.CLOSE_ATTACK:
// this.CloseAttack();
// break;
// case eState.TRACE:
// this.Trace();
// //yield return new WaitForSeconds(3.0f);
// //this.LongAttack();
// break;
// case eState.DIE:
// this.Die();
// break;
// }
// yield return new WaitForSeconds(0.3f);
// }
//}
private void LongAttack()
{
if (this.stateCoroutine != null)//이미 다른 state가 있을때
this.StopCoroutine(this.stateCoroutine);// 기존꺼를 멈추고
this.stateCoroutine = this.StartCoroutine(this.CoLongAttack()); //새로운거를 시작
}
private IEnumerator CoLongAttack()
{
this.anim.SetBool(hashLongAttack, true);
this.agent.isStopped = false;
//투사체 발사
yield return new WaitForSeconds(1.0f);
//발사 완료
//거리 다시 체크 Idle할건지 Trace할건지
//float distance = Vector3.Distance(this.transform.position, this.target.transform.position);
//if (distance <= this.traceRange)
//{
// this.ChageState(eState.CLOSE_ATTACK);
//}
//else if (distance <= this.attackRange)
//{
// this.ChageState(eState.TRACE);
//}
//else
this.ChageState(eState.IDLE);
}
private void OnDrawGizmos()
{
if (state == eState.TRACE)
{
Gizmos.color = Color.blue;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.traceRange);
}
else if (state == eState.CLOSE_ATTACK)
{
Gizmos.color = Color.red;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.attackRange);
}
}
//Idle 상태
public void Idle()
{
this.stateCoroutine = this.StartCoroutine(this.CoIdle());
}
private IEnumerator CoIdle()
{
this.agent.isStopped = true; //멈춤
this.anim.SetBool(hashTrace, false); //애니메이셔 실행
while (true)
{
//사거리 안에 들어오는지 계속 체크 해야 함
float distance = Vector3.Distance(this.transform.position, this.target.transform.position);
if (distance <= this.traceRange)
{
//상태 변환
this.ChageState(eState.TRACE);
break;
}
yield return null;//다음 프레임으로 이동
}
Debug.Log("Idle 상태 종료");
}
private void CloseAttack()
{
}
//private IEnumerator CoCloseAttack()
//{
//this.anim.SetBool(hashAttack, true);
//this.anim.SetBool(hashLongAttack, false);
//}
public void Trace()
{
if (this.stateCoroutine != null)
{
this.StopCoroutine(this.stateCoroutine);
}
this.stateCoroutine = this.StartCoroutine(this.CoTrace());
}
private IEnumerator CoTrace()
{
this.agent.SetDestination(this.target.gameObject.transform.position);
this.agent.isStopped = false;
this.anim.SetBool(hashTrace, true);
this.anim.SetBool(hashAttack, false);
this.anim.SetBool(hashLongAttack, false);
while (true)
{
//근거리 사거리에 들어왔는가를 체크
float distance = Vector3.Distance(this.transform.position, this.target.transform.position);
if (distance <= this.attackRange)
{
//상태 변환
this.ChageState(eState.CLOSE_ATTACK);
break;
}
yield return null;
}
Debug.Log("Trace 상태 종료");
}
private void Die()
{
this.isDie = true;
this.agent.isStopped = true;
this.anim.SetTrigger("Die");
Destroy(this.gameObject, 1.5f);
}
private void OnCollisionEnter(Collision collision)
{
if (collision.collider.CompareTag("Bullet"))
{
Destroy(collision.gameObject);
this.monsterHp -= 10;
Debug.LogFormat("monsterhp:{0}", this.monsterHp);
if (this.monsterHp <= 0)
{
this.state = eState.DIE;
}
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AI;
public class BossController : MonoBehaviour
{
public enum eState
{
IDLE = 0,
TRACE,
CLOSE_ATTACK, //근거리 공격
LONG_ATTACK, //원거리 공격
DIE,
}
public eState state;
[SerializeField]
private float closeAttackRange = 2.0f;
[SerializeField]
private float traceRange = 30.0f;
[SerializeField]
private float longAttackRange = 10.0f;
private float monsterHp = 100.0f;
public bool isDie;
private Animator anim;
private Transform bossTrans;
private NavMeshAgent agent;
private readonly int hashState = Animator.StringToHash("State");
private Coroutine stateCoroutine; //상태 코루틴 : 하나의 행동에 하나의 코루틴만 돌아감
private Player target;
private void Start()
{
this.Init(); //test , Main에서 Init해주기
}
public void Init()
{
this.agent = this.GetComponent<NavMeshAgent>();
this.bossTrans = this.GetComponent<Transform>();
this.anim = this.GetComponent<Animator>();
this.target = GameObject.FindWithTag("Player").GetComponent<Player>();
this.stateCoroutine = null;
this.ChageState(eState.IDLE);
this.CheckTimeToLongAttack();
}
private void CheckTimeToLongAttack()
{
this.StartCoroutine(this.CoCheckTimeToLongAttack());
}
[SerializeField]
private float delta = 0;
private float timeToLongAttack = 3f; //n초에 한번씩 원거리 공격
private IEnumerator CoCheckTimeToLongAttack()
{
while (true)
{
this.delta += Time.deltaTime;
if (this.delta >= timeToLongAttack)
{
if (this.state == eState.CLOSE_ATTACK || this.state == eState.LONG_ATTACK)
{
this.ResetTimeToLongAttack();
continue;
}
else
{
//Idle or Trace
this.ResetTimeToLongAttack();
this.ChageState(eState.LONG_ATTACK);
break;
}
}
yield return null;
}
}
private void ResetTimeToLongAttack()
{
this.delta = 0;//다시 0초로 바꾸기
this.timeToLongAttack = UnityEngine.Random.Range(3.0f, 6.0f);
}
private void ChageState(eState state)
{
Debug.LogFormat("{0} -> {1}", this.state, state);
if (this.state != state)
{
this.state = state;
switch (this.state)
{
case eState.IDLE:
this.Idle();
break;
case eState.CLOSE_ATTACK:
this.CloseAttack();
break;
case eState.LONG_ATTACK:
this.LongAttack();
break;
case eState.TRACE:
this.Trace();
break;
case eState.DIE:
break;
}
}
}
//private IEnumerator CheckMonsterState()
//{
// while (!isDie)
// {
// yield return new WaitForSeconds(0.3f);
// if (this.state == eState.DIE) yield break;
// float distance = Vector3.Distance(this.playerTrans.position, this.bossTrans.position);
// if (distance <= attackRange)
// {
// state = eState.CLOSE_ATTACK;
// }
// else if (distance <= traceRange)
// {
// state = eState.TRACE;
// }
// else
// {
// state = eState.IDLE;
// }
// }
//}
//private IEnumerator MonsterAction()
//{
// while (this.isDie == false)
// {
// switch (this.state)
// {
// case eState.IDLE:
// this.Idle();
// break;
// case eState.CLOSE_ATTACK:
// this.CloseAttack();
// break;
// case eState.TRACE:
// this.Trace();
// //yield return new WaitForSeconds(3.0f);
// //this.LongAttack();
// break;
// case eState.DIE:
// this.Die();
// break;
// }
// yield return new WaitForSeconds(0.3f);
// }
//}
private void LongAttack()
{
if (this.stateCoroutine != null)//이미 다른 state가 있을때
this.StopCoroutine(this.stateCoroutine);// 기존꺼를 멈추고
this.stateCoroutine = this.StartCoroutine(this.CoLongAttack()); //새로운거를 시작
}
private IEnumerator CoLongAttack()
{
this.anim.SetBool(hashLongAttack, true);
this.agent.isStopped = false;
//투사체 발사
yield return new WaitForSeconds(1.0f);
//발사 완료
//거리 다시 체크 Idle할건지 Trace할건지
this.ChageState(eState.IDLE);
}
private void OnDrawGizmos()
{
if (state == eState.TRACE)
{
Gizmos.color = Color.blue;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.traceRange);
}
else if (state == eState.CLOSE_ATTACK)
{
Gizmos.color = Color.red;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.closeAttackRange);
}
else if (state == eState.LONG_ATTACK)
{
Gizmos.color = Color.yellow;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.longAttackRange);
}
}
//Idle 상태
public void Idle()
{
this.stateCoroutine = this.StartCoroutine(this.CoIdle());
}
private IEnumerator CoIdle()
{
this.agent.isStopped = true; //멈춤
this.anim.SetBool(hashTrace, false); //애니메이셔 실행
while (true)
{
//사거리 안에 들어오는지 계속 체크 해야 함
float distance = Vector3.Distance(this.transform.position, this.target.transform.position);
if (distance <= this.traceRange)
{
//상태 변환
this.ChageState(eState.TRACE);
break;
}
yield return null;//다음 프레임으로 이동
}
Debug.Log("Idle 상태 종료");
}
public void CloseAttack()
{
Debug.LogFormat("CloseAttack");
if(this.stateCoroutine != null)
{
this.StopCoroutine(this.stateCoroutine);
}
this.stateCoroutine = this.StartCoroutine(this.CoCloseAttack());
}
private IEnumerator CoCloseAttack()
{
this.anim.SetBool(hashAttack, true);
//this.anim.SetBool(hashLongAttack, false);
while (true)
{
//사거리 안에 들어오는지 계속 체크 해야 함
float distance = Vector3.Distance(this.transform.position, this.target.transform.position);
if (distance <= this.traceRange)
{
//상태 변환
//this.ChageState(eState.TRACE);
Debug.Log("근거리-> 추적");
break;
}
yield return null;//다음 프레임으로 이동
}
Debug.Log("근거리 공격 상태 종료");
}
public void Trace()
{
if (this.stateCoroutine != null)
{
this.StopCoroutine(this.stateCoroutine);
}
this.stateCoroutine = this.StartCoroutine(this.CoTrace());
}
private IEnumerator CoTrace()
{
this.agent.SetDestination(this.target.gameObject.transform.position);
this.agent.isStopped = false;
this.anim.SetBool(hashTrace, true);
this.anim.SetBool(hashAttack, false);
this.anim.SetBool(hashLongAttack, false);
while (true)
{
//근거리 사거리에 들어왔는가를 체크
float distance = Vector3.Distance(this.transform.position, this.target.transform.position);
if (distance <= this.closeAttackRange)
{
//상태 변환
this.ChageState(eState.CLOSE_ATTACK);
break;
}
yield return null;
}
Debug.Log("Trace 상태 종료");
}
private void Die()
{
this.isDie = true;
this.agent.isStopped = true;
this.anim.SetTrigger("Die");
Destroy(this.gameObject, 1.5f);
}
private void OnCollisionEnter(Collision collision)
{
if (collision.collider.CompareTag("Bullet"))
{
Destroy(collision.gameObject);
this.monsterHp -= 10;
Debug.LogFormat("monsterhp:{0}", this.monsterHp);
if (this.monsterHp <= 0)
{
this.state = eState.DIE;
}
}
}
}
맞으면 깜빡거리기-> material 을 바꾸기
sci-fi city