1. 에셋 추가하기
유니티에는 '유니티' 단위가 있다
유니티를 확대하면 보이는 작은 크기의 타일들이다
작은 네모를 바로 1 유니티라고 하는데,
1 유니티 단위 당 100 픽셀이 기본값이다
이걸 바꾸면 이미지가 다른 사이즈로 바뀌게 끔 할 수 있는데,

Assets 파일을 집어넣은 뒤 Assets 파일 안의 이미지를 클릭, inspecter를 보면 Pixels Per Unit이 있다
이걸 50으로 조정하면 이미지의 1 유니티 단위당 픽셀이 50이 된다
쉽게 말하자면 1유니티 단위 안에 50 픽셀이 들어간다는 것이다
같은 단위 안에 더 많은 단위가 들어갈 수록 이미지가 작아질 것이고,
더 작은 숫자가 유니티 단위를 차지할 수록 이미지가 커질 것이다
이걸로 전체적인 에셋의 사이즈를 조정한 뒤, 맵 레이아웃에 들어가자
2. 기초 단계 레이아웃
우리는 아직도 캡슐을 가지고 운전을 하고 있기 때문에 우선 캡슐을 차 모양으로 바꿔야한다

캡슐 모양을 선택한 후 inspector의 sprite renderer를 살펴보면 Spirte라는 곳이 있다
이 곳에 원하는 모양을 넣으면 캡슐이 그 모양으로 변하게 된다
우리는 차 모양을 원하니 나는 사진처럼 Car 3를 지정해보았다
이대로 운전을 해서 circle에 부딪혀보면 충돌 범위가 약간 이상한 걸 알 수 있는데
바로 box collider의 범위 지정이 이상하기 때문이다

Edit collider에 있는 점 모양을 눌러보면 충돌 범위를 조정할 수 있으니,
차의 모양에 맞춰 움직여준다
또, Game 뷰를 보면 가끔 우리가 보는 사이즈에 비해서 너무 가까이서 보이거나 멀리 보이거나 할 수 있는데
이건 메인 카메라의 inspector에 들어가서 size를 조정해주면 된다
이번에는 hierarchy창을 정리해주자
먼저 empty object를 만들어준 뒤, 이름을 바꾼 후
우리가 추가한 asset들을 안에 싹 다 넣어줄거다

좌측의 삼각형 모양을 누르면 접기가 가능하니
보다 깔끔하게 관리할 수 있을 것이다

3. camera follow
카메라가 움직이는 차를 따라오도록 코딩해볼 것이다
c# script를 새로 만든 다음 FollowCamera를 만든다
스크립트를 메인 카메라에 적용한 뒤 코딩을 시작할 것이다
여기서는 Reference를 사용한다
스크립트가 적용된 게임 오브젝트 외의 것에 접근해야할 때 즉,
예를 들어 여기서는 카메라(게임 오브젝트)에 script를 적용했기 때문에 카메라의 transform에는 그냥 접근할 수 있지만
차의 transform에 접근해야한다면 이 대상에 접근할 것이라고 말해야한다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowCamera : MonoBehaviour
{
[SerializeField] GameObject thingToFollow;
void Update()
{
transform.position = thingToFollow.transform.position;
}
}
그래서 GameObject 타입인 thingToFollow 변수를 생성해준 뒤
카메라의 transform.position을 thingToFollow의 transform.position을 따라가게 설정한 뒤

ThingToFollow를 따라가게한다
그러면 바로...
...

이게 뭐냐 묻는다면 진짜로 차를 따라가게 만들었기 때문이라고 할 수 있다

맵이랑 차랑 붙어있기 때문에 잔디밭이 보일 수밖에 없다
약간의 거리를 둬야한다
예를 들어 z축을 -10정도하면 될 것 같다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowCamera : MonoBehaviour
{
[SerializeField] GameObject thingToFollow;
void Update()
{
transform.position = thingToFollow.transform.position + new Vector3 (0,0,-10);
}
}
position과 같은 타입으로 해야하기 때문에 Vector3을 만들어 더해준다
3-1. 유니티 실행 순서

간단하게 필요한 것만 설명해보자면
시작하기도 전에 조작이 필요하다면 awake를 사용하고,
일반적인 경우에는 start를 사용한다
update는 매 프레임마다 실행되는 동작을 말한다
late update는 업데이트 사이클이 끝난 뒤에 로직의 제일 마지막에 하는 업데이트다
나머지는 다른 강의에서 점차 배울 것이다
기존의 FollowCamera 코드를 수정해 Update를 LateUpdate로 바꿔주면
더욱 자연스러운 카메라 움직임을 볼 수 있다
4. if 구문 & 태그
물품 위를 지나가면 트리거를 지나가서(충돌) 콘솔에 어떤 메세지(대충 픽업했다는 뜻)을 출력할 것이다
그리고 손님과 부딪히면 택배를 배달하도록 할 것이다
이 구현을 위해 if문을 사용할 건데, if문은 참/거짓을 판별하는 문장으로
if ( this thing is true) {
do this thing;
}
다음과 같이 사용한다
근데 어떻게 택배를 인식할까? 바로 태그를 사용한다

Package의 inspector에 있는 상단에 tag를 눌러 add tag, Package를 추가한다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Delivery : MonoBehaviour
{
void OnCollisionEnter2D(Collision2D other)
{
Debug.Log("Ouch!");
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Package")
{
Debug.Log("Package picked up");
}
if (other.tag == "Customer")
{
Debug.Log("Package Deliverd");
}
}
}
other의 tag가 Package와 동일( == )하다면 Debug.Log를 출력하게끔 설정했다
과제로 Customer에게 전달하면 출력하라고도 나왔길래 천천히 시도해보았더니 되었다 (매우 기쁜 상태)
하지만 대충 했기도 하고 배운 게 아직 없어서
잔인하게도 고객을 밟고간다
다음 챕터에서 고객을 밟고가는 문제를 해결해보도록 하겠다
5. Bool 사용하기
bool은 변수 중에 하나로 참 혹은 거짓 둘 중에 (true, false) 하나를 담을 수 있다
if문과 함께 사용하는 유용한 친구다
# 변수를 선언한 뒤 지정하지 않으면 기본적으로 false로 설정되어 있다
아래 예제를 본 뒤 분석해보도록 하자
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Delivery : MonoBehaviour
{
bool hasPackage = false;
void OnCollisionEnter2D(Collision2D other)
{
Debug.Log("Ouch!");
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Package")
{
Debug.Log("Package picked up");
hasPackage = true;
}
if (other.tag == "Customer" && hasPackage)
{
Debug.Log("Package Deliverd");
hasPackage = false;
}
}
}
bool 타입의 hasPackage (이름은 bool임을 알 수 있게 작성한다) 를 생성한 뒤 false를 지정한다(안해도되긴하지만...)
그리고 물건을 픽업했다면 hasPackage를 true로 바꾸고,
Customer태그임과 동시에 물건을 들고있으면(hasPackage == true) 물건이 배달되었음을 콘솔로 알리고
hasPackage를 false로 바꾼다
5. 객체 삭제하기
destory는 게임 오브젝트를 삭제하는 것으로 두 가지를 pass in해줘야한다
pass in (지정해줘야한다)
1. 어떤 오브젝트가 destory되는지
2. destory되기까지 걸리는 시간은 어느정도인지
그리고
Destory(대상.gameObject, 시간);
다음과 같이 사용한다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Delivery : MonoBehaviour
{
bool hasPackage = false;
[SerializeField] float destroyTime = 0.5f;
void OnCollisionEnter2D(Collision2D other)
{
Debug.Log("Ouch!");
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Package" && !hasPackage)
{
Debug.Log("Package picked up");
hasPackage = true;
Destroy(other.gameObject, destroyTime);
}
if (other.tag == "Customer" && hasPackage)
{
Debug.Log("Package Deliverd");
hasPackage = false;
}
}
}
여기서 달라진 걸 보자면
한 개의 택배를 픽업한 뒤 다른 걸 픽업하지 못하게끔 !hasPackage로 바꿔줬다
!는 ~가 아닌 것 이라는 뜻으로 !hasPackage을 하면 false였던 것이 true로 바뀌면서 작동하게 된다
6. GetCompenent 사용하기
분홍색 물건을 픽업하고 나면, 분홍색 차로 바뀌게끔 스프라이트 렌더러를 사용할 것이다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Delivery : MonoBehaviour
{
[SerializeField] Color32 hasPackageColor = new Color32(1, 1, 1, 1);
[SerializeField] Color32 noPackageColor = new Color32(1, 1, 1, 1);
SpriteRenderer spriteRenderer;
void Start()
{
spriteRenderer = GetComponent<SpriteRenderer>();
}
bool hasPackage = false;
[SerializeField] float destroyTime = 0.5f;
void OnCollisionEnter2D(Collision2D other)
{
Debug.Log("Ouch!");
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Package" && !hasPackage)
{
Debug.Log("Package picked up");
hasPackage = true;
spriteRenderer.color = hasPackageColor;
Destroy(other.gameObject, destroyTime);
}
if (other.tag == "Customer" && hasPackage)
{
Debug.Log("Package Deliverd");
hasPackage = false;
spriteRenderer.color = noPackageColor;
}
}
}
스프라이트 렌더러는 "그림 담당" 컴포넌트라 할 수 있다
2D 이미지를 화면에 보여주는 컴포넌트로
예를 들어, 차, 패키지, 고객, 나무 같은 이미지가 화면에 보이는 건 SpriteRenderer 덕분이다
그럼 또 컴포넌트란 무엇인가로 넘어가야만 할 것 같다
Unity에서 게임 오브젝트는 "깡통 로봇" 같은 존재이고, 여러 기능을 가진 부품(컴포넌트)를 붙여야 움직일 수 있다
예를 들어 Unity에서 "자동차"라는 오브젝트를 만든다면:
- Transform → 자동차의 위치, 회전, 크기 (어디에 있는지 알려줌)
- SpriteRenderer → 자동차의 겉모습(이미지) 보여줌
- Rigidbody2D → 물리 법칙 적용 (중력, 속도, 관성 등)
- Collider2D → 충돌 감지 (벽이나 다른 오브젝트와 부딪힘)
- AudioSource → 소리 재생
이런 식으로 자동차에 필요한 "부품"을 하나씩 붙이는 거다.
컴포넌트를 쓰려면 GetComponent<>()로 꺼내올 수 있다
즉 이걸 이해하면
spriteRenderer = GetComponent<SpriteRenderer>(); 이 뜻은:
"이 오브젝트에 붙어 있는 SpriteRenderer 컴포넌트를 찾아서 변수 spriteRenderer에 저장하겠다" 는 의미로 이해된다
참고로 GetComponent<>()는 항상 자기 자신(GameObject)에 붙은 컴포넌트만 갖고오는데,
다른 오브젝트를 참조하고 싶다면
target(다른오브젝트).GetComponent<SpriteRenderer>()처럼 사용하면 된다
이른바 남의 로봇에서 부품을 빼오는 거다
7. 부스트&범퍼
이전에 다른 코드에서 짰던 것처럼 비슷하게 짜면 된다
OnTriggerEnter2D랑 OnCollisionEnter2D를 몰라서 함수명을 아무거나로 해버렸었지만
제대로 고쳤으니 됐다...
OnTriggerEnter2D와 OnCollisionEnter2D는 모두 무언가와 부딪혔을 때 실행되는 이벤트 함수이다
Trigger는 Is Trigger가 체크된 경우 사용하고, Collision은 쿵!! 하고 물리적 충돌이 발생했을 때 호출된다
이 둘은 이벤트 함수라 하고, 우리가 직접 호출하지 않아도 유니티 엔진이 특정 상황에서 자동으로 호출해주는 함수를 말한다
마치 Start()와 Update()처럼 말이다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Driver : MonoBehaviour
{
[SerializeField] float steerSpeed = 0.1f;
[SerializeField] float moveSpeed = 20f;
[SerializeField] float slowSpeed = 15f;
[SerializeField] float boostSpeed = 30f;
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "booster")
{
moveSpeed = boostSpeed;
}
}
void OnCollisionEnter2D(Collision2D collision)
{
moveSpeed = slowSpeed;
}
void Update()
{
float steerAmount = Input.GetAxis("Horizontal") * steerSpeed * Time.deltaTime;
float moveAmount = Input.GetAxis("Vertical") * moveSpeed * Time.deltaTime;
transform.Rotate(0, 0, -steerAmount);
transform.Translate(0, moveAmount, 0);
}
}
다음과 같이 코드를 짜면 이제 완성이다

이렇게 하면 첫 게임의 완성이다
원하는 기능을 넣기위해 조금의 수정과 조언을 얻겠지만 우선은, 우선은 끝났다
시작하기 전까지에는 도전하는 것이 무서워서 도망치고 싶었지만 잘 시작했다
어쩌면 이런 작은 시작이 전부일지도 모르겠다, 지금은 그 말에 동의하게 된다.
TA로 가는 작은 발걸음을 옮겼다 아직은 뭐에서 시작해서 TA까지 가게될지 모르겠지만
우선 그냥 했다
친구에게서 받은 작은 책 한권에 써있는 말대로 '그냥 했다'
TA가 잘 될 수 있을까요? -> "지금 필요한 건 걱정이 아니라 실행이다"
그냥 나아가다보면 멋진 사람이 되어있을지도...
그냥 하자
라는 결론으로 글을 끝낸다
'유데미 > C# Unity 2D' 카테고리의 다른 글
| Snow Boarder - 3 (42강-완) (0) | 2025.09.25 |
|---|---|
| Snow Boarder - 2 (35-41강) (1) | 2025.08.31 |
| Snow Boarder - 1 (29-34강) (0) | 2025.08.22 |
| Delivery Driver - 2 (16-20강) (2) | 2025.08.16 |
| Delivery Driver - 1 (9-15강) (4) | 2025.08.12 |
