2교시의 도착점
학생은 교수자의 Scene 구조와 완성 코드를 보며 “무엇을 어디에 두고, 어떤 사건이 누구에게 전달되는가”를 설명합니다. 실제 레벨 제작은 3교시에 시작합니다.
- 형식교수자 이론과 시연
- 공간 구조Grid / Tilemap
- 행동 구조Prefab / Script
- 01
Grid, Tile Asset, Tile Palette, Tilemap의 역할을 한 문장씩 구분합니다.
- 02
Ground, Collision, Interaction을 분리해 그림, 물리, 사건의 책임을 보이게 만듭니다.
- 03
Prefab을 같은 Component와 설정을 가진 반복 가능한 원본으로 설명합니다.
- 04
네 Script의 callback이 하나의 PlayerProgress로 모이는 흐름을 추적합니다.
- Trigger 회수
접촉 후보가 callback이 되기까지 네 조건을 그림 없이 복원합니다.
- Tilemap 어휘
Grid부터 Tilemap Renderer까지 편집 도구와 실행 결과를 구분합니다.
- 세 Layer 구조
Ground, Collision, Interaction을 나눈 Scene Hierarchy를 해설합니다.
- Prefab과 Matrix
반복 행동의 원본과 필요한 접촉 조합만 남기는 필터를 연결합니다.
- 전체 코드 추적
수집, 리셋, 목표 판정이 PlayerProgress를 공유하는 흐름을 읽습니다.
- 상태 시나리오
수집 전과 후, 위험 접촉 뒤의 결과를 실행 전에 예측합니다.
Tilemap은 그림 한 장이 아니라 셀 데이터입니다
완성 화면만 보면 바닥이 하나의 이미지처럼 보입니다. 실제로는 Grid의 좌표 위에 “어느 셀에 어떤 Tile을 놓았는가”가 저장되고, Renderer와 Collider가 그 데이터를 각자의 방식으로 읽습니다.
Grid셀 좌표의 기준
여러 Tilemap이 같은 셀 크기와 정렬 규칙을 공유하도록 좌표 틀을 제공합니다. 보통 Tilemap을 만들면 부모에 함께 생깁니다.
Tile Asset한 칸의 데이터
한 셀에 표시할 Sprite와 색, Collider 형태 같은 정보를 담습니다. Scene의 GameObject가 아니라 Project의 Asset입니다.
Tile Palette편집용 도구함
사용할 Tile을 모아 두고 붓, 상자, 지우개로 Tilemap에 칠하게 해 줍니다. 게임이 실행될 때 화면에 보이는 UI는 아닙니다.
Tilemap셀 배치 기록
어느 좌표에 어떤 Tile이 놓였는지 저장하는 Component입니다. Ground와 Collision을 별도 GameObject로 나누면 책임이 선명해집니다.
Tilemap Renderer셀을 화면에 그림
Tilemap의 Sprite를 한꺼번에 렌더링합니다. Sorting Layer와 Order로 다른 Sprite 앞뒤 관계를 정합니다.
Tilemap Collider 2D셀을 물리 형상으로 바꿈
Tile의 Collider Type을 읽어 각 셀에 Collider 형상을 만듭니다. 벽처럼 막아야 하는 Tilemap에만 둡니다.
편집 도구와 실행 Component를 나눕니다
Tile Palette는 제작자가 칠할 때 사용하는 창입니다. 게임 속 레벨은 Grid와 Tilemap Component에 저장됩니다. 따라서 Palette 창을 닫아도 이미 칠한 레벨은 사라지지 않습니다.
Tile을 골라 셀에 칠할 때 직접 사용하는 것은?
편집 작업의 역할을 고릅니다.
그림, 물리, 사건을 서로 다른 층에 둡니다
모든 Tile을 한 Tilemap에 칠하면 처음에는 빨라 보입니다. 그러나 무엇이 막고 무엇이 장식인지 찾기 어려워집니다. 책임별 GameObject를 나누면 Scene을 보는 것만으로 수정 위치가 드러납니다.
바닥과 길을 그립니다. Tilemap Renderer는 사용하지만 Collider는 두지 않습니다. Player는 이 그림 위를 자유롭게 이동합니다.
벽과 경계를 칠합니다. Tilemap Collider 2D가 셀을 막는 형상으로 바꾸며 Environment Layer에 둡니다.
Collectible, HazardZone, GoalZone Prefab Instance를 담는 빈 부모입니다. 각각 Is Trigger가 켜진 Collider2D와 Script를 가집니다.
많이 반복되는 공간
격자에 맞춘 벽처럼 동일한 규칙이 넓게 반복될 때 유리합니다. 여러 셀의 Collider를 자동으로 관리합니다.
의미가 있는 개별 사건
수집, 위험, 목표처럼 각 Instance가 상태와 행동을 가질 때 유리합니다. 위치는 달라도 같은 Component 구성을 공유합니다.
Tilemap Collider 2D는 필요한 곳에만 둡니다
Ground까지 Collider를 가지면 Player가 이동해야 할 바닥이 장애물이 될 수 있습니다. 이번 주에는 Collision Tilemap 하나만 물리 벽을 담당하게 해 원인을 좁힙니다. 큰 Tilemap의 Collider 형상을 단순화하는 Composite Collider 2D는 원리를 이해한 뒤 선택적으로 사용합니다.
Tilemap Collider 2D가 필요한 곳은?
이번 주의 역할 분리 원칙을 적용합니다.
Prefab은 모양보다 행동 묶음을 반복합니다
수집물 세 개를 복사하는 목적은 같은 Sprite를 얻는 데 그치지 않습니다. Collider의 크기, Is Trigger, Layer, Script와 설정값까지 하나의 검증된 원본에서 반복하는 것이 핵심입니다.
정확히 세 Instance
Sprite Renderer, Circle Collider 2D, Collectible Script를 가집니다. 한 번 수집되면 PlayerProgress에 1을 전달하고 자신을 비활성화합니다.
정확히 두 Instance
구역을 보여 주는 Sprite, Box Collider 2D, HazardZone Script를 가집니다. Player를 시작 위치로 돌려보냅니다.
정확히 한 Instance
목표 문 Sprite, Box Collider 2D, GoalZone Script를 가집니다. PlayerProgress에 완료 조건을 질문합니다.
상태의 유일한 소유자
4주차 이동 Component에 PlayerProgress를 추가합니다. 수집 개수와 시작 위치를 한곳에서 관리해 Trigger끼리 직접 의존하지 않게 합니다.
이 표는 이번 레벨에 필요한 접촉만 남긴 개념 모델입니다. 실제 Matrix는 대칭이므로 한 Layer 조합을 바꾸면 반대쪽 관계도 함께 바뀝니다. Player는 벽과 부딪히고 Interaction을 감지하지만, 벽과 수집물끼리 서로 사건을 만들 필요는 없습니다.
수집물 세 개의 Collider 크기를 함께 수정하려면?
반복 가능한 원본의 장점을 고릅니다.
세 Trigger가 하나의 Player 상태를 공유합니다
각 Trigger는 자신이 감지한 사건만 해석합니다. 수집 개수와 시작 위치는 PlayerProgress 한 곳에 두고, 다른 Script는 필요한 public method만 요청합니다.
필요 개수, 현재 개수와 시작 위치를 기억합니다.
Player를 확인하고 수집 개수를 한 번 올립니다.
Player를 시작 위치로 돌려보냅니다.
필요 개수를 모았는지 질문하고 성공을 판정합니다.
using UnityEngine;
public class PlayerProgress : MonoBehaviour
{
[SerializeField, Min(1)]
private int requiredCollectibles = 3;
private int collectedCount;
private Rigidbody2D body;
private Vector2 startPosition;
private void Awake()
{
body = GetComponent<Rigidbody2D>();
}
private void Start()
{
startPosition = body.position;
}
public void AddCollectible()
{
collectedCount++;
Debug.Log("수집: " + collectedCount + " / " + requiredCollectibles);
}
public bool HasAllCollectibles()
{
return collectedCount >= requiredCollectibles;
}
public void ResetToStart()
{
body.linearVelocity = Vector2.zero;
body.position = startPosition;
}
}
private field상태는 PlayerProgress 안에서만 직접 바꿉니다. Inspector에 보여야 하는 필요 개수만 SerializeField로 노출합니다.AddCollectible()Collectible은 내부 field를 알지 않고 “하나를 더하라”는 요청만 보냅니다.HasAllCollectibles()GoalZone은 계산식을 복제하지 않고 bool 질문 하나로 완료 조건을 확인합니다.ResetToStart()위험 접촉은 Rigidbody2D의 속도를 0으로 만들고 물리 위치를 시작점으로 옮깁니다. 수집 개수는 유지됩니다.
using UnityEngine;
public class Collectible : MonoBehaviour
{
private bool collected;
private void OnTriggerEnter2D(Collider2D other)
{
if (collected || !other.CompareTag("Player"))
{
return;
}
if (!other.TryGetComponent(out PlayerProgress progress))
{
return;
}
collected = true;
progress.AddCollectible();
gameObject.SetActive(false);
}
}
using UnityEngine;
public class HazardZone : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D other)
{
if (!other.CompareTag("Player"))
{
return;
}
if (other.TryGetComponent(out PlayerProgress progress))
{
progress.ResetToStart();
}
}
}
using UnityEngine;
public class GoalZone : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D other)
{
if (!other.CompareTag("Player"))
{
return;
}
if (!other.TryGetComponent(out PlayerProgress progress))
{
return;
}
if (!progress.HasAllCollectibles())
{
Debug.Log("아직 수집물이 남았습니다.");
return;
}
Debug.Log("LEVEL COMPLETE");
}
}
TryGetComponent가 두 가지를 동시에 확인합니다
상대 GameObject에 PlayerProgress가 있는지 확인하고, 있다면 같은 줄에서 progress 변수로 받아 옵니다. 이번 구성에서는 Player Tag와 PlayerProgress가 같은 Player GameObject에 있어야 합니다.
화면보다 먼저 상태 변화를 예측합니다
같은 Scene도 접촉 순서에 따라 결과가 달라집니다. 교수자는 Play 전에 아래 시나리오를 제시하고, 학생에게 어떤 field와 위치가 바뀌는지 먼저 말하게 합니다.
0개 상태에서 Goal 접촉
HasAllCollectibles()가 false를 반환합니다. 완료되지 않고 “아직 수집물이 남았습니다”가 기록됩니다.
수집물 하나를 두 번 통과
첫 접촉 뒤 GameObject가 비활성화되고 collected 방어선도 생깁니다. 개수는 한 번만 증가합니다.
2개 수집 후 Hazard 접촉
Player 위치는 시작점으로 돌아가지만 collectedCount는 2를 유지합니다. 남은 하나만 찾으면 됩니다.
3개 수집 후 Goal 접촉
3 >= 3이 true가 되어 완료 메시지가 한 번 기록됩니다. 레벨의 최소 목표가 성립합니다.
시연에서 확인할 장면
- Hierarchy부터 읽기
Grid 아래 두 Tilemap과 Interactions 부모를 접은 상태에서도 책임이 보이는지 확인합니다.
- Prefab 원본 수정
Collectible Collider 반지름을 바꾸고 세 Instance가 같은 변경을 이어받는 모습을 보여 줍니다.
- Matrix 한 칸 끄기
Player와 Interaction 조합을 끄면 코드가 같아도 모든 Trigger 사건이 사라짐을 비교합니다.
- 상태 순서 실행
Goal 거절 → 수집 2 → Hazard → 수집 1 → Goal 성공 순서로 Console과 위치를 추적합니다.
Unity 6.6 공식 문서
Tilemap과 Prefab의 정확한 역할, Collider 생성 방식과 Component 탐색 동작은 아래 공식 문서를 기준으로 정리했습니다.
Introduction to Tilemaps ↗
Grid 위에 Tile을 배치해 2D 레벨을 만드는 Tilemap 시스템의 기본 구조
Tilemap Collider 2D ↗
Tile Collider Type을 읽어 셀마다 Collider 형상을 생성하는 방식
Prefabs ↗
Component, property와 child를 재사용 가능한 Asset 원본으로 저장하는 기능
Component.TryGetComponent ↗
GameObject에서 요청한 Component를 찾아 성공 여부와 참조를 함께 얻는 API
Layer Collision Matrix ↗
Layer 조합별 2D 접촉 계산을 Project 단위로 켜거나 끄는 설정
질문이 남았다면
“Collision Tilemap의 벽은 Player를 막지만 Collectible callback만 오지 않습니다. 두 Collider와 Player Rigidbody2D, Is Trigger까지 확인했습니다”처럼 정상인 층과 실패한 층을 나누어 말합니다.