Unity/Unity 기초

Unity 강의 5일차 (2) - 점프 게임 디테일 추가

하참이 2025. 1. 20. 11:54

본 강의는 다음 문서를 참고하여 제작하였습니다. 자세한 내용은 하단 링크를 참조하시거나 댓글로 질문 남겨주시면 성심성의껏 답변 드리겠습니다.

 

https://learn.unity.com/tutorial/3-2gang-weoldeuga-bbareuge-jinagadorog-guhyeon?uv=2021.3&pathwayId=63ca4663edbc2a7be103183f&missionId=63c7676bedbc2a66daff99b1&projectId=63ca1d01edbc2a5f4807369e#63ca1d7dedbc2a4ff80d890f

 

3.2강 - 월드가 빠르게 지나가도록 구현 - Unity Learn

개요: 지금까지 플레이어가 스페이스바를 눌러 다가오는 장애물을 뛰어넘는 게임의 핵심 메카닉을 구현했습니다. 그러나 처음 몇 초 동안은 플레이어가 달리는 것처럼 보이지만, 곧 배경이 사

learn.unity.com

 


 

 

지난시간엔 점프 게임을 구현하기 위해 기초적인 환경을 설정하였습니다. 기존에 배웠던 것들을 응용하는 단계기에 어렵지는 않았을 것 입니다.

 

이번엔 맵이 움직이도록 하여 캐릭터가 빠르게 이동하는 듯한 연출을 부여해보도록 하겠습니다.

 

RepeatBackground.cs라는 새 스크립트를 만들고 Background 오브젝트에 연결합니다.

 

 

 

 

 

배경이 반복되는 것처럼 보이도록 하기 위해 초기 위치를 설정해줍니다. ReapeatBackground 코드를 다음과 같이 작성합니다.

 

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

public class RepeatBackground : MonoBehaviour
{
    private Vector3 startPos;
    // Start is called before the first frame update
    void Start()
    {
        startPos = transform.position;
    }

    // Update is called once per frame
    void Update()
    {
        if (transform.position.x < startPos.x - 50)
        {
            transform.position = startPos;
        }
    }
}

 

 

배경이 시작 위치에서 x축 기준 50만큼 움직여서 차이가 생기게 되면 시작위치로 돌려놓는 코드입니다. 하지만 아직 배경이 움직이지는 않네요. MoveLeft 컴포넌트를 Background에도 추가해줍시다.

 

배경에 BoxCollider를 추가해줍시다.

 

 

 

 

 

그리고 RepeatBackground 스크립트를 다음과 같이 정리합니다.

 

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

public class RepeatBackground : MonoBehaviour
{
    private Vector3 startPos;
    private float repeatWidth;
    // Start is called before the first frame update
    void Start()
    {
        startPos = transform.position;
        repeatWidth = GetComponent<BoxCollider>().size.x / 2;
    }

    // Update is called once per frame
    void Update()
    {
        if (transform.position.x < startPos.x - repeatWidth)
        {
            transform.position = startPos;
        }
    }
}

 

 

 

이제 게임 오버를 생성해봅시다.

 

하이어라키창에서의 ground를 찾고 Ground 태그를 달아줄 것 입니다.

 

 

 

 

 

태그는 게임 오브젝트를 구분짓고 정리, 분류하기 위한 기능입니다. 이를 이용해서 게임 오브젝트중에서 Player 오브젝트만 찾아서 함수를 호출 할 수 도 있고, 아군은 피하고 적은 맞는 총을 발사 하는 등의 구분이 필요한 행동이 가능해집니다.

 

PlayerController를 다음과 같이 수정합니다.

 

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

public class PlayerController : MonoBehaviour
{
    private Rigidbody playerRb;
    public float jumpForce = 10;
    public float gravityModifier = 1;
    public bool isOnGround = true;
    public bool gameOver = false;

    // Start is called before the first frame update
    void Start()
    {
        playerRb = GetComponent<Rigidbody>();
        Physics.gravity *= gravityModifier;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space) && isOnGround)
        {
            playerRb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
            isOnGround = false;
        }        
    }
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("Ground"))
        {
            isOnGround = true;
        }
        if (collision.gameObject.CompareTag("Obstacle"))
        {
            gameOver = true;
            Debug.Log("Game Over");
        }
    }
}

 

Ground 태그와 닿으면 땅에 닿은 판정을, Obstacle 태그에 닿으면 게임 오버 판정을 하도록 한 것 입니다. 이런식으로 태그는 오브젝트를 구분짓는 역할을 가능하게 해줍니다.

 

그러므로 장애물에도 Obstacle 태그를 생성하고 추가해줍니다.

 

 

 

게임을 실행해서 장애물에 부딪히면 게임오버로그가 뜨는것을 확인할 수 있습니다.

 

 

 

gameover시 맵과 장애물이 움직이지 않게 코드를 수정합시다.

 

MoveLeft 스크립트를 다음과 같이 수정합니다.

 

 

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

public class MoveLeft : MonoBehaviour
{
    private float speed = 30;
    private PlayerController playerControllerScript;
    // Start is called before the first frame update
    void Start()
    {
        playerControllerScript = GameObject.Find("Player").GetComponent<PlayerController>();
    }

    // Update is called once per frame
    void Update()
    {
        if (playerControllerScript.gameOver == false)
        {
            transform.Translate(Vector3.left * Time.deltaTime * speed);
        }
    }
}

 

 

 

GameObject.Find는 인자로 받은 문자열과 같은 이름을 가진 게임 오브젝트를 반환하는 메서드 입니다. 이를 이용하여 씬에 있는 Player 게임 오브젝트를 찾을 수 있습니다. Player의 PlayerController 스크립트 컴포넌트에 접근해 gameOver일 경우 MoveLeft를 멈춥니다.

 

 

게임 오버시에 장애물 생성도 멈춰봅시다. SpawnManager 스크립트도 다음과 같이 수정해봅시다. 위 스크립트를 참고해 아래 코드를 안보고 제작해보는 것을 추천드립니다.

 

 

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

public class SpawnManager : MonoBehaviour
{
    public GameObject obstaclePrefab;
    private Vector3 spawnPos = new Vector3(25, 0, 0);
    private float startDelay = 2;
    private float repeatRate = 2;
    private PlayerController playerControllerScript;
    // Start is called before the first frame update
    void Start()
    {
        InvokeRepeating("SpawnObstacle", startDelay, repeatRate);
        playerControllerScript = GameObject.Find("Player").GetComponent<PlayerController>();
    }

    void SpawnObstacle()
    {
        if (playerControllerScript.gameOver == false)
        {
            Instantiate(obstaclePrefab, spawnPos, obstaclePrefab.transform.rotation);
        }
    }

    // Update is called once per frame
    void Update()
    {

    }
}

 

 

 

 

마지막으로 장애물이 화면 밖으로 넘어갈 경우 제거를 하며 게시글을 마치겠습니다.

 

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

public class MoveLeft : MonoBehaviour
{
    private float speed = 30;
    private PlayerController playerControllerScript;
    private float leftBound = -15;
    // Start is called before the first frame update
    void Start()
    {
        playerControllerScript = GameObject.Find("Player").GetComponent<PlayerController>();
    }

    // Update is called once per frame
    void Update()
    {
        if (playerControllerScript.gameOver == false)
        {
            transform.Translate(Vector3.left * Time.deltaTime * speed);
        }

        if (transform.position.x < leftBound && gameObject.CompareTag("Obstacle"))
        {
            Destroy(gameObject);
        }
    }
}

 

 

 

이번에도 태그를 이용하였습니다. 좌측 임계점을 넘어간 MoveLeft 컴포넌트를 가진 게임오브젝트가 "Obstacle" 태그를 가지고 있을 경우 제거한다고 보시면 되겠습니다.