[C# / Unity 를 이용한 게임 만들기] 고양이의 구름등반 2탄!

Patrick!·2023년 6월 10일
0
post-thumbnail

1. 게임을 기획해보자!

지난 시간에 이어 게임을 완성시켜보자!
[C# / Unity 를 이용한 게임 만들기] 고양이의 구름등반 1탄! 에 이어서 작성된 자료!

책에서는 다음과 같이 게임의 규칙을 명명했다.

  1. 플레이어는 구름을 밟고 올라가면서 목표지점에 도달해야 한다.
  2. 플레이어의 움직임에 따라 애니메이션 효과가 작동해야 한다.
  3. 플레이어가 구름에 올라가면 거기에 맞춰 화면도 위로 올라간다.
  4. 플레이어가 정상에 도착하면 클리어 씬으로 전환되고 클리어 씬을 탭하면 다시 게임 씬으로 돌아가도록 구현하겠습니다.

지난 시간에는 물리동작(Physics -> Rigidbody, Collider), 애니메이션(Mecanim)에 대해 배웠다면!
이번엔 카메라 스크립트 전환, 씬 전환 등을 이번 시간에 알아보도록 할거다.


2. 기획한 것을 하나하나 만들어보자!

고양이에게 애니메이션을 적용한 것까지 진행했으니 고양이가 밟고 다닐 구름을 늘려보도록 하자!

1번 규칙에서 나온것처럼 고양이는 구름을 밟고 깃발이 있는 지점까지 도달해야 한다.

하지만 이전시간가지 만든 부분을 보면 고양이와 구름에 Physics(Rigidbody, collider)와 애니메이션만 추가했을 뿐 게임을 만든 것은 아니다.


A. 그렇기에 이제는 고양이가 구름을 밟고 올라갈 구름을 배치시켜보자.

구름을 배치하는 과정에는 [C# / Unity 를 이용한 게임 만들기] 고양이의 화살 피하기! 에서 다룬 'Prefab'을 이용하는 방법이 있다.

Prefab을 만드는 방법

  1. 제너레이터 스크립트를 사용해 프리팹에서 인스턴스를 만드는 방법
  2. 직접 만드는 방법 (수작업으로 배치하는 작업)

이번엔 직접 만드는 방법으로 진행해보려 합니다!
그 전에! 배치할 Object가 완성된 Object라면 더욱 좋다!

앞서 수작업으로 배치하는 작업이라고 설명했는데 정말 .. 수작업입니다...
1. Hierarchy창에서 Object를 Project창으로 드래그&드롭을 진행하면
2. 프리팹이 생성되는데
3. 이를 필요한 만큼 Scens뷰로 복사하는 형태로 만드는 방법 입니다.

완성된 Object가 좋은 이유?!

A0 Object -(copy)-> A1 Object가 실행되면서 A0에 적용된 component 속성값복사가 진행된다.
게임을 만드는데 있어 편리한 기능을 제대로 활용하게 되는 것이다!

왼쪽사진에 보이는 cloudPrefab들은 복사과정을 통해 같은 component를 가지고 있으며 Position / Scale 만 다를뿐 이다.
오른쪽 사진은 각각의 cloudPrefab들이 Scens 뷰에 위치한 게임화면을 보여주고 있다.

이를 실행시켜서 살펴보면 생동감있는 게임이 됬다는 것을 보여준다.

아직까지는 고양이의 움직임을 (카메라가) 따라가지 못하는 상황이다.


네 번째 문제를 해결해보자!

" 게임 속에서 카메라 = 플레이어가 보는 화면 "에 해당한다고 보면 된다.
플레이어가 게임을 플레이 하면서 보는 화면이 변화가 없다면 TV채널을 돌리는 것보다 재미없는 상황일 것이다..

그렇기에 생동감있는 게임의 조건은 실시간으로 게임에서 보여지는 변화에 맞는 화면을 출력할 필요가 있다!
(물론 게임의 장르나 세계관 및 상황에 따라 이는 달라질 수 있다.)

3. 플레이어가 구름에 올라가면 거기에 맞춰 화면도 위로 올라간다. 조건을 만족시키기 위해
여기서 "카메라"도 게임 오브젝트의 일종이므로 일반 오브젝트와 같이 컨트롤러 스크립트로 움직이게 해야한다.

카메라를 조작할 코드를 살펴보자!

public class CameraController : MonoBehaviour
{
    GameObject player;


    void Start()
    {
        this.player = GameObject.Find("cat");    
    }

    void Update()
    {
        Vector3 playerPos = this.player.transform.position;
        transform.position = new Vector3(
            transform.position.x, playerPos.y, transform.position.z);
    }
}

플레이어가 수직 이동할 때마다 카메라가 따라다니도록 프레임마다 플레이어 좌표를 찾아 카메라의 Y좌표에 반영하도록 했다.
플레이어 이동에 따라 수직방향의 변화만 필요하기에 X, Z좌표의 값을 카메라를 그대로 사용하도록 한다!


3. 구현하기전 적용될 원리를 알아보자!

이 게임의 목적은 고양이가 구름을 등반하여 꼭대기에 존재하는 깃발에 도착하는 것이다.
즉, 충돌판정에 대한 로직이 필요 -> Physics를 사용한 충돌 판정을 사용하면 이를 쉽게 진행할 수 있다.

Physics를 사용해 충돌 판정을 할 때는 Algorithm을 따로 구현할 필요가 없다고 한다! (얼마나 좋아~)
Collider 컴포넌트를 적용한 오브젝트들이 충돌했을 때 Physics가 자동으로 닿았는지 판정해 주기 때문이다.
충돌하면 충돌한 오브젝트에 적용된 스크립트의 OnCollisionEnter2D 메서드 등이 호출된다. (이를 이용)

Physics를 사용한 충돌판정 종류는 Collider 모드(충돌 모드) / Trigger 모드(통과모드)가 존재한다.
Collision 모드는 오브젝트가 닿았을 때 충돌 판정은 물론 충돌했을 때 주변에 미치는 영향까지 포함해 충돌 반응을 실행합니다. 한편 Trigger 모드는 충돌 판정만 하고 충돌 응답은 실행하지 않습니다.

상태Collsion 모드Trigger 모드
충돌한 순간OnCollsionEnter2DOnTriggerEnter2D
충돌 중OnCollsionStay2DOnTriggerStay2D
충돌이 끝난 순간OnCollsionExit2DOnTriggerExit2D

위의 순간에 따라서 호출되는 메서드들은 차이가 존재합니다. 충돌한 순간 과 충돌이 끝난 순간 의 경우 한 번만 호출된다고 보면 됩니다. 충돌 중 의 경우 지속적으로 호출이 된다는 차이점이 존재합니다.

깃발과 플레이어의 충돌판정을 쉽게 구현해보자!

- Physics의 충돌 판정 조건
판정한 모든 오브젝으에 Collider 컴포넌트가 적용되어 있어야 한다.
충돌을 판정할 오브젝트 중 적어도 한쪽에는 Figidbody 컴포넌트가 적용되어 있어야 한다.

플레이어는 Rigidbody와 Collider 가 적용되어 있으니 깃발에 Collider2D를 적용하고 Trigger 모드(통과모드)로 설정을 진행하도록 합니다.

이로써 플레이어와 깃발의 충돌 판정을 할 준비가 됬다!
이제 플레이어와 깃발이 닿았을 때 호출되는 메서드를 PlayerController 스크립트에 추가해보자!

public class PlayerController : MonoBehaviour
{
	... 
    
    // 골 도착
    private void OnTriggerEnter(Collider other)
    {
        Debug.Log("골");
    }
    // OnTriggerEnter2D 메스드의 매개변수에는 충돌 상대의 오브젝트에 적용한 Collider가 전달
    // 여기서 플레이어가 깃발에 닿은 사실은 알려주려고 Console 창에 출력합니다.
}

- OnTriggerEnter2D 메서드가 호출되지 않을 때 체크할 사항
충돌 판정할 오브젝트에 Collider 컴포넌트가 적용되어 있는가?
Collider 컴포넌트의 Is Trigger가 체크되어 있는가?
스크립트에 OnTriggerEnter2D 메서드가 구현되어 있는가?
스크립트가 적용되어 있는가?


플레이어가 깃발에 도착하고나서 게임이 끝난다면 너무 싱겁습니다... 조금 더 게임적인 면모로 탈바꿈하기 위해 씬 전환을 만들어보도록 하겠습니다!

다섯 번째 문제를 해결해보자!

Unity에서는 게임 화면을 묶어 씬 형태로 관리하게 됩니다.
게임 실행 -> 타이틀 화면 -> 메뉴화면 -> 게임화면 -> 게임결과화면 등으로 이루어지는 것이 큰 틀이라고 할 때,

이번에는 게임결과화면을 만들어 보도록 하겠습니다!

Unity에서는 각 씬(게임화면)을 전환시키려면 전환할 시점에 다른 씬의 파일명을 지정하기만 하면 됩니다.

File -> New Scene -> Basic 2D 선택 -> Create 를 통해 새로운 씬 화면을 생성합니다.

이후 씬을 생성하면 Save as 를 통해 씬(Scene Name : ClearScene)을 저장합니다.

background_clear 를 화면에 Position(0, 0, 0)으로 배치합니다.

다음으로 ClearDirector Script를 작성합니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement; // LoadScene을 사용하는데 필요합니다

public class ClearDirector : MonoBehaviour
{
    void Update()
    {
        // 마우스가 클릭된 것을 감지했으면 SceneManager 클래스의
        // LoadScene 메서드를 사용해 게임 씬으로 전환합니다
        // LoadScene은 매개변수로 받은 씬 이름의 씬을 로드하는 메서드
        if (Input.GetMouseButtonDown(0))
            // 여기서 게임 씬으로 전환해야 하므로 매개변수의 씬 이름을 GameScene으로 입력
            SceneManager.LoadScene("GameScene");
    }
}

이제 클리어 씬에서 게임 씬으로 전환해봅시다!

빈 오브젝트(ClearDirector)를 생성하고 Script(ClearDirector)를 적용시킵니다.

이제 게임을 실행해보면!? 클릭시 씬을 출력해주겠지! 했는데!

위의 오류가 발행하는 것을 확인할 수 있다 ... (역시 쉽게 지나가는 일은 없다!)

여섯 번째 문제를 해결해보자!

이를 해결하기 위해서는 어떻게 해야할까?
위의 오류는 씬을 등록하지 않았기 때문에 발생하는 것이다.
씬 전환을 사용하려면 어느 씬을 어떤 순서로 사용하는지 유니티에 등록을 해야한다!

File -> Build Settings 에서 ClearScene과 GameScene을 Scene In Build 에 추가합니다.

[Add Open Scenes]를 통해 자동적으로 추가가 가능하다. 추가되지 않은 것은 직접 드래그&드롭 한다.

이후 추가한 씬들을 보면 우측에 숫자가 출력 되는데 이는 씬의 출력 순서를 의미합니다
GameSene이 0, ClearScene이 1이 되도록 순서를 바꿉니다. 그리고 Scenes/SampleScene은 사용하지 않으므로 체크를 해제합니다.

이제 다시 게임을 실행시켜봅시다!

클릭 후 정상적으로 게임화면으로 이동하는 것을 확인할 수 있습니다!

이제 반대로 깃발에 고양이가 도착하면 게임씬이 바뀌도록 PlayerController Script를 수정해보겠습니다.

using UnityEngine.SceneManagement;

...

	void OnTriggerEnter2D(Collider2D other) {
    	Debug.Log("골");
        SceneManager.LoadScene("ClearScene");
    }
}

스크립트까지 수정했으니 진짜 게임을 시작해보자!

게임의 시작과 끝을 통해 완성도를 더욱 높일 수 있었던 시간이었다!

다음시간에는 고양이의 구름등판 게임의 '버그' 를 수정하는 시간을 가져보도록 하겠다!


출처 : 그림으로 이해하고 만들면서 익히는 유니티 교과서[개정5판] - 기타무라 마나미

profile
C++와 Unreal Engine / C#과 Unity / Katalon Studio를 통한 자동화 테스트 등을 하루하루 공부한 기록

0개의 댓글