본문 바로가기

Unity

[Unity] 🌟2D 게임 핵심 메서드 및 응용🌟

728x90
반응형

캐릭터 생성 및 편집

캐릭터 스프라이트 설정

준비된 소스 파일에는 각각의 스프라이트가 존재한다. 스프라이트 시트는 여러 이미지를 하나의 이미지 파일로 합친 것이다. 캐릭터가 연속적으로 움직이는 모습을 여러 이미지 파일로 만드는 것보다 한 이미지 파일로 합쳐서 관리하는 것이 관리도 편하고 성능이 좋다.

 

싱글 스프라이트 하나의 스프라이트를 표현
멀티플 스프라이트  하나의 스프라이트 에셋을 여러 개의 개별 스프라이트로 잘라 사용

[ 캐릭터 스프라이트 편집 / 자르기 ]

① 스프라이트 선택

② 인스펙터 > Sprite Mode > Multiple/Single

③ Sprite Editor
▻Type: Grid bu Cell Size
▻Pixel Size: (64,64)

④ Slice 후 저장 및 나가기

캐릭터 리지드바디와 콜라이더 설정 

캐릭터 게임 오브젝트가 중력에 의해 떨어지려면 리지드 바디 2D 컴포넌트가 필요하고 게임의 발판에 서 있으려면 콜라이더 2D가 필요하다. 이때 콜라이더 2D는 원형을 사용한다. 상황에 따라 변경해도 된다.

 

리지드 바디 2D 컴포넌트 추가

Collision Detection: Discrete → Continuous 변경

Constraints > Freeze Rotation [z] 체크: 고정

 

서클 콜라이더 컴포넌트 추가

- Player 게임 오브젝트가 각진 모서리에착지를 용이하게 만듦

 

콜라이더 2D는 각진 모서리의 착지를 용이하게 위해 사용하는데 Player 게임 오브젝트의 하체 일부만 차지하도록 오프셋과 반지름을 조정해 배치한다. 

추가적으로 Z축의 회전을 잠가 불필요한 회전이 발생하는 상황을 막아야 한다.

[ 이산과 연속 ]

위의 사진에서 확인할 수 있듯, 리지드 바디 2D의 충돌 감지 방식을 이산(Discrete)에서 연속(Continuous)으로 변경했다.

 

이산은 충돌 감지를 일정 시간 간격으로 끊어서 실행하는 반면 연속움직이기 이전 위치와 움직인 다음 위치 사이에서 예상되는 충돌까지 감지하므로 연속이 이산보다 충돌 감지가 상대적으로 정확하다.

캐릭터 오디오 설정

오디오 소스 컴포넌트게임 오브젝트에 소리를 낼 수 있는 능력을 부여한다.

아래와 같이 Player 게임 오브젝트가 점프 소리를 내도록 오디오 소스 컴포넌트를 추가한다. 이때 오디오 소스 컴포넌트는 소리를 재생하는 부품이지 소리를 담은 파일 아니라는 점에 주의한다.

 

  1. Player 게임 오브젝트 > Audio > Audio Source 추가

  2. Audio Source 컴포넌트에서 AudioClip 필드 옆의 선택 버튼 > 선택 창에서 원하는 오디오 클립 클릭

  3. Audio Source 컴포넌트의 Play on Awake 체크 해제

 

Play on Awake는 오디오 소스 컴포넌트가 활성화되었을 때 최초 1회 오디오를 자동 재생하는 옵션이다. 해당 설정이 활성화돼 있을 시 시작과 동시에 점프 소리가 1회 무조건 재생되게 된다. 따라서 필요하지 않은 경우는 설정 해제한다.

캐릭터 애니메이션 설정

프로젝트 창의 Asset 폴더 하위에 새 폴더를 생성한다. 생성된 폴더 이름을 Animation으로 설정한다.

▷ 상단 메뉴 > Window > Animation > Animation

▷ 열린 애니메이션 크기를 조절한다.

⭐️ 단축키로는 [cmd + 6]을 이용한다. ⭐️

 

열린 애니메이션 창을 확인하면 '애니메이션 클립 만들기'라는 영어 메시지를 확인할 수 있다.

이때 Create 버튼을 눌러 Player 게임 오브젝트에 관한 새로운 애니메이션 클립과 컨트롤러를 생성할 수 있다.

[선택한 애니메이션 클립 생성]

① 애니메이션 창 > Create 클릭

② 새로운 애니메이션 클립을 원하는 이름으로 Asset 폴더 내부의 Animation 폴더에 저장

 

이때 애니메이션을 생성할 오브젝트를 클릭 후에 애니메이션 클립을 생성함에 주의한다. 또한 저장하는 폴더의 위치를 초기화하고 원하는 폴더로 저장한다.

 

🌟🌟🌟
특정 오브젝트를 클릭 후 애니메이션 Create 버튼 클릭 /
저장하는 폴더의 위치를 초기화하기

[선택한 애니메이션 클립 구성]

① 프로젝트 창에서 Sprites 폴더로 이동

② 캐릭터 스프라이트 펼치기 > 모든 스프라이트 선택 후 Animation 창으로 이동

③ 애니메이션 창의 sample을 6 ~ 16으로 변경

[애니메이션의 루프 해제]

새 애니메이션은 기본적으로 애니메이션을 반복 재생하는 루프 재생이 활성화되어 있다.

하지만 특정 애니메이션 클립은 반복 재생이 되면 안 되는 경우가 있기에 필요시에는 애니메이션의 루프를 비활성화한다.

 

1️⃣ 프로젝트 > Animation 창 > 루프 비활성화가 필요한 애니메이션 클립 선택
2️⃣ 인스펙터 창 > Loop Time 해제

유한 상태 머신

애니메이션 클립을 어떤 상황에서 어떻게 재생하려면 애니메이션 컨트롤러가 필요하다.

애니메이션 컨트롤러는 상황에 어떤 애니메이션 클립을 재생해야 하는지 저장한 지도이며, 유한 상태 머신 모델을 사용한다.

[ 유한 상태 머신]

유한 상태 머신이란 유한한 수의 상태가 존재하며, 한 번에 한 상태만 '현재 상태'가 되도록 프로그램을 설계하는 모델이다.

유한 상태 머신에서는 어떤 상태에서 다른 모델로 전이하여 현재 상태를 전환할 수 있다.

 

유한 상태 머신으로 게임 속 적 AI로 구현한다고 가정할 때, 유한 상태 머신으로 구현한 적 AI는 다음과 같은 3가지 상태를 가진다.

 

탐색 목표를 찾아낸다.
추적 목표를 쫒는다.
공격 목표를 공격한다.

애니메이터 컨트롤러와 애니메이터

애니메이터 컨트롤러는 유한 상태 머신을 사용해 재생할 애니메이션을 결정하는 상태도를 표현하는 에셋이다.

애니메이터는 애니메이터 컨트롤러를 참고하여 게임 오브젝트에 애니메이션을 적용하는 컴포넌트다.

 

· 새로운 애니메이션 컨트롤러는 <프로젝트 창>에서 Create > Animator Controller로 생성한다.

· 생성한 애니메이션 컨트롤러를 Anmation 폴더에 이동한다.

· 애니메이션 컨트롤러는 Window > Animation > Animator로 열 수 있다.

 

💫💫💫 중요 💫💫💫

Animator 창은 마우스 휠로 확대 및 축소가 가능하며 맥 기준 [option] 키를 누른 채로 클릭을 하면 화면을 이동하면서 볼 수 있다!

애니메이션의 전이

[ 상태와 전이 생성 / 삭제 ]

기본 상태의 종류와 설명은 오른쪽 링크를 참고한다. [링크]

 특정 상태를 기본 상태로 변경하기 위해선 우클릭 > Set as Layer Default로 설정한다.

 

▶️ 전이를 구성하려면 우클릭 > Make Transition을 통해서 상태를 연결하며 쌍방향 연결이 가능하다.

▶️ 전이를 삭제하려면 클릭 후에 [cmd] + [Delete]를 이용해 삭제한다.

[ 피라미터 추가 : 전이의 조건 ]

전이의 조건은 애니메이터 컨트롤러의 파라미터를 사용해 구성한다. 파라미터의 종류는 int, float, bool, Trigger가 있다.

파라미터의 생성은 아래와 같다. (예시)

① 애니메이터 창 > Parameters 클릭

② + 버튼 클릭 > Bool > 생성된 파라미터의 이름을 Grounded로 변경

 + 버튼 클릭 > Trigger > 생성된 파라미터의 이름을 Die 변경

 

bool 타입의 파라미터는 참과 거짓을 확인하는 true와 false 값을 가지지만 트리거 파라미터는 다른 타입과 달리 특정 값을 할당할 없다.

트리거 타입 파라미터는 트리거를 '셋' 또는 '발동'하여 '방아쇠를 당기는' 방식으로 사용한다.

 

지속적으로 어떠한 수치를 확인하는 것이 아니라 어떤 사건이 발생했을 때 전이가 일어나도록 조건을 구성 시에는 트리거 파라미터를 사용하는 것이 편리하다. 트리거 타입셋 하는 순간 즉시 true가 되고 곧바로 false가 되도록 구현되어 있다.

[ 전이 설정 ]

① 애니메이터 창에서 전이를 원하는 화살표를 클릭

② 인스펙터 창에서 Has Exit Time 체크 해제

 Setting > Trasition Duration을 0으로 변경

 조건 추가

⑤ 조건값을 false로 변경(default)

 

Has Exit Time

Has Exit Time은 종료 시점을 활성화하는 옵션이다. 일반적으로 해제한다.

 

▷ Has Exit Time이 활성화: 전이의 조건을 만족해도 즉시 다음 상태로 전이하지 않음.

▷ Has Exit Time가 비활성화: 전이 조건을 만족하는 즉시 전이가 실행.

 

Trasition Duration

전환 지속 시간은 전이가 이루어지는 동안 현재 애니메이션 클립과 다음 애니메이션 클립을 섞어(블렌딩) 부드럽게 해주는 역할을 수행한다.

2D 스프라이트에서의 전환 지속 시간을 0으로 설정해도 무방하며, 디폴트 값으로 사용한다.

2D 게임에서 C# 스크립트 작성

[ 플레이어 캐릭터 제어: PlayerController ]

23.11.16 수정 및 추가

 

2D 게임을 돌아가게 하기 위해서는 다음과 같은 변수/함수가 필요하다.

 

·  게임 바닥에 닿았는지를 확인하는 변수

·  플레이 캐릭터의 사망 상태를 확인하는 변수

· 마우스와 같은 입력을 확인할 함수

· 오브젝트 간의 확인 및 처리를 담당하는 함수

 

위와 같은 조건을 다룰 함수는 아래 링크와 첨부자료를 참고하자.

 

[2D Game] #4. 스크립트 생성

PlayerController 스크립트 생성 PlayerController 스크립트를 생성하여 사용자 입력을 감지하여 점프하고, 충돌을 감지하여 장애물에 닿았을 때 사망 처리를 실행하여 보자. 또한 해당 스크립트를 이용

udangtangtang-cording-oldcast1e.tistory.com

배경 설정

스프라이트 랜더러 컴포넌트가 그리는 그래픽의 앞뒤 정렬은 트랜스폼 컴포넌트의 위치값과 상관없다. 

2D 게임 오브젝트가 그려지는 순서 스프라이트 랜더러의 정렬 레이어가 결정한다.

 

따라서 2D 게임 오브젝트의 스프라이트를 정렬하기 위해선 정렬 레이어를 추가하여 사용한다.

 

   1. Sprites Randerer 컴포넌트의 Sorting Layer의 Default 클릭 > Add.. 클릭

   2. Tag & Layer 창에서 sorting Layers 리스트의 +클릭

   3. 생성된 Layer 이름을 BackGround로 변경

   4. + 클릭 > 생성된 Layer이름을 Middleground로 변경

   5. + 클릭 > 생성된 Layer이름을 Foreground로 변경

 

이때 유니티는 가장 아래쪽 정렬 레이어가 가장 앞쪽에 그려진다는 점에 유의한다!

 

Background 가장 뒤
Middleground 중간
Foreground 가장 앞

 

게임을 플레이하는 경우, 플레이어 오브젝트와 배경의 관계는 둘 중 하나이다.

 

(1) 플레이어는 '게임 상' 좌우로 이동하지 않고 배경이 움직이는 경우

(2) 배경은 움직이지 않고 플레이어가 이동하여 플레이하는 경우

 

(1)의 경우에는 배경과 플레이어와 상호작용하는 오브젝트만 움직이면 되므로 코드의 복잡도와 상호작용 오브젝트를 많이 만들 필요가 없다. 반면 (2)의 경우에는 플레이어가 직접 움직이며 작용하므로 더 많은 오브젝트와 변수를 할당해야 한다.

 

(1)의 경우와 같이 배경이 움직이게 하기 위해서는 배경을 상하좌우 움직이도록 하는 스크립트배경이 연속적으로 이동하게 하기 위한 스크립트 두 개가 필요하다. 이때 배경이 다른 오브젝트와 상호작용하지 않도록 콜라이더를 Trigger로 변경한다!

두 스크립트는 아래 첨부 파일을 확인하자.

 

BackgroundLoop.cs
0.00MB
ScrollingObject.cs
0.00MB

캔버스와 게임 UI

캔버스와 스케일

UI를 구성하기 위해서는 먼저 캔버스 게임 오브젝트를 만들어야 한다.

캔버스UI를 잡아주는 틀이기 때문에 캔버스의 크기나 가로세로 비율이 달라지면 캔버스에 배치된 UI의 모습도 다르게 보인다. 

 

캔버스의 크기는 게임을 실행 중인 화면의 해상도로 결정된다.

이때 캔버스 컴포넌트의 UI 스케일 모드의 기본 설정인 고정 픽셀 크기는 캔버스 크기가 변해도 배치된 UI 요소의 크기를 변경하지 않으므로 화면 크기가 달라지면 UI 요소의 크기나 UI 요소의 간격이 의도와 다르게 크거나 작아지는 경우가 생긴다.

[ 화면 크기에 따른 스케일 변경 ]

앞서 다룬 고정 픽셀 크기에 따라 의도치 않은 UI의 간격이 차이 나지 않도록 다양한 크기와 비율의 화면에도 UI의 크기와 배치를 위해 '화면 크기에 따라 스케일' 모드를 UI 스케일 모드로 사용해야 한다. 이때 다른 크기의 화면에 캔버스가 그려질 때는 캔버스 자체를 확대/축소한다.

 

🌟 🌟 🌟

Scale With Scene Size :실행 화면의 기준 화면에 따른 변경

[ 방향 매치 ]

 '화면 크기에 따라 스케일' 모드는 실제 화면과 기준 해상도 사이의 화면 비율이 다른 경우 캔버스 스케일러 컴포넌트의 일치 필드 값이 높은 방향의 길이를 유지하고 다른 방향의 길이를 조절한다.

이때 일치 값을 결정하는 데는 기준이 없다. 이 경우는 UI 요소가 많이 나열된 방향의 일치 값높여주는 것이 좋다.

캔버스 스케일러 설정

 '화면 크기에 따라 스케일' 모드를 사용해 640x360을 기준 해상도로 사용하여 UI를 배치한다. 

 

  ① Canvas 컴포넌트 생성 (하이어 라키 > Create > UI > Canvas)

  ② Canvas Scaler 컴포넌트의 UI Scale Mode를 Scale With Screen Size로 변경

  ③ Reference Resolution을 (640,360)으로 변경

[ 텍스트 UI ]

텍스트의 생성은 아래와 같다.

 

· Create > UI > Text

· Text 게임 오브젝트의 이름을 <원하는 이름>으로 변경

· 그림자 효과 : Text 게임 오브젝트에 Shadow 컴포넌트 추가(UI > Effect > Shadow)

게임 매니저

플레이어의 상태에 따라 게임의 전반적인 상태를 관리하는 게임 매니저를 만들어보자. 게임 매니저의 역할은 다음과 같다.

 

 ·  점수 저장

 ·  게임오버 상태 표현

 ·  플레이어의 사망을 감지해 게임 오버 처리 실행

 ·  점수에 따라 점수 UI 텍스트 갱신

 ·  게임 오버되었을 시 게임 오버 UI 활성화

 

게임 매니저는 다음 두 조건을 만족해야 한다.

 

① 게임 매니저는 단 하나만 존재

② 어떤 곳에서 손쉽게 게임 매니저에 접근이 가능

[ 싱글턴 패턴 ]

이런 조건에서는 주로 싱글턴이라는 디자인 패턴을 사용한다.

싱글턴 패턴은 '어떤 오브젝트가 프로그램에 단 하나만 존재해야 하며, 어느 곳에서도 쉽게 접근 가능해야 할 때' 사용된다. 싱글턴 패턴을 사용하면 게임 매니저가 씬에 단 하나만 있게 하고, 어느 곳에도 게임 매니저에 즉시 접근하게 만든다.

 

클래스에 의해 생성된 각각의 오브젝트각 개체로서 존재하며 각각의 오브젝트마다 해당 개체의 변수가 존재하는 것이 아닌 하나의 변수를 공유해야 한다.

[ 정적 변수 ]

어떤 변수를 정적 타입으로 선언하면 해당 타입의 오브젝트를 몇 개를 생성하든 그 수에 상관없이 메모리에 하나만 존재한다.

이때 Static 변수는 해당 클래스와 관련 있지만 개별 오브젝트마다 하나씩 가지고 있는 것보다는 모든 오브젝트가 공유하는 것이 더 나은 값을 표현할 때 사용한다. 그러한 값의 예로는 오브젝트의 개수가 있다.

 

Static 변수의 특징은 다음과 같다.

  • 메모리에 단 하나만 존재하고 모든 오브젝트가 공유한다.
  • 클래스 이름과 점(.) 연산자를 이용해 접근이 가능하다.

GamaManager 스크립트 생성

기본적인 게임 매니저 스크립트는 아래 [더 보기] 란의 코드를 참고한다.


더보기
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

// 게임 오버 상태를 표현하고, 게임 점수와 UI를 관리하는 게임 매니저
// 씬에는 단 하나의 게임 매니저만 존재할 수 있다.
public class GameManager : MonoBehaviour {
    public static GameManager instance; // 싱글톤을 할당할 전역 변수

    public bool isGameover = false; // 게임 오버 상태
    public Text scoreText; // 점수를 출력할 UI 텍스트
    public GameObject gameoverUI; // 게임 오버시 활성화 할 UI 게임 오브젝트

    private int score = 0; // 게임 점수

    // 게임 시작과 동시에 싱글톤을 구성
    void Awake() {
        // 싱글톤 변수 instance가 비어있는가?
        if (instance == null){
            // instance가 비어있다면(null) 그곳에 자기 자신을 할당
            instance = this;
        }
        else{
            // instance에 이미 다른 GameManager 오브젝트가 할당되어 있는 경우
            // 씬에 두개 이상의 GameManager 오브젝트가 존재한다는 의미.
            // 싱글톤 오브젝트는 하나만 존재해야 하므로 자신의 게임 오브젝트를 파괴
            Debug.LogWarning("씬에 두개 이상의 게임 매니저가 존재합니다!");
            Destroy(gameObject);
        }
    }
    void Update() {
        // 게임 오버 상태에서 게임을 재시작할 수 있게 하는 처리
        if(isGameover && Input.GetMouseButtonDown(0)){
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }
    // 점수를 증가시키는 메서드
    public void AddScore(int newScore) {
        if(isGameover){
            score += newScore;
            score.text = "Score" + score;
        }
    }
    // 플레이어 캐릭터가 사망시 게임 오버를 실행하는 메서드
    public void OnPlayerDead() {
        isGameover = true;
        gameoverUI.SetActive(true);
    }
}

GamaManager 싱글턴 구현

static으로 선언된 변수는 모든 오브젝트가 공유하는 하나의 변수가 된다. 

이때 instance는 메모리에 단 하나만 존재하므로 instance에 할당될 수 있는 GamaManager 오브젝트도 단 하나이다.

 

즉, 싱글턴이 될 GamaManager 오브젝트는 스스로를 instance에 할당한다.

아래 블럭 안의 코드에서 GamaManager에서 싱글턴을 구현한 부분을 보자.

 

Awake() 메서드의 if 문 블록에는 instance가 비어있다면 그곳에 자기 자신을 할당한다.

23.11.18 수정 및 추가

 

if (instance == null) instance = this;

이렇게 instance에 할당된 GamaManager 오브젝트는 GamaManager.instance로 즉시 접근할 수 있다.

 

단, GamaManager 타입의 오브젝트는 씬에 단 하나만 존재해야 하며 두 개 이상 존재할 경우 하나만 남기고 파괴해야 한다!

 따라서 자신이 아닌 다른 GamaManager 오브젝트가 instance에 이미 할당된 경우 else문을 통해 제어한다.

 

else{
    Debug.LogWarning("씬에 두개 이상의 게임 매니저가 존재합니다!");
    Destroy(gameObject);
}

GamaManager의 필드

GamaManager의 다른 변수를 살펴보고 나머지 메서드를 작성해 보자.

싱글턴을 위한 변수 instance 이외의 변수는 아래 코드와 같다.

public bool isGameover = false; // 게임 오버 상태
public Text scoreText; // 점수를 출력할 UI 텍스트
public GameObject gameoverUI; // 게임 오버시 활성화 할 UI 게임 오브젝트

private int score = 0; // 게임 점수

[ GamaManager의 Update() 메서드 ]

게임 재시작은 현재 활성화된 다시 로드하는 방식으로 구현한다.

따라서 씬 관리자 SceneManager가 필요하므로 스크립트 상단에 다음과 같은 선언이 필요하다.

 

using UnityEngine.SceneManagement;

게임이 시작되면 반복적으로 if 문 검사를 통해 isGameover가 true인지 검사함과 동시에 좌클릭을 눌렀는지 확인한다. 게임 오버 상태에서 좌클릭을 누르면 현재 활성화된 신을 재 로딩하여 재시작한다.

 

이때 게임 오버 상태에서 마우스 왼쪽 버튼을 누르면 if문 블록 코드가 실행되고 현재 활성화된 씬을 다시 로드하여 게임을 재시작한다.

 

SceneManager.LoadScene(SceneManager.GetActiveScene().name);

SceneManager.GetActiveScene() 메서드는 현재 활성화된 씬의 정보를 Scene 타입으로 오브젝트로 가져오는 메서드이다. 그리고 Scene 타입의 오브젝트는 씬의  이름을 변수 name으로 제공한다.

 

그렇게 가져온 현재 씬의 이름을 SceneManager.LoadScene() 메서드에 입력하여 현재 씬을 다시 로드한다.

 

게임 오버가 아닌 경우 점수를 추가하며 스코어를 업데이트할 때 score += newScore; 을 이용하여 newScore만큼 증가한다. 이후 스코어 텍스트 오브젝트의 텍스트를 업데이트한다.

 [ GamaManager의  메서드 ]

AddScore() OnPlayerDead()
public void AddScore(int newScore) {
    if(isGameover){
        score += newScore;
        scoreText.text = "Score" + score;
    }
}
public void OnPlayerDead() {
    isGameover = true;
    gameoverUI.SetActive(true);
}

 

▶️ AddScore()

게임 오버가 아닌 경우 점수를 추가하며 스코어를 업데이트할 때 score += newScore; 을 이용하여 newScore만큼 증가한다.

이후 스코어 텍스트 오브젝트의 텍스트를 업데이트한다.

 

▶️ OnPlayerDead()

OnPlayerDead() 메서드가 실행될 때,

isGameover는 true가 되며 gameoverUI에 할당된 Gameover Text 게임 오브젝트가 실행되게 된다.

PlayerController 스크립트 수정

GamaManager의 게임오버 기능인 OnPlayerDead()를 알맞은 시점에 실행하려면 PlayerController 스크립트의 수정이 필요하다.

 

OnPlayerDead() 메서드는 플레이어가 사망할 때 실행되므로 PlayerController 스크립트의 Die() 메서드에서 실행되어야 한다. 따라서 PlayerController의 스크립트를 다음 아래 [더 보기] 란의 코드와 같이 수정한다.

더보기
private void Die() {
    // 애니메이터의 Die 트리거 파라미터를 셋
    animator.SetTrigger("Die");

    // 오디오 소스에 할당된 오디오 클립을 deathClip으로 변경
    playerAudio.clip = deathClip;
    // 사망 효과음 재생
    playerAudio.Play();

    // 속도를 제로(0, 0)로 변경
    playerRigidbody.velocity = Vector2.zero;
    // 사망 상태를 true로 변경
    isDead = true;

    GameManager.instance.OnPlayerDead();
}

ScrollingObject 스크립트 수정

게임 오버 상태에서는 움직이던 발판과 배경이 멈춰야 하므로 GamaManager의 변수 isGameover를 검사하여 움직임 여부를 결정한다.

private void Update() {
    // 게임 오브젝트를 왼쪽으로 일정 속도로 평행 이동하는 처리
    if(!GameManager.instance.isGameover)
        transform.Translate(Vector3.left*speed *Time.deltaTime);
}

2D 게임 발판 만들기

23.11.18 추가

 

먼저 Platform 게임 오브젝트의 자식으로 있는 장애물 게임 오브젝트를 배열 타입으로 선언하고 플레이어 캐릭터가 발판인 자신을 밟았는지를 알려주는 변수를 선언한다.

 

 · public GameObject[] obstacles; // 장애물 오브젝트들

 · private bool stepped = false; // 플레이어 캐릭터가 밟았었는가

[ OnEnable() 메서드 ]

OnEnable() 메서드는 활성화 때마다 호출되는 함수이다.

하지만 처음 한 번만 실행되는 Start() 메서드와는 달리 OnEnable() 메서드는 활성화 될때마다 매번 다시 실행된다.

따라서 OnEnable() 메서드는 컴포넌트를 끄고 다시 키는 방식으로 재설정할 수 있다.

 

⭐️ ⭐️ ⭐️

OnEnable() 메서드는 사용자 함수가 아닌 유니티의 기본 이벤트 메서드임을 기억한다.

 

게임 오브젝트의 활성 상태는 해당 게임 오브젝트의 컴포넌트에도 영향을 미치므로 개별 컴포넌트의 활성 상태를 제어하지 않고 게임 오브젝트를 끄고 키는 방식으로 OnEnable() 메서드를 재실행하는 것도 가능하다.

 

OnEnable() 메서드의 로직은 아래와 같다.

 

  1. 반복문을 사용해 순번 i를 0부터 장애물의 수 인 obstacles.Length만큼 반복한다.

  2. obstacles 배열에 있는 장애물 오브젝트에 대해 접근하고 1/3 확률로 활성화한다.

[ OnCollisionEnter2D() 메서드 ]

OnCollisionEnter2D() 메서드의 로직은 아래와 같다. (예시)

 

  1. 충돌한 게임 오브젝트의 태그가 Player이고 stepped가 false 인 경우를 (!false == true) 검사한다.

  2. 조건이 참이라면 stepped을 true로 갱신한다.

  3. 게임 메니저를 싱글턴으로 접근하여 AddScore() 메서드를 실행해 1점을 추가한다.

 

활용 코드는 아래의 [더보기]를 참고한다.

더보기
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

// 게임 오버 상태를 표현하고, 게임 점수와 UI를 관리하는 게임 매니저
// 씬에는 단 하나의 게임 매니저만 존재할 수 있다.
public class GameManager : MonoBehaviour {
    public static GameManager instance; // 싱글톤을 할당할 전역 변수

    public bool isGameover = false; // 게임 오버 상태
    public Text scoreText; // 점수를 출력할 UI 텍스트
    public GameObject gameoverUI; // 게임 오버시 활성화 할 UI 게임 오브젝트
    private AudioSource BackGroundMusic; // 사용할 오디오 소스 컴포넌트

    private int score = 0; // 게임 점수

    void Start(){
        BackGroundMusic = GetComponent<AudioSource>();
        BackGroundMusic.Play();
    }

    // 게임 시작과 동시에 싱글톤을 구성
    void Awake() {
        // 싱글톤 변수 instance가 비어있는가?
        if (instance == null)
        {
            // instance가 비어있다면(null) 그곳에 자기 자신을 할당
            instance = this;
        }
        else
        {
            // instance에 이미 다른 GameManager 오브젝트가 할당되어 있는 경우

            // 씬에 두개 이상의 GameManager 오브젝트가 존재한다는 의미.
            // 싱글톤 오브젝트는 하나만 존재해야 하므로 자신의 게임 오브젝트를 파괴
            Debug.LogWarning("씬에 두개 이상의 게임 매니저가 존재합니다!");
            Destroy(gameObject);
        }
    }

    void Update() {
        // 게임 오버 상태에서 게임을 재시작할 수 있게 하는 처리
        if(isGameover && Input.GetMouseButtonDown(0)){
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }

    // 점수를 증가시키는 메서드
    public void AddScore(int newScore) {
        if(isGameover){
            score += newScore;
            scoreText.text = "Score" + score;
        }
        
    }

    // 플레이어 캐릭터가 사망시 게임 오버를 실행하는 메서드
    public void OnPlayerDead() {
        isGameover = true;
        gameoverUI.SetActive(true);
        BackGroundMusic.Stop();
    }
}

 [ 오브젝트 할당 ]

실행화면
코드가 완성 되었다면 발판을 제어하는 메서드인 Platform을 부모 컴포넌트에 추가하고, obstacles에 자식 오브젝트를 할당한다.
23.11.28 추가

오브젝트 풀링

오브젝트 풀링이란 초기에 필요한 만큼 오브젝트를 미리 만들어 풀(pool)에 쌓아두는 방식이다.

 

풀에 오브젝트를 생성해둔 이후에 새로운 오브젝트가 필요할 경우 새로운 오브젝트를 파괴하지 않고 풀에 있는 오브젝트를 가져다 쓰는 방법이다. 오브젝트의 사용이 끝난 경우 파괴하는 대신 풀에 반환한다.

 

Instantiate나 Destroy 메서드는 생성/파괴에서 성능을 많이 요구하므로 이를 과하게 사용하는 경우 끊김 현상이 일어날 수 있다. 따라서 각 상황에 따라 생성 및 파괴를 하는 것보다 사용해야할 때 꺼내고 사용하지 않을 때 반납하는 방식을 사용하면 메모리를 효율적으로 관리할 수 있다.


오브젝트 풀링은 필요한 오브젝트를 게임 초반에 미리 생성하므로 로딩시간이 길어질 수 있다.

로딩이 긴 게임들은 이러한 이유로 로딩이 길고 게임이 끊기지 않는다.

2D 게임 실행

BackgroundLoop.cs
0.00MB
GameManager.cs
0.00MB
Platform.cs
0.00MB
PlatformSpawner.cs
0.00MB
PlayerController.cs
0.00MB
ScrollingObject.cs
0.00MB

728x90
반응형
댓글