Carrot
본문 바로가기
Unity/멋쟁이사자처럼 부트캠프

[멋쟁이사자처럼부트캠프] 유니티 게임 개발 5기(31일차) - 2D 플랫포머 게임 (6)

by 독기품은토끼 2025. 6. 30.
✅ 오늘의 학습 목표
1. 타일 맵 제작
2. 맵 기믹 제작

 

1. Adventure 맵 제작

1. 2D Renderer

씬을 생성하면 보통 3D 환경에 맞는 렌더 파이프라인이 생성된다고 한다.

2D 게임에 적합한 환경을 만들어주기 위해서 2D 전용 렌더 파이프라인을 생성해 주자

 

1.1. 생성

 

2D Renderer Data와 Universal Render Pipeline Asset 두 가지가 함께 생성된다.

 

1.2. 적용

 

▶ 유니티의 두 렌더링 설정 위치

[Project Settings > Graphics]

전체 프로젝트 기본 파이프라인을 바꾸는 곳

  • 여기다 2D Render Pipeline을 넣어주면 씬 뷰나 에디터 뷰에서부터 2D 특화 렌더링이 적용된다.
  • 안 넣으면, 에디터에서는 이상하게 조명이 깨져 보인다거나 2D Light가 안 먹을 수 있음.

[Project Settings > Quality]

게임 실행 시 실제로 사용되는 렌더링 설정

  • Quality 탭은 각 퀄리티 레벨마다 따로 파이프라인 설정이 가능함 (예: PC/모바일 따로 설정 가능)
  • 모바일 빌드할 때 Mobile 퀄리티에 따로 설정 안 해주면 적용 안 됨 😅
  • 여기도 2D Render Pipeline Asset을 넣어줘야, 게임 실행 중에도 2D 조명/렌더링이 정상 적용된다.

 

2. 플랫포머 맵 만들기

 

맵을 적절하게 만들어주고 콜라이더 및 리지드바디를 적용시켜 준다.

 

  • Tag: "Ground"로 설정 → 땅인지 판별하려고
  • Composite Operation = Merge → 타일 콜라이더 하나로 합치기
  • Rigidbody2D: Static → 움직이지 않는 땅은 물리 계산 X
  • Composite Collider 2D → 합치기 위해 필요

 

그리고 메인 카메라에 기존에 만들어둔 CameraFollow 스크립트도 넣어주고 최소/최댓값을 맵 크기에 맞게 설정해 준다.

 

 

2. 맵 기믹 제작

🥕 예행 작업
1. Scripts 생성 (PushPlatform, MovingPlatform)
2. Sprite Image 준비

 

1. 움직이는 상자

 

단순히 콜라이더 적용한 상자를 배치해 주면 된다.

 

 

2. 사다리 (줄)

 

사다리 (줄)이 될만한 오브젝트를 만들어주고 아래 코드를 적용해 준다

using UnityEngine;

public class KnightController_Keyboard : MonoBehaviour
{
    private bool isLadder;

    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Ladder"))
        {
            isLadder = true;
            // 물리적인 값이 남아있을 수 있으므로 초기화
            knightRb.gravityScale = 0f; // 사다리에서는 중력으로 인한 떨어짐이 없어야 함
            knightRb.linearVelocity = Vector2.zero;
        }
    }

    void OnTriggerExit2D(Collider2D other)
    {
        if (other.CompareTag("Ladder"))
        {
            isLadder = false;
            knightRb.gravityScale = 2f;
            knightRb.linearVelocity = Vector2.zero;
        }
    }

    void Move()
    {
        if (inputDir.x != 0)
        {
            var scaleX = inputDir.x > 0 ? 1 : -1;
            transform.localScale = new Vector3(scaleX, 1, 1);

            knightRb.linearVelocityX = inputDir.x * moveSpeed;
        }

        if (isLadder && inputDir.y != 0)
        {
            knightRb.linearVelocityY = inputDir.y * moveSpeed;
        }
    }
}

 

이렇게만 하면 사다리 기능은 작동하지만,
플레이어가 사다리 꼭대기에서 지면으로 올라갈 때 막히는 문제가 생긴다.

 

 

타일맵에 Platform Effector 2D 컴포넌트를 추가하고 Composite Collider 2D의 'Used by Effector' 옵션을 체크해 주면 해결된다.

이 설정을 하면 지면 위로는 올라갈 수 있고 아래로는 자연스럽게 통과할 수 있는 일방향 플랫폼(One-way platform) 처리가 가능해진다.

 

하지만 이렇게 설정하면 옆에서 해당 지면으로 들어갈 때도 통과가 가능해져 버린다.
이건 게임 상황에 따라 막아야 할 수도 있는데 강의에서는 이 부분의 처리 로직은 생략되었다.

실제로 제작할 땐 조건을 걸어서 사다리를 통해 위에서만 통과 가능하게 구현해 주는 게 좋을 것 같다.

 

 

 

3. 점프 발판

점프 발판이 될 애니메이션 오브젝트를 배치해 준 다음

 

 

트리거 파라미터를 생성해서

플레이어가 발판을 밟았을 때에만 애니메이션이 실행되도록 구현해 준다.

 

using UnityEngine;

public class PushPlatform : MonoBehaviour
{
    private Animator animator;
    private Rigidbody2D targetRb;
    [SerializeField] private float pushPower = 50f;

    void Start()
    {
        animator = GetComponent<Animator>();
    }
    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            targetRb = other.GetComponent<Rigidbody2D>();
            Invoke("PushCharacter", 1f);
        }
    }

    private void PushCharacter()
    {
        targetRb.AddForceY(pushPower, ForceMode2D.Impulse);
        animator.SetTrigger("[Trigger] Push");
    }
}

 

 

 

4. 움직이는 플랫폼

움직이는 플랫폼은 기존에 배운 삼각함수를 활용해서 만들어주려고 한다.

 

 

강사님은 스프라이트 이미지를 통해서 오브젝트를 만들어주었는데

나는 타일맵으로 만들어주었고 태그는 Ground로 설정하고 콜라이더까지 적용해 주었다.

 

using UnityEngine;

public class MovingPlatform : MonoBehaviour
{
    public enum MoveType { Horizontal, Vertical }
    public MoveType moveType;

    public float theta;
    public float power = 0.1f;
    public float speed = 1f;

    private Vector3 initPos;

    void Start()
    {
        initPos = transform.position;
    }

    void Update()
    {
        theta += Time.deltaTime * speed;
        transform.position = new Vector3(initPos.x + power * Mathf.Sin(theta), initPos.y, initPos.z);
    }
}

 

플랫폼이 움직일 수 있도록 삼각함수를 구현해 주었다.

 

그런데 이렇게만 구현하면 플레이어가 플랫폼에 올라탔을 때 방향키로 같이 움직여주어야 플레이어가 같이 이동되는 현상이 있다.

 

void Update()
{
    theta += Time.deltaTime * speed;

    if (moveType == MoveType.Horizontal)
        transform.position = new Vector3(initPos.x + power * Mathf.Sin(theta), initPos.y, initPos.z);
    else if (moveType == MoveType.Vertical)
        transform.position = new Vector3(initPos.x, initPos.y + power * Mathf.Sin(theta), initPos.z);
}

// 움직이는 플랫폼 위에 플레이어가 있으면 같이 움직이도록
void OnCollisionEnter2D(Collision2D other)
{
    if (other.gameObject.CompareTag("Player"))
    {
        other.transform.SetParent(transform);
    }
}

void OnCollisionExit2D(Collision2D other)
{
    if (other.gameObject.CompareTag("Player"))
    {
        other.transform.SetParent(null);
    }
}

 

이 부분을 보완해 주기 위해서 플레이어가 플랫폼에 올라탔을 때에만 플레이어의 오브젝트가 플랫폼의 자식 오브젝트로 할당되게끔 바꿔주었다.

이렇게 하면 플레이어가 플랫폼 위에 있을 때, 부모 오브젝트(플랫폼)의 움직임을 따라가게 된다.

 

또한 플랫폼이 좌우 또는 상하로 다르게 움직일 수 있도록 enum을 활용해 타입을 구분해 주었고,
실제로 각 플랫폼마다 Horizontal, Vertical 값을 따로 설정해 주었다.

 

 

 

5. Light

맵의 일부 부분만 밝게 해 주려는 처리를 해주려고 한다.

Light값을 조절하기 위해서 본문 가장 처음에 다루었던 Render 설정을 꼭 해주어야 하니 참고 바란다.

 

 

우선 라이트를 적용하기 위해서 글로벌 라이트와 일부분만 밝게 처리할 Freeform 라이트 2개를 생성해 준다.

 

 

Global Light는 맵 전체의 밝기를 조절하려고 사용하고 있다.

Freeform Light만 사용할 경우 Global Light가 없으면 씬 전체가 어둡게 보이니 항상 Global Light와 함께 사용해야 자연스럽다.

그리고 Global Light에서 일부분만 밝게 보이는 것을 조금 더 강조하기 위해서 Intensity 값을 조금 내려주었다.

 

 

만약 맵의 밝기가 낮아지지 않는다면 타일맵의 머테리얼이 Lit 이 맞는지 확인해보아야 한다.

 

 

 


 

 

오늘부터 강사님&멘토님이랑 커피챗이 시작되었다.

대화 내내 무슨 내용으로 이야기하실지 궁금하다.. 나는 아직 무슨 게임을 개발하고 싶은지 잘 모르겠어서 할만한 이야기가 있을지도 잘 모르겠고ㅜㅜ.. 뭔가 무섭다..!!