유니티

로그라이크 - MovingObject.cs

hololol 2019. 6. 24. 14:51
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


//movingObject=>상속할 부모 역할이다. (추상클래스)
//player, enemy는 움직이는게 똑같다.(현재 위치 =>목적지 위치로 이동하는게 똑같음)
//겹치는 부분, 공통 부분을 상속을 받게끔 구성한다.
public abstract class MovingObject : MonoBehaviour
{
    public float moveTime=0.1f;
    public LayerMask blockingLayer; //상호작용을 위해서 LayerMask를 설정한다.
    //player과 wall은 상호작용. player<==>wall, enemy<=>player
  
    float inverseMoveTime;

    
    BoxCollider2D boxCollider;
    Rigidbody2D rb2D; 

    
    //오버라이드 할 수 있게 가상메소드로 만든다
    protected virtual void Start()
    {
        boxCollider = GetComponent<BoxCollider2D>();//박스 콜라이더를 잠깐 끄기위해 getComponent로 가져온다.
        rb2D = GetComponent<Rigidbody2D>();//목적지
        inverseMoveTime = 1 / moveTime;
    }

    //부드럽게 이동하기 (while)
    protected IEnumerator SmoothMovement(Vector3 end)
    {
        //목적지에 도착했는지 알아내기(남아있는 거리를 잰다)
        float distance = (transform.position - end).sqrMagnitude; //sqrMagnitude는 (거리의)제곱. 제곱을 하면 플러스가 됨.

        while(distance > float.Epsilon)
        {
            //MoveTowards  = 직선으로 3번째 값만큼 이동한다
            //rb2D.position = 나의위치
            //end = 목적지
            //inverseMoveTime * Time.deltaTime = 1/60만큼 끊어서 간다
            Vector3 newPos = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);

            //나의 위치로 진짜로 움직여라
            rb2D.MovePosition(newPos);


            //한번 움직이고 남은거리 계산
            distance = (transform.position - end).sqrMagnitude;

            //한 프레임만큼 휴식한다.
            yield return null;
        }
        

    }

    //앞에 장애물이 있는가 없는가
    //반환형이 여러개이고 싶을때 out을 씀.
    protected bool Move(int xDir, int yDir, out RaycastHit2D hit)
    {
        Vector2 start = transform.position; //start = 나의 위치
        Vector2 end = start + new Vector2(xDir, yDir); //end = start에서 움직여야하는 나의위치

        //나도 레이저에 걸리니 boxCollider 끔
        boxCollider.enabled = false;

        //start에서 end로 한 줄로 레이저를 쏘시오. blockingLayer가 아닌것은 인식하지 않음
        hit = Physics2D.Linecast(start, end, blockingLayer);

        //다시 Collider 살리기
        boxCollider.enabled = true;

        //부딪힌것이 없으면 나의 목적지로 움직인다
        if (hit.transform == null)
        {
            StartCoroutine(SmoothMovement(end));
            return true; //움직였다고 리턴 true값 반환
        }
        return false; //부딪히면 false 리턴


    }

    //공격하면서 움직인다
    //하나의 메소드를 만들었는데 반응하는 대상이 다르다
    protected virtual void AttempMove<T>(int xDir, int yDir)
        where T:Component //T자리에는 Component 대상만 들어갈 수 있다
    {

        RaycastHit2D hit;
        bool canMove = Move(xDir, yDir, out hit);

        if (hit.transform == null) return;

        //자료형에 컴포넌트를 가져와서 담는다
        T hitComponent = hit.transform.GetComponent<T>();


        //움직이지않고 hitComponent가 null이 아니라면
        if (!canMove && hitComponent != null)
            OnCantMove(hitComponent);

    }

    //본문이 존재하지 않는 추상메소드 생성
    protected abstract void OnCantMove<T>(T component)
        where T : Component;

}