이제 플레이어도 만들어서 이동스크립트도 넣어주고
본격적인 '필드'도 만들고 문도 만들어서 맵 이동까지 만들어보자

목표는 위와 같다
(실제로는 여기에 모바일을 위한 추가로 조이스틱을 넣었다)
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를 사용해서 좌표를 입력하면 해당 좌표로 지정한 시간동안 이동하고
이동 전 '플레이어'의 충돌 콜라이더를 껐다가, 이동 후 다시 켜주는 코드를 넣어준다
이런식으로 좌표를 기반으로 구현하면 간단하게 맵 배치와 이동을 구현할 수 있다
'유니티 > 실습' 카테고리의 다른 글
게임 개발일지 - 제목미정 - 1 - 시스템 (2) | 2022.04.27 |
---|---|
게임 개발일지 - 제목미정 - 0 - 무엇을 만들까? (0) | 2022.04.27 |
바인딩오브아이작 만들기 - 그리드맵 생성 - 1 (0) | 2022.04.19 |
바인딩오브아이작 만들기 - 그리드맵 생성 - 0 (2) | 2022.04.17 |
오브젝트풀 - 체인라이트닝 (0) | 2022.02.15 |