유니티/실습

바인딩오브아이작 만들기 - 그리드맵 생성 - 2

파란색까마귀 2022. 4. 19. 21:34

 

이제 플레이어도 만들어서 이동스크립트도 넣어주고

본격적인 '필드'도 만들고 문도 만들어서 맵 이동까지 만들어보자

 

 

목표는 위와 같다

(실제로는 여기에 모바일을 위한 추가로 조이스틱을 넣었다)

 

rigidbody2D가 적용된 'player'오브젝트와

해당 오브젝트가 돌아다닐수 있는 '필드' 그리고 각 필드의 '상하좌우'를 제한하는 '벽'을 만들고

방을 오갈 수 있는 '문' 오브젝트를 각각 네 방향에 배치했다

한쪽 구석에는 '맵'을 확인할 수 있는 오브젝트를 배치해놨다

 

오브젝트 배치 및 카메라 설정은 따로 기술하지 않겠다

그냥 2D콜라이더와 리지드바디2D를 믿기로 했다

 

다만 특이점은, 문 오브젝트의 경우 tag값으로 Door를 설정해줬다

 

플레이어 동작 오브젝트도 간단하게 만들었다

private void Update()
	{
		m_horMove = Input.GetAxisRaw("Horizontal");
		m_verMove = Input.GetAxisRaw("Vertical");
	}

대충 horizontal과 Vertical입력을 받아서

 

public void FixedUpdate()
	{
		if (!m_playerActive)
			return;

		//m_horMove = m_moveJoystick.Horizontal;
		//m_verMove = m_moveJoystick.Vertical;

		Vector3 direction = Vector3.up * m_verMove * m_speed * Time.deltaTime + Vector3.right * m_horMove * m_speed * Time.deltaTime;
		rb.MovePosition(transform.position + direction);
}

 

FixedUpdate에서 입력에 따라 이동하도록 수정해줬다

이때 PlayerActive변수를 통해 '조정가능' 여부를 확인하는 방식으로 간단하게 구성했다

 

private void OnTriggerEnter2D(Collider2D collision)
	{
		if (collision.tag == "Door")
		{
			Door temp = collision.GetComponent<Door>();
			if (temp.DoorType == 0)
			{
				this.transform.position = new Vector2(this.transform.position.x, -2.8f);
			}
			else if (temp.DoorType == 1)
			{
				this.transform.position = new Vector2(this.transform.position.x, 2.8f);
			}
			else if (temp.DoorType == 2)
			{
				this.transform.position = new Vector2(6.8f, this.transform.position.y);
			}
			else if (temp.DoorType == 3)
			{
				this.transform.position = new Vector2(-6.8f, this.transform.position.y);
			}
			Debug.Log(temp.gameObject.name);
			m_fieldManager.SendMessage("DoorKnock", temp.DoorType);
		}
	}

 

그리고 충돌 감지 스크립트를 넣어서 '문'에 충돌했을때 문 좌표에서 약간 앞쪽에 위치로 이동하도록 해줘서

'문'에 연속적으로 부딪히지 않게 조절했다

 

그리고 fieldManager에 SendMessage로 함수를 발동시킨다

 

그전에.. 먼저 필드 생성을 해줘야되서

처음 만든 필드를 프리펩으로 설정한 뒤 필드 타입 스크립트를 넣어준다

 

public class FieldType : MonoBehaviour
{
    private List<BoxCollider2D> m_colliders = new List<BoxCollider2D>();
    private List<Door> m_doors = new List<Door>();
	[HideInInspector]
    public int[] Doors = new int[4];
	private void Start()
	{
		int count = this.transform.childCount;
		for (int i = 0; i < count; i++)
		{
			BoxCollider2D box = this.transform.GetChild(i).GetComponent<BoxCollider2D>();
			if (box != null)
			{
				m_colliders.Add(box);
				if (box.GetComponent<Door>() != null)
				{
					m_doors.Add(box.GetComponent<Door>());
				}
			}
		}

		for (int i = 0; i < 4; i++)
		{
			if (Doors[i] == -1)
				m_doors[i].gameObject.SetActive(false);
			else
				m_doors[i].gameObject.SetActive(true);
		}
	}

	public void SetColliderActive(bool isActive)
	{
		int count = m_colliders.Count;
		for (int i = 0; i < count; i++)
		{
			m_colliders[i].enabled = isActive;
		}
	}
}

 

'이동'할때 '문'에 부딪히지 않도록 '활성/비활성화' 함수도 넣어주고

문 오브젝트 관리 함수도 넣어준다

 

그리고 이전에 만든 RoomManager.cs에서

 

private void SetRoomConnection()
{
	~생략~
	SetRoomPrefabs();
}

 

각 방 리스트의 '연결된 방' 정보를 갱신한 다음 필드 오브젝트 생성 함수를 넣는다

 

 

	private void SetRoomPrefabs()
	{
		m_complete = true;

		for (int i = 1; i < m_roomList.Count; i++)
		{
			Debug.Log(m_roomList[i].m_currentPos);
			Vector2 pos = new Vector2(m_roomList[i].m_currentPos.x * 18, m_roomList[i].m_currentPos.y * -10);
			GameObject obj = Instantiate(m_fieldPrefabs, pos, Quaternion.identity, m_fieldManager.transform);

			obj.GetComponent<FieldType>().Doors[0] = m_roomList[i].m_myTopIndex;
			obj.GetComponent<FieldType>().Doors[1] = m_roomList[i].m_myBottomIndex;
			obj.GetComponent<FieldType>().Doors[2] = m_roomList[i].m_myLeftIndex;
			obj.GetComponent<FieldType>().Doors[3] = m_roomList[i].m_myRightIndex;
		}

		m_fieldManager.gameObject.SetActive(true);
		m_fieldManager.RegistRoom();
	}

 

생성 조건은 간단하다

미리 만들어둔 프리펩을 각 '방'의 좌표값에 맞춰서 x,y 위치를 잡아줘서 생성하고

각 방의 연결된 방이 있는지 확인하는 변수를 정보에 넣어준다음

해당 조건을 바탕으로 관리 함수에 등록한다 (RegistRoom())

 

    public PlayerController m_player;
    private List<FieldType> m_rooms = new List<FieldType>();

	public void RegistRoom()
	{
		for (int i = 0; i < this.transform.childCount; i++)
		{
			m_rooms.Add(this.transform.GetChild(i).GetComponent<FieldType>());
		}
	}

 

FieldManager는 더 간단하다

먼저 List하나를 두어 '필드'를 저장해두고

 

플레이어 함수에서 문에 '충돌'해서 'DoorKnock' 함수를 발동시켰을때 동작할 함수를 생성해준다

 

    public void DoorKnock(int direction)
    {
        if (direction == 0)//up
        {
            StartCoroutine(CoMoveMap(new Vector2(this.transform.position.x, this.transform.position.y - 10)));
        }
        else if (direction == 1)//down
        {
            StartCoroutine(CoMoveMap(new Vector2(this.transform.position.x, this.transform.position.y + 10)));
        }
        else if (direction == 2)//left
        {
            StartCoroutine(CoMoveMap(new Vector2(this.transform.position.x + 18, this.transform.position.y)));
        }
        else if (direction == 3)//right
        {
            StartCoroutine(CoMoveMap(new Vector2(this.transform.position.x - 18, this.transform.position.y)));
        }
    }

 

바로 맵 전체를 상하좌우에 맞춰서 이동시켜주는 함수다

 

    private IEnumerator CoMoveMap(Vector2 mapDirection)
    {
        for (int i = 0; i < m_rooms.Count; i++)
        {
            m_rooms[i].SetColliderActive(false);
        }

        m_player.SendMessage("IsPlayerActive", false);

        Vector2 currentPos = this.transform.position;
        float delta = 0;
        float duration = 0.5f;

        while (delta < 1)
        {
            delta += Time.deltaTime / duration;

            this.transform.position = Vector2.Lerp(currentPos, mapDirection, delta);
            yield return null;
        }

        this.transform.position = mapDirection;
        Debug.Log("DONE");

        for (int i = 0; i < m_rooms.Count; i++)
        {
            m_rooms[i].SetColliderActive(true);
        }

        m_player.SendMessage("IsPlayerActive", true);

    }

 

코루틴과 Lerp를 사용해서 좌표를 입력하면 해당 좌표로 지정한 시간동안 이동하고

이동 전 '플레이어'의 충돌 콜라이더를 껐다가, 이동 후 다시 켜주는 코드를 넣어준다

 

이런식으로 좌표를 기반으로 구현하면 간단하게 맵 배치와 이동을 구현할 수 있다

 

 

 

728x90