반응형

https://www.youtube.com/watch?v=LrpaW6VglVU 

 

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


//일반형(generic) 을 사용하는 이유 플레이어, 적, 벽 과의 상호작용에서 서로서로 hitComponent 의 종류를 알 수 없기 때문에 당장 OnCantMove 함수에 입력을 받고 각각의 상속한 클래스들의 구현에 따라 동작하게 할 수 있기 때문이다.
public abstract class MovingObject : MonoBehaviour
{
    public float moveTime = 0.1f;
    public LayerMask blockingLayer; //충돌여부 변수


    private BoxCollider2D boxCollider;
    private Rigidbody2D rb2D; //객체의 움직임 레퍼런스를 담을 변수
    private float inverseMoveTime; //움직임을 효율적이게 계산하기 위한 변수


    // Start is called before the first frame update
    protected virtual void Start()//자식 클래스가 덮어써서 재정의 하기 위해 start 를 다시 정의할 수도있어서
    {
        boxCollider = GetComponent<BoxCollider2D>();
        rb2D = GetComponent<Rigidbody2D>();
        inverseMoveTime = 1f / moveTime; //나누기 대신에 효율적인 곱하기를 사용하기 위해 움직임의 역수치를 저장
    }

    protected bool Move (int xDir, int yDir, out RaycastHit2D hit)//bool 리턴값, hit 리턴값 두개의 리턴값을 가짐
    {
        Vector2 start = transform.position; //현재위치를 받기위한 변수
        // position 은 기존 3차원 이지만 Vector 2에 저장함으로 z 값은 날라가게됨 
        Vector2 end = start + new Vector2(xDir, yDir);

        boxCollider.enabled = false;//자기자신과 부딛히지 않기 위해 boxCollider 해제
        hit = Physics2D.Linecast(start, end, blockingLayer); // 시작지점과 끝지점 까지의 라인을 가져오고 blockinglayer 와 충돌검사
        boxCollider.enabled = true; 

        if(hit.transform == null)//부딪힌게 없다면
        {
            StartCoroutine(SmoothMovement(end));//end 방향으로 이동
            return true;
        }
        return false;
    }


    protected IEnumerator SmoothMovement (Vector3 end)//객체를 움직이게 할 함수 end에 어디로 움직일지 저장
    {
        float sqrRemainingDistance = (transform.position - end).sqrMagnitude; // 현재위치 - end 벡터에 sqrMagnitude 로 거리계산 Magnitude : 벡터길이 , sqrMagnitude : 벡터길이 제곱 

        while (sqrRemainingDistance > float.Epsilon)
        {
            Vector3 newPosition = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime); // epsilon (0에 가까운 아주작은 수 ) newposition 을 계산하여 end 값과 가장가까운 위치로 이동시키기 위한 변수
            //(현재위치(rigidpositon), 이동할위치, 시간(이 변수의 단위만틈 목적지로 가까워짐)) 
            rb2D.MovePosition(newPosition); // 새로운 위치로 이동
            sqrRemainingDistance = (transform.position - end).sqrMagnitude; // 움직인 후 남은 거리 계산 
            yield return null; //루프를 갱신하기 전에 다음 프레임을 기다림
        }
    }

    protected virtual void AttemptMove <T> (int xDir, int yDir)
        where T : Component
    {
        RaycastHit2D hit;
        bool canMove = Move(xDir, yDir, out hit);//이동하는데 성공하면 canMove = true else flase    

        if (hit.transform == null)//다른것과 부딪히지 않았다면 코드 종료
            return;

        T hitComponent = hit.transform.GetComponent<T>(); //충동할 레퍼런스를 T 타입 컴포넌트에 할당 

        if (!canMove && hitComponent != null)//움직임이 막힘 -> 충돌
            OnCantMove(hitComponent);
    }

    protected abstract void OnCantMove<T>(T component)
        where T : Component;// 자식 클래스에서 오버라이드 위해 남겨둠 
}

 

일반형(Generic) 타입을 사용하는 이유 

 

플레이어, 적, 벽 과의 상호작용에서 서로서로 hitComponent 의 종류를 알 수 없기 때문에 당장 OnCantMove 함수에 입력을 받고 각각의 상속한 클래스들의 구현에 따라 동작하게 할 수 있기 때문이다.

반응형

'Unity > 로그라이크 따라해보기' 카테고리의 다른 글

로그라이크 따라하기 7,8,9  (0) 2021.07.09

+ Recent posts