본문 바로가기
3D 콘텐츠 제작

zombero-boss

by 노재두내 2023. 10. 11.

using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UI;

public class BossController : MonoBehaviour
{
    public Material[] mat = new Material[2];

    public enum eState
    {
        IDLE = 0,
        TRACE,
        ClOSE_ATTACK,    //근거리 공격 
        LONG_ATTACK,  //원거리 공격
        DIE,
    }
    public eState state;
    [SerializeField]
    private float closeAttackRange = 4.0f;
    [SerializeField]
    private float traceRange = 30.0f;
    [SerializeField]
    private float longAttackRange = 10.0f;

    private readonly int hashState = Animator.StringToHash("State");

    private float monsterHp = 160.0f;
    public bool isDie;
    private Animator anim;
    private Transform playerTrans;
    private Transform bossTrans;
    private NavMeshAgent agent;
    public float time = 0;
    private bool isThrow = false;
    [SerializeField]
    private Transform firePos;
    [SerializeField]
    private GameObject SphereBomb;

    private GameObject bodyMesh;
    private GameObject shieldMesh;
    private GameObject axeMesh;

    private float currHp;
    private Image hpBar;
    // Start is called before the first frame update
    void Start()
    {
        this.agent = this.GetComponent<NavMeshAgent>();
        this.bossTrans = this.GetComponent<Transform>();
        this.playerTrans = GameObject.FindWithTag("Player").GetComponent<Transform>();
        this.anim = this.GetComponent<Animator>();

        //agent.destination = this.playerTrans.position;
        this.StartCoroutine(CheckMonsterState());
        this.StartCoroutine(MonsterAction());
        this.StartCoroutine(this.CoCheckTimeToLongAttack());

        this.bodyMesh = GameObject.Find("BlackKnightMesh");
        this.shieldMesh = GameObject.Find("ShieldMesh");
        this.axeMesh = GameObject.Find("AxeMesh");

        this.currHp = this.monsterHp;
        hpBar = GameObject.FindGameObjectWithTag("HP_BAR")?.GetComponent<Image>();

    }

    private IEnumerator CoCheckTimeToLongAttack()
    {
        while (true)
        {
            this.time += Time.deltaTime;
            if (time >= 3.2f)
            {
                this.ResetTime();
            }
            yield return null;
        }
    }
    private void ResetTime()
    {
        this.time = 0;
    }
    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 <= closeAttackRange)
            {
                state = eState.ClOSE_ATTACK;
            }
            else if (distance <= longAttackRange&&this.time>=3.0f)
            {
                state = eState.LONG_ATTACK;
                this.isThrow = false;
            }
            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();
                    break;
                case eState.LONG_ATTACK:
                    this.LongAttack();
                    break;
                case eState.DIE:
                    this.Die();
                    break;
            }
            yield return new WaitForSeconds(0.3f);
        }
    }

    private void Idle()
    {
        this.agent.isStopped = true;
        this.anim.SetInteger(hashState,0);
    }
    private void CloseAttack()
    {
        this.anim.SetInteger(hashState, 2);
    }
    private void Trace()
    {
        this.agent.SetDestination(this.playerTrans.position);
        this.agent.isStopped = false;
        this.anim.SetInteger(hashState, 1);
    }
    private void LongAttack()
    {
        StartCoroutine(CoLongAttack());
    }
    private IEnumerator CoLongAttack()
    {//투사체 던지기
        this.anim.SetInteger(hashState, 3);
        yield return new WaitForSeconds(0.2f);
        Instantiate(this.SphereBomb, firePos.position, firePos.rotation);
        Debug.Log("전");
        yield return new WaitForSeconds(3.0f);
        Debug.Log("후");
    }
    private void Die()
    {
        this.isDie = true;
        this.agent.isStopped = true;
        this.anim.SetTrigger("Die");
        GetComponent<CapsuleCollider>().enabled = false;
        Destroy(this.gameObject, 1.5f);
    }
    private void OnCollisionEnter(Collision collision)
    {
        if (currHp>0.0f&& collision.collider.CompareTag("Bullet"))
        {
            Destroy(collision.gameObject);

            this.currHp -= 10.0f;
            DisPlayHealth();
            Debug.LogFormat("monsterhp:{0}", this.currHp);
            if (this.currHp <= 0)
            {
                this.state = eState.DIE;
            }
        }
        this.StartCoroutine(CoChangeMaterial());
    }

    private void DisPlayHealth()
    {
        hpBar.fillAmount = currHp / monsterHp;
    }

    private IEnumerator CoChangeMaterial()
    {

        this.bodyMesh.GetComponent<SkinnedMeshRenderer>().material = mat[0];
        this.shieldMesh.GetComponent<MeshRenderer>().material = mat[0];
        this.axeMesh.GetComponent<MeshRenderer>().material = mat[0];
        yield return new WaitForSeconds(0.1f);
        this.bodyMesh.GetComponent<SkinnedMeshRenderer>().material = mat[1];
        this.shieldMesh.GetComponent<MeshRenderer>().material = mat[1];
        this.axeMesh.GetComponent<MeshRenderer>().material = mat[1];
        yield return null;
    }
    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.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SphereController : MonoBehaviour
{
    [SerializeField]
    private float force = 500f;
    private Rigidbody rBody;
    //[SerializeField]
    //private GameObject bombPointGo;
    // Start is called before the first frame update
    void Start()
    {
        this.rBody = this.GetComponent<Rigidbody>();
        this.rBody.AddForce(this.transform.forward * this.force);
    }
    private void OnCollisionEnter(Collision collision)
    {
        Destroy(this.gameObject);
        Vector3 hitPoint = collision.GetContact(0).point;
        //Instantiate(bombPointGo,hitPoint)
    }
}
using System.Collections;
using System.Collections.Generic;
using System.Xml.Serialization;
using UnityEngine;

public class Player : MonoBehaviour
{
    public Material[] mat = new Material[3];

    [SerializeField]
    private float moveSpeed = 4f;
    [SerializeField]
    private Animator anim;
    private Rigidbody rBody;
    [SerializeField]
    private GameObject bossPrefab;
    public System.Action onReachPortal;
    //총알발사 
    [SerializeField]
    private GameObject bulletPrefab;
    [SerializeField]
    private Transform firePos;
    [SerializeField]
    private GameObject fireFx;
    private IEnumerator shootRoutine;

    private GameObject bodyMesh;
    private GameObject headMesh;

    private void Start()
    {
        shootRoutine = CoFire();
        this.rBody = this.GetComponent<Rigidbody>();
        this.Idle();

        this.bodyMesh = GameObject.Find("Body20");
        this.headMesh = GameObject.Find("Head20");
    }
    // Start is called before the first frame update
    public void Move(Vector3 dir)
    {
        this.rBody.isKinematic = false;
        this.anim.SetInteger("State", 1);
        //마우스 드래그 각도 구하기
        var angle = Mathf.Atan2(dir.x, dir.z) * Mathf.Rad2Deg;
        var q = Quaternion.AngleAxis(angle, Vector3.up);
        //마우스 각도만큼 회전시키고 그 방향으로(forward)이동하기
        this.transform.rotation = q;
        this.transform.Translate(Vector3.forward * this.moveSpeed * Time.deltaTime);
        this.StopFire();
    }

    public void Idle()
    {
        //Debug.Log("idle");
        this.anim.SetInteger("State", 0);
        //this.rBody.isKinematic = true;
    }

    // 총 쏘는 자세
    public void Attack()
    {
        if (this.bossPrefab != null)
        {
            this.anim.SetInteger("State", 2);
            this.transform.LookAt(this.bossPrefab.transform.position);
            this.Fire();
        }
        //조이스틱이 OnUp일때 Attack을 호출하니까 당연히 죽으면 바로 멈추는게 아니라 조이스틱을 한번 더 움직여야 멈춘다.
        //else if(this.bossPrefab==null)
        //{
        //    this.anim.SetInteger("State", 0);
        //    this.StopFire();
        //}
    }

    //------------------------------------------------------총알 발사--------------------------------------------------------
    public void Fire()
    {
        //Debug.Log("총알발사");
        this.StartCoroutine(shootRoutine);
    }
    public void StopFire()
    {
        //Debug.Log("총알 발사 중지");
        this.StopCoroutine(shootRoutine);
    }
    private IEnumerator CoFire()
    {
        while (true)
        {
            Instantiate(bulletPrefab, firePos.position, firePos.rotation);
            this.ShowFireEffect();
            yield return new WaitForSeconds(0.5f);
        }
    }
    private void ShowFireEffect()
    {
        GameObject fireGo = Instantiate(fireFx, firePos.position, firePos.rotation);
        Destroy(fireGo, 0.5f);
    }
    private void OnCollisionEnter(Collision collision)
    {
        this.StartCoroutine(CoChangeMaterial());
    }

    private IEnumerator CoChangeMaterial()
    {
        this.bodyMesh.GetComponent<SkinnedMeshRenderer>().material = mat[0];
        this.headMesh.GetComponent<SkinnedMeshRenderer>().material = mat[0];
        yield return new WaitForSeconds(0.1f);
        this.bodyMesh.GetComponent<SkinnedMeshRenderer>().material = mat[1];
        this.headMesh.GetComponent<SkinnedMeshRenderer>().material = mat[2];
        //yield return null;
    }
}

보스 애니메이터

 

 

 

집가서 할 거 - Player hp bar, 몬스터 죽으면 총쏘기 멈추기(idle)

카메라 좀 더 멀리 설정, 스카이 박스

시간 된다면 튜토리얼 연결하기

'3D 콘텐츠 제작' 카테고리의 다른 글

3D프로젝트 발표  (1) 2023.10.12
zombero-boss 전체  (0) 2023.10.11
zombero- boss  (0) 2023.10.10
zombero-boss 3일  (0) 2023.10.09
zombero- boss 2일  (1) 2023.10.08