본문 바로가기
게임 프로그래밍/게임개발 중급

게임개발 중급(16) - 2D 플랫포머 게임 만들기(11)

by jyppro 2023. 5. 6.

2D 플랫포머 게임 만들기(11)

 

저번에는 게임 자체를 멈출 수 있는 방법과, 추가로 ESC 키 입력을 통한 일시정지기능과 시각적 표현까지 구현 하였습니다. 이번에는 원래 하려고 계획했던 움직이는 장애물을 한번 만들어 보겠습니다.

 

움직이는 장애물 만들기

저는 기존에 만들어둔 장애물 프리팹에 새로운 스크립트를 추가하여 넣을 것이기 때문에, 프리팹을 하이어라키에 가져온 후, 새 스크립트를 적용한 새 프리팹을 만들도록 하겠습니다.

프리팹-생성
새로운 프리팹 생성

MovingObstacle 으로 새로운 프리팹을 생성하였습니다. 이 프리팹에 적용하게 될 코드는 이것입니다.

 

FixedMovingObstacle

using UnityEngine;

public class FixedMovingObstacle : MonoBehaviour
{
    public float speed = 5f;  // 장애물이 움직일 속도
    public float moveRange = 4f;

    private Vector2 moveDirection;  // 장애물이 움직일 방향

    void Start()
    {
        moveDirection = new Vector2(0f, 1f);
    }

    void Update()
    {
        // 장애물을 이동시킴
        transform.Translate(moveDirection * speed * Time.deltaTime);

        // 장애물이 움직일 범위를 벗어나면, 반대 방향으로 움직이도록 방향을 바꿈
        if (transform.position.y <= -moveRange || transform.position.y >= moveRange)
        {
            moveDirection *= -1f;
        }
    }
}

첫번째로 만들 움직이는 장애물은, 고정된 위치를 왔다갔다 하는 장애물 입니다. 속도와 범위를 정해주고, MoveDirection으로 방향을 정해줍니다. Update()에서 방향에 속도를 프레임마다 주어서 이동시킵니다. 하지만, 이렇게만 하면 한방향으로 계속 움직여서 맵 밖으로 날아갈 것입니다. 그래서 범위를 넘어가면 반대방향으로 움직이도록 해줍니다. 마찬가지로 반대방향도 벗어나지 못하도록 처리해줍니다.

 

이렇게 작성한 뒤에, 기존에 저희가 코인과 장애물을 생성할 때 사용한 제너레이터 스크립트에 public으로 게임오브젝트를 선언해주고 기존 장애물과 생성시간을 다르게 한 함수를 추가해 줍니다.

InvokeRepeating("SpawnFixedMovingObstacle", 0f, 8f); // 8초마다 SpawnObstacle 함수 실행

기존 장애물과 구분되도록 함수를 분리해서 하나 더 작성해 줍니다.

void SpawnFixedMovingObstacle()
    {
        Vector2 spawnPosition = new Vector2(10f, -3f);
        
        Instantiate(FixedMovingObstaclePrefab, spawnPosition, Quaternion.identity);
    }

이렇게 작성이 끝나면, 프리팹 사용법에서 말씀드렸던 것처럼 생성한 프리팹을 스크립트에 드래그 앤 드롭으로 연결시켜주어야 합니다. 연결한 다음 게임을 실행시켜보면..

 

움직이는-장애물1
움직이는 장애물

장애물이 Y축을 따라 위아래로 움직이는 모습을 볼 수 있습니다.

움직이는-장애물2
범위 안에서의 움직임

정해진 범위 밖으로 나가지 못하고 반복적으로 움직입니다.

 

이미 움직이는 장애물 만들기는 성공했지만, 저번주에 할 것을 미뤘으니 하나를 추가로 더 만들어 보겠습니다.

이번에는 랜덤하게 움직이는 장애물을 만들어 보겠습니다.

 

무작위로 움직이는 장애물 만들기

움직이는 장애물을 이미 만드셨다면, 그리 어렵지 않습니다. 장애물에 랜덤성을 부여해 주려면, 범위와 속도를 랜덤으로 부여해주면 됩니다.

 

우선, 이전과 마찬가지로 프리팹을 하나 더 생성하겠습니다. 이번엔 RandomMovingObstacle로 정해줍니다. 이전 프리팹도 헷갈릴 수 있으니 FixedMovingObstacle로 바꿔줍니다.

생성된-프리팹들
생성된 프리팹들

RandomMovingObstacle

생성한 프리팹을 다루는 방법은 이전과 같습니다. 굳이 한번 더 설명하지는 않겠습니다. 그럼 저희가 해줘야 할 것은 새로 스크립트를 짜는 것입니다.

 

using UnityEngine;

public class RandomMovingObstacle : MonoBehaviour
{
    public float moveRange = 4f;  // 장애물이 움직일 범위
    public float moveTime = 2f;  // 장애물이 한 방향으로 움직일 시간
    private float speed;
    private Vector2 moveDirection;  // 장애물이 움직일 방향
    private float timer;  // 타이머

    void Start()
    {
        // 장애물이 처음에 움직일 방향을 랜덤하게 설정
        moveDirection = new Vector2(Random.Range(-1f, 1f), Random.Range(-1f, 1f)).normalized;
        speed = Random.Range(2f, 5f);
    }

    void Update()
    {
        // 타이머가 moveTime을 초과하면 새로운 방향으로 움직임을 설정
        if (timer > moveTime)
        {
            moveDirection = new Vector2(Random.Range(-1f, 1f), Random.Range(-1f, 1f)).normalized;
            timer = 0f;
        }

        // 장애물을 이동시킴
        transform.Translate(moveDirection * speed * Time.deltaTime);

        // 장애물이 움직일 범위를 벗어나면, 반대 방향으로 움직이도록 방향을 바꿈
        if (transform.position.x < -moveRange || transform.position.x > moveRange ||
            transform.position.y < -moveRange || transform.position.y > moveRange)
        {
            moveDirection *= -1f;
        }

        timer += Time.deltaTime;
    }
}

이것이 새로 만든 RandomMovingObstacle 스크립트 입니다.

이전에 만든 Fixed와 다른 점은 움직일 시간과 타이머가 존재합니다. 더불어 랜덤성을 부여하기 위해 속도와 방향을 Random으로 부여해줍니다. 이렇게 코드를 작성하고 마찬가지로 제너레이터에도 선언과 함수를 추가시켜 줍니다. 저는 기본 장애물 5초, 고정움직임 장애물 8초, 랜덤 움직임 장애물 10초 마다 생성하도록 만들었습니다.

 

ObstacleSpawner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObstacleSpawner : MonoBehaviour
{
    public GameObject ObstaclePrefab;
    public GameObject FixedMovingObstaclePrefab;
    public GameObject RandomMovingObstaclePrefab;
    
    void Start()
    {
        InvokeRepeating("SpawnObstacle", 0f, 5f); // 5초마다 SpawnObstacle 함수 실행
        InvokeRepeating("SpawnFixedMovingObstacle", 0f, 8f); // 8초마다 실행
        InvokeRepeating("SpawnRandomMovingObstacle", 0f, 10f); // 10초마다 실행
    }
    
    void SpawnObstacle()
    {
        Vector2 spawnPosition = new Vector2(10f, -3f);
        
        Instantiate(ObstaclePrefab, spawnPosition, Quaternion.identity);
    }

    void SpawnFixedMovingObstacle()
    {
        Vector2 spawnPosition = new Vector2(10f, -3f);
        
        Instantiate(FixedMovingObstaclePrefab, spawnPosition, Quaternion.identity);
    }

    void SpawnRandomMovingObstacle()
    {
        Vector2 spawnPosition = new Vector2(10f, -3f);
        
        Instantiate(RandomMovingObstaclePrefab, spawnPosition, Quaternion.identity);
    }
}

현재 제너레이터 역할을 하는 ObstacleSpawner 스크립트의 모습입니다.

 

이제 게임을 실행시켜 보겠습니다.

 

랜덤하게-움직이는-장애물
랜덤하게 움직이는 장애물

가만히 있는 기본 장애물과, 위아래로 움직이는 장애물 그리고 랜덤하게 움직이는 장애물이 한번에 보입니다.

세 개의 장애물이 모이니 게임의 난이도가 이전과는 비교도 되지 않을 만큼 상승하였습니다.

 

<NEXT>

이번에는 고정적으로 움직이는 장애물 그리고 무작위로 움직이는 장애물을 만들어 보았습니다. 얼마 전까지만 해도 매우 단순했던 게임이 점점 새로운 것들이 추가되면서, 난이도가 높아지고 재밌어지게 되었습니다. 이제 2D 플랫포머 게임에 대한 기본적인 내용은 거의 다 한것 같습니다. 다음에는 여태껏 2D 플랫포머 게임 만들기를 하면서 사용한 오브젝트, 스크립트 등의 내용을 한번에 정리하고 2D 플랫포머 게임 만들기는 종료하고 다른 주제로 찾아오겠습니다. 감사합니다.