프로젝트/[Sparta] 유니티로 만드는 게임개발 종합반

[1주차 게임] 빗물받는 르탄이 -2

순정법사 2022.12.11

C. 빗방울 생성하기

1. 빗방울 특징 파악하기

a. 빗방울의 특징

* 빗방울은 하늘에서 랜덤한 위치에서 내린다

* 큰 / 중간 / 작은 빗방울이 존재한다 (3, 2, 1점)

* 캐릭터와 부딪히면 점수를 더한다

* 바닥에 부딪히면 없어진다

 

2. 빗방울 생성 및 설정하기

a. 빗방울 생성하기

1) MainScene → GameObject → 2D Object → Sprite → Circle 클릭

2) rain으로 rename

 

빗방울 생성 경로

 

b. 빗방울 설정하기

생성된 물방울(일것)
하늘로 올리고 (Position 4), 레이어 앞으로 올리기
150,150,255,255 색상 변경

 

3. 빗방울 움직이기

a. 빗방울 떨어지게 하기

rigidbody 2D를 사용해서 (중력 이용) 떨어지게 보이게 하기

Inspector -> Add Component -> Physics 2D -> Rigidbody 2D 추가

 

Inspector의 Component 추가
Physics 2D 추가
Rigidbody 2D 추가

 

4. 빗방울 충돌 제거

a. 충돌의 기본 조건

1) 둘 다 Collider 가 있어야 한다

2) 둘 중 하나는 Rigidbody가 있어야 한다

 

b. 충돌 세팅하기

두 개중 아래 ridigbody는 물방울에 설정을 했으니, 충돌할 물체 두가지 인 물방울과 땅을 Collider로 설정한다

설정하는 방법은 rigidbody와 같음, 그저 Physics 2D에서 Circle Colider이냐, Box Colider이냐를 고를 뿐!

 

<rain 설정 : Circle Colider>

원형으로 선택
Inspector를 확인해보면 잘 적용되어있다

 

<ground 설정 : Box Colider>

ground는 박스니까
Inspector를 확인해보면 마찬가지로 적용되어있다
잘 적용이 되면 이렇게 초록색 테두리 선이 생성된다

 

충돌 세팅이 정상적으로 완료되면 이런 형식이 된다

돌이 떨어지는줄

 

c. 충돌 감지하기

1) "땅" 인지 알 수 있게, ground 라고 tag를 주기

ground 오브젝트에서 Add Tag를 누른다
ground의 태그를 생성한다.
생성된 ground 태그를 ground에 태깅해준다

 

2) 땅에 닿았는지 확인하기

 

OnCollisionEnter2D 함수 : 다른 콜라이더에 부딪혔을 때 실행되는 내장함수

 

void OnCollisionEnter2D(Collision2D coll){
    //나와 부딪힌 태그의 이름이 ground면 땅과 충돌한 것이다
    if (coll.gameObject.tag == "ground"){
        Debug.Log("땅이다!");
    }
}

 

a) rtan script처럼 새로운 rain script를 생성하고

b) 위 코드를 넣어준 후

c) 드래그로 rain 스크립트 속성을 rain에게 부여해줌

 

 

잘 적용되어있다
실행해보면 땅땅!이 콘솔로 찍힌다.

 

### Warning !

실행을 해놓고, 멈춤을 누르고 설정을 바꾸면 저장되지 않는다,, 그래서 여태 날려먹은것 ㅠ
다시 실행버튼을 꼭 눌러서 초기화를 시키고 진행하자!

멈추지마 제발~~

 

d. 충돌 제거 하기

debug.log를 아래 destroy함수로 변경하기

gameObject는 나 자신을 의미함

 

void OnCollisionEnter2D(Collision2D coll)
{
    if (coll.gameObject.tag == "ground")
    {
        Destroy(gameObject);
    }
}

 

결론적으로 비가 없어지게 된다 하하하

 

4. 빗방울 랜덤 설정하기

a. 랜덤한 위치 잡아주기

1) 포지션 변경 함수

transform.position = new Vector3(x, y, z);

 

2) start() 에 랜덤 position 세팅하기

void Start()
{
    float x = Random.Range(-2.7f, 2.7f);
    float y = Random.Range(3.0f, 5.0f);
    transform.position = new Vector3(x, y, 0);
}

위 세팅은 x 기준 -2.7f ~ 2.7f  / y 기준 3.0f ~ 5.0f 사이의 랜덤한 값을 자동 생성해주고

transform.position으로 값을 지정해줘서 시작할 때 마다 새로운 위치에서 생성됨

 

b. 랜덤하게 대 / 중 / 소 사이즈 및 색상 잡아주기

0) 물방울 종류 정하기

* 3가지 종류의 물방울을 생성하며

* 종류마다 크기와 색상이 각각다르고

* 크기가 클 수록 점수가 높지만,  예외적으로 빨간 물방울은 감점

 

1) 사이즈 변경 함수

transform.localScale = new Vector3(size, size, 0);

 

2) 색 변경 함수

GetComponent<SpriteRenderer>().color = new Color(100 / 255f, 100 / 255f, 255 / 255f, 255 / 255f);

(참고 : 255.0f 로 나눠주는 게 핵심! = 나눈 값이 소수가 나오게 해야한다)

 

3) 3가지 물방울 만들기

종류, 사이즈, 점수를 변수화 해 사용함

int type;
float size;
int score;

// Start is called before the first frame update
void Start()
{
    float x = Random.Range(-2.7f, 2.7f);
    float y = Random.Range(3.0f, 5.0f);
    transform.position = new Vector3(x, y, 0);

    type = Random.Range(1, 4);  //1, 2, 3 까지

    if (type == 1)
    {
        size = 1.2f;
        score = 3;
        GetComponent<SpriteRenderer>().color = new Color(100 / 255f, 100 / 255f, 255 / 255f, 255 / 255f);
    }
    else if (type == 2)
    {
        size = 1.0f;
        score = 2;
        GetComponent<SpriteRenderer>().color = new Color(130 / 255f, 130 / 255f, 255 / 255f, 255 / 255f);
    }
    else
    {
        size = 0.8f;
        score = 1;
        GetComponent<SpriteRenderer>().color = new Color(150 / 255f, 150 / 255f, 255 / 255f, 255 / 255f);   //물방울 색상 변경하기
    }

    transform.localScale = new Vector3(size, size, 0); //물방울 크기 변경하기
}

 

5. 빗방울 여러개 생성하기

a. GameManager란?

게임 전체를 조율하는 오브젝트!

ex) 점수 / 다시 시작 / 3번 째 다시 시작에 부스터 / 광고보기 등

 

a) 몇 초 마다 특정 동작을 반복하게 하기

b) 어떤 특정 요소를 생성하는 기능이 있음

 

b. GameManager 생성하기

(1) MainScene에 createEmpty로 gameManager를 생성하기

(2) Script 폴더에 C#으로 GameManager script을 생성하기

(3) gameManager 객체에 스크립트 속성 부여하기

(4) 속성이 부여됐는지 확인하기

 

 

c. Prefabs 생성하기

(1) Prefabs 폴더 만들고

(2) 복제할 오브젝트를 끌어다놓고 (여기서는 rain)

(3) (rain) 오브젝트는 삭제함 (무서워)

 

잘가 rain,,,

 

d. 빗방울 복제하기

a) gameManager Script 에 Rain 선언하기

게임 매니저 c# 스크립트에서 프리팹을 연결해야하니 선언한다

 

public GameObject rain;

 

b) 유니티에서 gameManager 객체에 Rain이 지정하기

드래그 앤 드롭

 

c) 반복되는 함수를 정의하기

다시 gameManager Script로 돌아와서 

원하는 시간 마다 반복되는 함수 InvokeRepeating 을 사용한다

InvokeRepeating(String methodName, float time, float repeatRate);

 

위 함수를 이용해서 0.5초마다 한번씩 실행되는 함수(mainRain)를 생성한다

시작하자 마자 실행되어야 하니 Start() 함수에 넣어줌

void Start()
{
    InvokeRepeating("makeRain", 0, 0.5f);
}

void makeRain()
{
    Debug.Log("비를 내려라!");
}

잘 나온다

 

### Warning !

위 이미지에도 잘 나와있다시피 Assets의 GameManager Script말고, Hierarchy의 gameManager의 Rain을 설정해야 한다!!

 

옳은 예시
틀린 예시 (바보바보)

 

d) 비를 복제하기

log를 제거하고, 복제하는 함수인 Instantiate()함수를 사용해서 비를 복제해준다

void makeRain()
{
    Instantiate(rain);
}

 

e) gameManager Script의 전체 코드

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

public class GameManager : MonoBehaviour
{
    public GameObject rain;

    // Start is called before the first frame update
    void Start()
    {
        InvokeRepeating("makeRain", 0, 0.5f);
    }

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

    void makeRain()
    {
        Instantiate(rain);
    }

}

잘 나온다!

 

 


D. 점수 올라가게 하기

1. 점수 보드 만들기

UICanvas 위에 그려지고 카메라 위치와는 관계가 없이 보여짐

→ 버튼 / 텍스트 / 순위를 보여줄 때에만 사용

 

a. 폰트 적용하기

1) 배민한나체 다운로드

http://pop.baemin.com/fonts/hanna11yrs/BMHANNA_11yrs_ttf.ttf

 

2) Asset 하위폴더로 Font 폴더 생성 후 배민 한나체 넣어주기

 

b. Canvas 생성하기

MainScene → GameObject →  UI →  Canvas 생성

 

 

C. Text 생성하기

강의 버전과 다르게 최신버전에서는 Legacy에 있다 

 

찾았따 요놈

 

a) Inspector에서 제일 먼저 초기화 (reset)을 해주고

b) width , height값을 잡아주고

c) 위치를 잡아주고

d) 텍스트를 생성해주고

e) 저장한 폰트와 스타일을 설정해주고

f) 색상을 지정해주면 끝 

공통 설정

 

1) 위 설정된 text 객체를 4개로 만들어주고

2) 각 이름을 Label-Score, Score, Label Time, Time으로 설정해 준 후 각 속성에 맞게 변경한다

 

알아서 예쁘게 변경하자

 

### Warning !

설정이 모두 똑같은데 하나만 올라갔다
내려와 이좌식


원인은 60초라는 텍스트 안에 들어있는 엔터였다..

원인 : 엔터

 

2. GameManager Singleton

a. 싱글톤이란?

어디서도 부를 수 있는 '하나' 

 

b. 싱글톤을 만드는 코드

싱글톤을 원하는 스크립트에 아래 코드만 추가해주면 끝난다

public static GameManager I;

void Awake()
{
    I = this;
}

 

3. 점수가 올라가는 함수 만들기

GameManager Script에 점수가 올라가는 함수를 추가한다

int totalScore = 0;

public void addScore(int score)
{
    totalScore += score;
}

 

4. 캐릭터에 빗방울이 맞으면 점수 올라가게 하기

a. 캐릭터에 tag 주기

rtan 객체에 rtan 태그를 ground 했던것 처럼 똑같이 부여해주기

 

b. collider 주기

빗방울 적용할때랑 똑같이 생성하면 됨
혜자판정 완성

 

c. rain Script

빗방울 스크립트에 캐릭터에 맞으면 점수가 올라가고, 사라지게 만들기

(땅에 부딪혔을 때 랑 거의 똑같지만, 점수를 부여하는게 다름)

 

3번에서 한 싱글톤으로 생성한 gameManager의 addScore을 불러오면서, 저번 파일에서 제작한 score값을 넣어준다

void OnCollisionEnter2D(Collision2D coll)
{
    //나와 부딪힌 태그의 이름이 ground면 땅과 충돌한 것이다
    if (coll.gameObject.tag == "ground")
    {
        Destroy(gameObject);
    }

    if (coll.gameObject.tag == "rtan")
    {
        //게임매니저는 싱글톤이라 바로 불러올 수 있음
        GameManager.I.addScore(score);
        Destroy(gameObject);
    }
}

 

d. 확인하기

addScore 함수에 Debug.Log를 걸어서 확인

 

잘나온다

 

5. UI에 올라가는 점수 표기하기

a. UI Text 받기

using UnityEngine.UI; // 사용한다 선언하고

...

public Text scoreText; // scoreText 선언해주기

 

b. 데이터 값 보내주기

public void addScore(int score)
{
    totalScore += score;
    scoreText.text = totalScore.ToString();
}

 

6. 마주한 버그들

a. 물을 싫어하는 르탄이

<문제>

소수성 르탄;;
이런 로그가 찍혔다

 

<해결방법>

gameManager 에서 Score text 변수를 Score로 지정해주지 않아서 생긴 버그

 

 

<완성>

드디어 물을 좋아하는 르탄이,,

 

 

b. 컴파일 해결하고 게임해라

<문제>

네..

 

<해결방법>

대소문자 틀려서 그랬다 (내 잘못 아님 진짜로 원래 강의 코드가 잘못되어 있었음)

당당하게 대문자로 쓰거라

 

E. 게임 끝내기

1. Retry 판넬 만들기

a.  Panel 캔버스 생성하기

MainScene → GameObject → UI →  Canvas

Panel 아님 캔버스로 생성 후 이름을 Panel로 변경

 

속을뻔했다

 

b. Panel 캔버스에 Image를 추가

 

c. Image 설정

1) image 사이즈: 400 / 250

2) 배경 색상 (232, 52, 78, 255)

 

 

d. text 생성 및 설정

Image와 같은 위치에 text 객체을 생성한다

 

1) txt 설정: 80size / Bold / 중간정렬

2) 글자 색상 (255, 255, 255, 255)

3) 사이즈: 400 / 250

 

e. Panel 캔버스 설정

현재는 Inactive로 만들기

active <-> Inactive로 보였다 안보였다 설정을 할것임 (게임 끝나면 보이고, 게임이 시작하면 안보이게)

 

왼쪽 체크박스가 active설정이다 (활성화 된 상태)

 

 

2. 시간이 가게 하기

gameManager가 하는 역할!

a. 시간 변수 생성하기

public Text timeText;	//Canvas의 time을 엮는 변수
float limit = 60f;	//진행되는 시간을 알려주는 변수

 

b. 변수 매핑하기

변수 생성 뒤 Score 했던것과 마찬가지로 매핑 후 진행

 

 

c. 시간이 흐르게 하기

Time.deltaTime : 시간이 몇초가 지났는지 알려주는 함수

ToString("N2") : 소수점 둘째 자리까지 짤라서 문자열로 만들어줌 ((ex) 3.10초)

 

void Update()
{
        limit -= Time.deltaTime; 		//몇초가 지났는지 알려주는 역할
        timeText.text = limit.ToString("N2");
}

 

d. 멈추게 하기

limit 변수가 0이 되면 게임이 끝내야 한다 = 조건이 되고

timeScale : 시간을 느리게 , 멈추게, 빠르게 등 시간의 속성을 어떻게 할지 설정할 수 있는 속성

(0 : 멈춤, 1.0f : 실제 시간 흐름, 2.0f : 빠르게)

따라서 0이 된다면, 게임 속 시간이 흐르지 않아서 GameManager가 아무런 행동도 하지 않음

 

void Update()
{
    limit -= Time.deltaTime;
    if (limit < 0)
    {
        Time.timeScale = 0.0f;	//시간을 멈추세요!
        limit = 0.0f;			//남은 시간 없습니다!
    }
    timeTxt.text = timeLimit.ToString("N2");
}

 

3. 0초에 Retry 판넬 나오게 하기

a) Panel 받고 나오게 하기

public GameObject panel; //판넬 받고

...

// Update is called once per frame
void Update()
{
    limit -= Time.deltaTime; 	
    if (limit < 0)
    {
        Time.timeScale = 0.0f;
        panel.SetActive(true);  // 나오게하기 (추가된 코드)
        limit = 0.0f;
    }
    timeText.text = limit.ToString("N2");
}

 

b) Panel 연결하기

변수 설정 후 연결은 바로바로 하자

 

4. 판넬 클릭하면 다시 시작하게 하기

= mainScene을 리로드하면 됨!

a) Panel 캔버스에 button 컴포넌트를 추가하기

 

b) 다시하기 함수 생성하기

메인 씬 불러오는 것은 중앙(gameManager.cs)에서 해야할 일 = 중요한 일

SceneManagement를 받아와 MainScene이 다시 loac되는 retry()함수를 생성한다

 

using UnityEngine.SceneManagement;
...

public void retry()
{
    SceneManager.LoadScene("MainScene");
}

 

c) retry() 연결 함수 제작하기

panel.cs에서 retry() 함수를 사용할 수 있게 제작

gameManager에 구현된 retry()를 게임메니저를 통해 불러온다 = 안전한 방법

 

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

public class panel : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    
    //판넬을 클릭하면 이 함수가 실행됨
    public void retry()
    {
        GameManager.I.retry();
    }

}

-확인

 

4) 함수 연결하기

Panel 캔버스에 생성한 Button Comp에 On Click() 함수를 연결해준다

On Click()부분에 + 버튼을 눌러서 추가해 주면 된다

Panel 전체를 을 끌어다주고, retry() 함수를 연결했다.

 

+ 버튼 누르는지 모르고 당황했다

 

5. 초기화 함수를 만들기

a) 초기화 해야 할 요소들

전체시간, 남은시간, 점수를 초기화 해야 한다. 즉

→ timeScale, timeLimit, totalScore을 초기화!

 

b) 초기화 함수를 구현하기

InitGame()을 구현하고, 시작할때 실행될 수 있게 하기

void Start()
{
    InvokeRepeating("makeRain", 0, 0.5f);
    InitGame();
}

...
   
void InitGame()
{
    Time.timeScale = 1.0f; //현재 시간 속도로 구현
    totalScore = 0;
    limit = 5.0f;
}

 

 

F. 수업 전체 코드

https://github.com/bumkyulee/sparta-raindrop

 

GitHub - bumkyulee/sparta-raindrop: 로켓단 수업 자료 : "빗물 받는 르탄이"

로켓단 수업 자료 : "빗물 받는 르탄이". Contribute to bumkyulee/sparta-raindrop development by creating an account on GitHub.

github.com

 

 

G. 완성품

꺄 드디어 완성했다

(버벅거리는건 녹화를 잘못했어요 ㅠ.ㅠ)

내가 처음으로 만든 게임 으하하하