본문 바로가기
KDT/유니티 기초

23/08/09 SimpleRPG 몬스터 공격 및 데미지 받기

by 잰쟁 2023. 8. 9.
728x90
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

namespace Test2
{
    public class Test_PlayerAttackSceneMain : MonoBehaviour
    {
        [SerializeField]
        private Button btnAttack;
        [SerializeField]
        private HeroController heroController;
        [SerializeField]
        private MonsterController monsterController;

        void Start()
        {
            Debug.LogFormat("btnAttack: {0}", btnAttack);  //Button 컴포넌트의 인스턴스
            //이벤트 등록
            this.btnAttack.onClick.AddListener(() => {

                //사거리 체크
                //두 점(A,B)과의 거리, 두 오브젝트의 radius의 합
                //B-A : C(방향벡터), magnitude (벡터의 길이)
                //MonsterController 컴포넌트가 붙어있는 게임오브젝의
                Vector3 b = monsterController.transform.position;
                Vector3 a = heroController.transform.position;
                Vector3 c = b - a;  //정규화되지 않은 방향벡터 (방향과 크기), 크기 : 길이

                //--------------> (방향 ->, 크기 ------------ )

                float distance = c.magnitude;
                Debug.LogFormat("distance : {0}", distance);
                Debug.DrawLine(a, b, Color.red, 5f);

                //단위벡터 (길이가 1인 벡터)
                //Vector3 normal = c.normalized; //방향
                //시작위치, 방향, 얼마동안 보여줄건가(초), 색상, 타입 (채움)
                //DrawArrow.ForDebug(a, normal, 5f, Color.red, ArrowType.Solid);
                //DrawArrow.ForDebug(a, c, 5f, Color.red, ArrowType.Solid);
                //Vector3. Distance

                //두 컴포넌트의 radius (반지름)의 합
                float radius = this.heroController.Radius + this.monsterController.Radius;
                Debug.LogFormat("radius: {0}", radius);
                Debug.LogFormat("<color=yellow>distance: {0},radius: {1}</color>", distance, radius);
                Debug.LogFormat("IsWithRange: <color=lime>{0}</color>", this.IsWithinRange(distance, radius));

            if (this.IsWithinRange(distance, radius))
                {
                //HeroController에게 공격을 명령
                this.heroController.Attack(this.monsterController);
                }
 
            });  
        }
        //사거리 체크
        private bool IsWithinRange(float distance, float radius)
        {
            //distance > radius   //false
            return radius >= distance;  //true
        }

        // Update is called once per frame
        void Update()
        {

        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Test2
{
    public class HeroController : MonoBehaviour
    {
        public enum eState
        {
            Idle, Attack
        }

        [SerializeField]
        private float radius = 1f;
        private Animator anim;
        //private eState state = eState.Idle;
        private eState state;   //초기화 0(Idle)
        private float impactTime = 0.399f;
        public MonsterController target;

        public float Radius
        {
            get
            {
                return this.radius;
            }
        }

        void Start()
        {
            //내가(HeroController) 컴포넌트가 붙어있는 게임오브젝트에 붙어있는 Animator컴포넌스 가져옴
            this.anim = this.GetComponent<Animator>();
        }

        // Update is called once per frame
        void Update()
        {

        }

        public void Attack(MonsterController target)
        {
            this.target = target;
            //공격 애니메이션을 1회 실행
            //애니메이터 컴포넌트가 필요
            this.PlayAnimation(eState.Attack);
        }

        //enum을 변수로 받아 애니메이션 실행
        private void PlayAnimation(eState state)
        {
            //this.state : prev, state: current
            //중복막기
            if(this.state != state)
            {
                Debug.LogFormat("{0} -> {1}", this.state, state);
                this.state = state;
                this.anim.SetInteger("State", (int)state);  //정수 -> enum

                switch (state)
                {
                    case eState.Attack:
                        //코루틴 함수는 StartCoroutine으로 실행해야 함
                        this.StartCoroutine(this.WaitForCompleteAttackAnimation());
                        break;
                }

            }
            else
            {
                Debug.LogFormat("{0}는 현재와 동일한 상태입니다.", state);
            }
            
        }
        //코루틴 함수
        //IEumerator 반환타입을 갖는 1개 이상의 yield return을 포함하는 함수
        //Update와 동일하게 동작 가능
        private IEnumerator WaitForCompleteAttackAnimation()
        {
            yield return null; //다음의 시작(1프레임 건너뜀, next frame)

            Debug.Log("공격 애니메이션이 끝날때까지 기다림");
            //layerIndex : 0
            AnimatorStateInfo animStateInfo = this.anim.GetCurrentAnimatorStateInfo(0);
            bool isAttackState = animStateInfo.IsName("Attack01");
            Debug.LogFormat("isAttackState: {0}", isAttackState);
            if (isAttackState)
            {
                Debug.LogFormat("animStateInfo.length: {0}", animStateInfo.length);
            }
            else
            {
                Debug.LogFormat("Attack State가 아닙니다.");
            }

            //0.11초 이후에 임펙트 효과 넣기
            yield return new WaitForSeconds(impactTime);  //Impact
            Debug.Log("<color=red>Impact!!!</color>");

            //대상에게 피해를 입힘
            this.target.HitDamage();

            //0.833초를 대기
            //yield return new WaitForSeconds(0.833f);
            yield return new WaitForSeconds(animStateInfo.length - impactTime); //0.48초만큼 기다림

            //Idle 애니메이션을 함
            //this.anim.SetInteger("State",0);
            this.PlayAnimation(eState.Idle);
        }

        //기즈모 생성
        private void OnDrawGizmos()
        {
            Gizmos.color = Color.yellow;
            GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.radius);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


namespace Test2 
{
    public class MonsterController : MonoBehaviour
    {
        [SerializeField]
        private float radius = 1f;
        private Animator anim;

        public float Radius
        {
            get
            { return this.radius; }
        }

        void Start()
        {
            this.anim = GetComponent<Animator>();
        }

        // Update is called once per frame
        void Update()
        {

        }

        //공격받는 메서드
        public void HitDamage()
        {
            Debug.Log("피해 애니메이션을 실행합니다.");
            this.anim.SetInteger("State",2);
        }

        //기즈모 생성
        private void OnDrawGizmos()
        {
            Gizmos.color = Color.yellow;
            GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.radius);
        }
    }
}
using UnityEngine;
using System.Collections;
#if UNITY_EDITOR
using UnityEditor;
#endif
// adapted from http://wiki.unity3d.com/index.php/DrawArrow 


public enum ArrowType
{
    Default,
    Thin,
    Double,
    Triple,
    Solid,
    Fat,
    ThreeD,
}

public static class DrawArrow
{
    public static void ForGizmo(Vector3 pos, Vector3 direction, Color? color = null, bool doubled = false, float arrowHeadLength = 0.2f, float arrowHeadAngle = 20.0f)
    {
        Gizmos.color = color ?? Color.white;

        //arrow shaft
        Gizmos.DrawRay(pos, direction);

        if (direction != Vector3.zero)
        {
            //arrow head
            Vector3 right = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + arrowHeadAngle, 0) * new Vector3(0, 0, 1);
            Vector3 left = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - arrowHeadAngle, 0) * new Vector3(0, 0, 1);
            Gizmos.DrawRay(pos + direction, right * arrowHeadLength);
            Gizmos.DrawRay(pos + direction, left * arrowHeadLength);
        }
    }

    public static void ForDebug(Vector3 pos, Vector3 direction, float duration = 0.5f, Color? color = null, ArrowType type = ArrowType.Default, float arrowHeadLength = 0.2f, float arrowHeadAngle = 30.0f, bool sceneCamFollows = false)
    {
        Color actualColor = color ?? Color.white;
        duration = duration / Time.timeScale;

        float width = 0.01f;

        Vector3 directlyRight = Vector3.zero;
        Vector3 directlyLeft = Vector3.zero;
        Vector3 directlyBack = Vector3.zero;
        Vector3 headRight = Vector3.zero;
        Vector3 headLeft = Vector3.zero;

        if (direction != Vector3.zero)
        {
            directlyRight = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + 90, 0) * new Vector3(0, 0, 1);
            directlyLeft = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - 90, 0) * new Vector3(0, 0, 1);
            directlyBack = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180, 0) * new Vector3(0, 0, 1);
            headRight = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + arrowHeadAngle, 0) * new Vector3(0, 0, 1);
            headLeft = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - arrowHeadAngle, 0) * new Vector3(0, 0, 1);
        }

        //draw arrow head
        Debug.DrawRay(pos + direction, headRight * arrowHeadLength, actualColor, duration);
        Debug.DrawRay(pos + direction, headLeft * arrowHeadLength, actualColor, duration);

        switch (type)
        {
            case ArrowType.Default:
                Debug.DrawRay(pos, direction, actualColor, duration); //draw center line
                break;
            case ArrowType.Double:
                Debug.DrawRay(pos + directlyRight * width, direction * (1 - width), actualColor, duration); //draw line slightly to right
                Debug.DrawRay(pos + directlyLeft * width, direction * (1 - width), actualColor, duration); //draw line slightly to left

                //draw second arrow head
                Debug.DrawRay(pos + directlyBack * width + direction, headRight * arrowHeadLength, actualColor, duration);
                Debug.DrawRay(pos + directlyBack * width + direction, headLeft * arrowHeadLength, actualColor, duration);

                break;
            case ArrowType.Triple:
                Debug.DrawRay(pos, direction, actualColor, duration); //draw center line
                Debug.DrawRay(pos + directlyRight * width, direction * (1 - width), actualColor, duration); //draw line slightly to right
                Debug.DrawRay(pos + directlyLeft * width, direction * (1 - width), actualColor, duration); //draw line slightly to left
                break;
            case ArrowType.Fat:
                break;
            case ArrowType.Solid:
                int increments = 20;
                for (int i = 0; i < increments; i++)
                {
                    float displacement = Mathf.Lerp(-width, +width, i / (float)increments);
                    //draw arrow body
                    Debug.DrawRay(pos + directlyRight * displacement, direction, actualColor, duration); //draw line slightly to right
                    Debug.DrawRay(pos + directlyLeft * displacement, direction, actualColor, duration); //draw line slightly to left
                                                                                                        //draw arrow head
                    Debug.DrawRay((pos + direction) + directlyRight * displacement, headRight * arrowHeadLength, actualColor, duration);
                    Debug.DrawRay((pos + direction) + directlyRight * displacement, headLeft * arrowHeadLength, actualColor, duration);
                }
                break;
            case ArrowType.Thin:
                Debug.DrawRay(pos, direction, actualColor, duration); //draw center line
                break;
            case ArrowType.ThreeD:
                break;
        }

        /*#if UNITY_EDITOR
            //snap the Scene view camera to a spot where it is looking directly at this arrow.
                if (sceneCamFollows)
                    SceneViewCameraFollower.activateAt(pos + direction, duration, "_arrow");
        #endif*/
    }

    public static void randomStar(Vector3 center, Color color)
    {
        //special: refuse to draw at 0,0.
        if (center == Vector3.zero) return;
        for (int i = 0; i < 2; i++)
            DrawArrow.ForGizmo(center, UnityEngine.Random.onUnitSphere * 1, color, false, 0.1f, 30.0f);
    }

    public static void comparePositions(Transform t1, Transform t2)
    {
        //direct from one to the other:
        ForDebug(t1.position, t2.position - t1.position);

        //direction
        //Vector3 moveDirection = (t2.position-t1.position).normalized;
    }
}