C#/Unity

[Unity2D] 몬스터,캐릭터와 충돌 및 공격 변경

반나무 2020. 7. 9. 17:28

GreenMonster.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 이동간 절대기준 사용위한 Tweening 라이브러리 사용
using DG.Tweening;
using System;

public class GreenMonster : MonoBehaviour
{
    ////////////////////////////////////////////////////////////////////////////////
    // 멤버변수 선언

    bool _IsMoveAction = false;

    // 이동 겹치기 방지
    bool _DontMoveDown = false;
    bool _DontMoveUp = false;
    bool _DontMoveLeft = false;
    bool _DontMoveRight = false;

    // HitCount
    int _HitCount = 0;

    // hero 위치 
    int _AttackDirection = 0;

    ////////////////////////////////////////////////////////////////////////////////
    // 델리게이트 선언(return형과 함수형이같아야함)
    // 함수를 추가 삭제하기 편함
    delegate void DelegateInit();
    DelegateInit CurrentAction;

    // Start is called before the first frame update
    void Start()
    {
        // 델리게이트 Start
        CurrentAction += new DelegateInit(MoveAction);
    }

    // Update is called once per frame
    void Update()
    {
        // 델리게이트 사용
        CurrentAction();
    }

    // 움직이는 액션
    void MoveAction()
    {
        if (!_IsMoveAction)
        {
            int R = UnityEngine.Random.Range(0, 4); // 랜덤이동을 위한 부분
            switch (R)
            {
                case 0:
                    LeftMove();
                    break;
                case 1:
                    RightMove();
                    break;
                case 2:
                    UpMove();
                    break;
                case 3:
                    DownMove();
                    break;
            }
        }
    }

    // 위쪽 이동
    void UpMove()
    {
        if (_DontMoveUp == false)
        {
            float EndPositionY = transform.position.y;
            float delay = UnityEngine.Random.Range(0, 3); // delay속도 랜덤 생성

            _IsMoveAction = true; // 토큰 값 변경

            GetComponent<Animator>().SetInteger("State", 0);

            EndPositionY += 1.5f;
            // delay먼저 작동하고 complete
            transform.DOMoveY(EndPositionY, 1.5f).OnComplete(MoveActionComplete).SetEase(Ease.Flash).SetDelay(delay);

        }
    }
    // 아래쪽 이동
    void DownMove()
    {
        if (_DontMoveDown == false)
        {
            float EndPositionY = transform.position.y;
            float delay = UnityEngine.Random.Range(0, 3); // delay속도 랜덤 생성

            _IsMoveAction = true; // 토큰 값 변경
            GetComponent<Animator>().SetInteger("State", 1);

            EndPositionY -= 1.5f;
            transform.DOMoveY(EndPositionY, 1.5f).OnComplete(MoveActionComplete).SetEase(Ease.Flash).SetDelay(delay);
        }
    }
    // 왼쪽 이동
    void LeftMove()
    {
        if (_DontMoveLeft == false)
        {
            float EndPositionX = transform.position.x;
            float delay = UnityEngine.Random.Range(0, 3);

            // 내부 컴포넌트는 GetComponent로 불러올 수 있다.
            _IsMoveAction = true; // 토큰 값 변경
            GetComponent<Animator>().SetInteger("State", 2);  // Animator에서 State값 가져와 변경하는 코드

            EndPositionX -= 1.5f;
            transform.DOMoveX(EndPositionX, 1.5f).OnComplete(MoveActionComplete).SetEase(Ease.Flash).SetDelay(delay);
        }
    }
    // 오른쪽이동
    void RightMove()
    {
        if (_DontMoveRight == false)
        {
            float EndPositionX = transform.position.x;
            float delay = UnityEngine.Random.Range(0, 3);

            GetComponent<Animator>().SetInteger("State", 3);
            _IsMoveAction = true; // 토큰 값 변경

            EndPositionX += 1.5f;
            transform.DOMoveX(EndPositionX, 1.5f).OnComplete(MoveActionComplete).SetEase(Ease.Flash).SetDelay(delay);
        }
    }
    
    // 이동이 끝났을 때
    void MoveActionComplete()
    {
        // 토큰값 false
        _IsMoveAction = false;
        GetComponent<Animator>().SetInteger("State", GetComponent<Animator>().GetInteger("State") + 4);
    }

    ////////////////////////////////////////////////////////////////////////////////
    // 공격 모션 
    void AttackAction()
    {
        // 움직이는 도중에 공격하지 않게 함
        if (!_IsMoveAction)
        {
            GetComponent<Animator>().SetInteger("State", _AttackDirection % 4 + (4 * 4));
        }
    }

    // 총알 맞았을 때
    void HitAction()
    {

    }

    ////////////////////////////////////////////////////////////////////////////////
    // 이동모션에서 공격모션으로 변경
    // 방향값 인자로 받아옴
    public void ChangeToAttack(CollisionDetaction.Direction d)
    {
        if (CurrentAction.Method.Name == "MoveAction")
        {
            // Direction -> int로 캐스팅
            _AttackDirection = (int)d;

            CurrentAction -= new DelegateInit(MoveAction);
            CurrentAction += new DelegateInit(AttackAction);
        }
    }

    // 공격모션에서 이동모션으로 변경
    public void ChangeToMoveAction()
    {
        if (CurrentAction.Method.Name == "AttackAction")
        {
            CurrentAction -= new DelegateInit(AttackAction);
            CurrentAction += new DelegateInit(MoveAction);
        }
    }

    
    ////////////////////////////////////////////////////////////////////////////////
    // 트리거 진입
    private void OnTriggerEnter2D(Collider2D collision)
    {
        String name = collision.gameObject.name;

        // collosion은 상대방의 정보 가져옴
        if (name == "bot_wall")
        {
            _DontMoveDown = true;
        }
        else if (name == "top_wall")
        {
            _DontMoveUp = true;
        }
        else if (name == "left_wall")
        {
            _DontMoveLeft = true;
        }
        else if (name == "right_wall")
        {
            _DontMoveRight = true;
        } 
        // 총알에 맞았을 때
        else if(name == "Player_Bullet(Clone)")
        {
            // Hit
            _HitCount++;

            GetComponent<Animator>().SetInteger("State", GetComponent<Animator>().GetInteger("State")%4 + (4*2));
            
            // Death
            if (_HitCount >= 3)
            {
                // 곱해서 더한값을 나머지 연산으로 다시 처음으로 돌아감(방향 파악하기위해)
                GetComponent<Animator>().SetInteger("State", GetComponent<Animator>().GetInteger("State")%4 + (4 * 3));
            }
        }
       
    }

    // 트리거 나옴
    private void OnTriggerExit2D(Collider2D collision)
    {
        String name = collision.gameObject.name;
        // collosion은 상대방의 정보 가져옴
        if (name == "bot_wall")
        {
            _DontMoveDown = false;
        }
        else if (name == "top_wall")
        {
            _DontMoveUp = false;
        }
        else if (name == "left_wall")
        {
            _DontMoveLeft = false;
        }
        else if (name == "right_wall")
        {
            _DontMoveRight = false;
        }
    }

    // 몬스터 죽음(애니메이션에 이벤트 등록함)
    private void MonsterDestroy()
    {
        Destroy(gameObject);
    }
}

CollisionDetaction.cs

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

public class CollisionDetaction : MonoBehaviour
{
    // 방향 정의함 
    // 열거형(자동으로 ++ 되서 넘버링된다) 
    public enum Direction
    {
        Up = 0,
        Down,
        Left,
        Right,
    }

    // public 하면 유니티 에디터에 Script 부분에 추가된다. 근데 멤버변수는 public하면 좋지 않기 떄문에
    // 그 앞에 [SerializeField]를 추가해 Script에 추가한다.
    [SerializeField]Direction _MyDirection;

    // Start is called before the first frame update
    void Start()
    {
        
    }

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

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.name == "hero")
        {
            // 부모의 정보를 받아올 수 있다.
            //transform.parent.gameObject.GetComponent<GreenMonster>().ChangeToAttack(_MyDirection);

            // SendMassage() 자주안씀 퍼포먼스가 좀 부족함. public으로 다 알면 위에 정보처리로 하는게 좋음
            // 외부 라이브러리가 private로 되어있거나 찾아오기 어려우면 쓰기도 한다. 
            // SendMessageOptions 는 혹시 실패났을때 예외처리 할 수 있게 값 받아오는 것. RequireReceiver하면 퍼포먼스면에서 부족함
            transform.parent.gameObject.SendMessage("ChangeToAttack",_MyDirection, SendMessageOptions.DontRequireReceiver);

        }
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        //transform.parent.gameObject.GetComponent<GreenMonster>().ChangeToMoveAction();
        transform.parent.gameObject.SendMessage("ChangeToMoveAction", SendMessageOptions.DontRequireReceiver);
    }
}
반응형