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

[2주차 게임] 풍선을 지켜라 -2

순정법사 2022.12.16

E. 시간 가게 하기

1. 시간 올라가게 하기

a. gameManager.cs에서 UI text 받기

using UnityEngine.UI;

public Text timeTxt;

 

b. timeText 연결하기

도킹완료

 

c. 시간 올리기

float alive = 0f;

void Update()
{
    alive += Time.deltaTime;
    timeTxt.text = alive.ToString("N2");  //숫자 -> 문자(소숫점 둘째자리까지)
}

 

d. 확인하기

잘간당~~

 

 

 

F. 게임 끝내기

1. 게임 종료 판넬 만들기

a. Canvas 판넬 만들기

UI → Canvas를 생성하고 endPanel로 rename 

 

b. endPanel 에서 Image(UI) 배경 만들기

1) 사이즈 x: 450, y: 600

2) Add Component로 shadow 추가하기

     (a) shadow: rgba 255, 255, 0, 150 (Add Component로 추가!)

     (b) distance(그림자 위치): x: 15, y: -15

 

노란색 그림자가 맞는걸까..?
음...

 

c. 폰트 다운받기

아래 주소를 복붙해 다운받고 Font폴더 생성후 파일을 넣어준다

폰트는 배달의 민족 주아체이다

 

http://pop.baemin.com/fonts/jua/BMJUA_ttf.ttf

 

잘 들어갔다

 

d. 끝 메시지 만들기

endPanel -> UI -> Legacy -> text로 끝 메시지를 생성함

 

1) 끝 메시지

* name: msg

* posY: 200

* width: 200 / height:200

* text: 끝

* font: 배민주아체

* size: 50

* bold / 가운데정렬

 

 

요렇게된당

 

e. 현재 스코어, 최고 스코어

각 스코어로 묶어서 따로 endPanel 하위 폴더로 또 Canvas를 생성함

그 각각의 Canvas안에서 스코어와 라벨을 각각 생성함 

 

이런식으로

 

1) 최고  스코어 maxScore Canvas

 

endPanel 하위 폴더로 maxScore인 Canvas를 생성 후 그 안에서 text인 label과 maxScoreTxt를 생성한다

ctrl+d (복제) 사용해서 만들기

 

a) label 

b) maxScoreTxt

 

* size: 40

* width: 200 / height:200

* 가운데정렬

* position: (-100, 100), (150, 100) - 각각 순서대로

* font: 배민주아체

* bold

* text: 최고, 0.00 - 각각 순서대로

* color: black, red

 

2) 현재 스코어 thisScore Canvas

 

endPanel 하위 폴더로 thisScore인 Canvas를 생성 후 그 안에서 text인 label, thisScoreTxt를 생성한다

 

* size: 40

* width: 200 / height:200

* 가운데정렬

* position: (-100, 0), (150, 0)

* font: 배민주아체

* bold

* text : 이번판, 0.00 - 각각 순서대로

* color: black

 

아 최고가 두개네 이런;;

 

f. retry 버튼 만들기

endPanel 하위 폴더로 retryBtn Canvas를 생성한 후 그 안에서 Image, Text를 생성함

 

1) Image 생성

 

* posY : -200

* width: 300, height: 100

* rgb: 80, 80, 200

 

2) text 생성

 

* PosY: -200

* width: 160, height: 50

* size: 40

* color: white

* bold, 중앙정렬

* text: 다시하기

 

변경된곳

 

이렇게 나온당

 

3) retryBtn에 속성(add comp) 달기

 

(a) Add Component -> button 속성을 부여해줌

 

(b) button 안에 Graphic target 에  Image를 연결해준다 (click시 색상 변화)

     -> retry 버튼에서 클릭시 색상이 변경되어야 하는 것은 Image이기때문!

 

이렇게 드래그해준다

 

g. 판넬 전체 숨기기

현재는 사용하지 않고, 나중에 나타나야 하니 inActive로 설정

 

잠깐만 눈감아..

 

2. 판넬 나타내기

a. gameManager 싱글톤 처리하기

public static gameManager I;

void Awake()
{
    I = this;
}

 

b. 게임 종료하기

1) gameManager.cs에 종료함수 만들기

 

시간을 멈추고, 판넬을 활성화하는 gameOver()함수를 생성

 

public GameObject endPanel;

public void gameOver()
{
    Time.timeScale = 0.0f;
    endPanel.SetActive(true);
}

 

연결까지 완료

 

 

2) square.cs에 네모가 풍선과 부딪히면 게임 종료하게 추가하기

 

(a) balloon을 태그에 걸어주기

여태까지 ballon인줄 알았다..

 

(a) 부딪히면 종료해주기

void OnCollisionEnter2D(Collision2D coll)
{
    if (coll.gameObject.tag == "balloon")
    {
        gameManager.I.gameOver();
    }
}

 

3) play 해서 확인하기

생각보다 어렵다;;

 

c. 현재 점수 보여주기

1) thisScoreText 가져오기

 

gameManager.cs에서 수정한다

 

public Text thisScoreTxt;

 

바로 연결해줬다

 

2) gameOver() 수정하기

 

 thisScoreTxt에 종료된 시간 넣어주기

public void gameOver()
{
    Time.timeScale = 0.0f;
    thisScoreTxt.text = alive.ToString("N2");
    endPanel.SetActive(true);
}
### Warning!

<문제>

게임을 너무 못해가지고 그런지 아님 버전이 달라져서 그런건지 모르겠지만,, 최고 점수와 현재 시간이 다른 이슈가 있음을 찾아내야 하는데 찾기가... 너무 힘들어서 3자리까지 만들어서 수정하고 실행했더니 다른 결과값이 결국!! 나왔다...

아니 왜 또 최고가 수정이 안됐지


<원인>

gameOver()이 실행이 되어서 점수는 6.717이 나와도, 게임이 정지되기 전에 Update()가 계속 실행되기 때문에 이런 이슈가 발생되는 것이다
내가 발견한 이슈는 아니고 강사님이 이런 이슈가 있으니 아래처럼 코딩하세요~ 라고 알려주셨다

<해결>

boolean 변수를 하나 생성해서 동시에 일어날 수 있도록 하면 해결된다! 아래 3)에 적혀있음

 

 

3) Update() 함수를 멈추게 하기

gameOver()를 부를때와 Update()가 멈추는 때가 다름, 그래서 동시에 제어할 변수(isRunning) 가 필요함 

(그래야지 TimeTxt = thisScoreTxt가 된다)

bool isRunning = true;

void Update()
{
    if (isRunning)
    {
        alive += Time.deltaTime;
        timeTxt.text = alive.ToString("N2");
    }
}

public void gameOver()
{
    isRunning = false;
    Time.timeScale = 0.0f;
    thisScoreTxt.text = alive.ToString("N2");
    endPanel.SetActive(true);
}

 

d. 다시하기 만들기

1) 다시하기 함수 만들기

 

gameManager.cs에서구현

 

using UnityEngine.SceneManagement;

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

 

2) 시간을 다시 켜주기

 

gameManager.cs에서구현, 꼭 시간도 되돌려놓아야 함

void Start()
{
    Time.timeScale = 1.0f;
    InvokeRepeating("makeSquare", 0.0f, 0.5f);
}

 

3) 다시하기 버튼에 retry() 함수 붙이기

 

(a) Runtime Only인지 확인

 

(b) Scene -> gameManager 클릭

 

저 위에 Editor And Rerun 아니빈다 (잘못함)

 

(c) gameManager의 retry()를 클릭하기

왜 기억이 안났찌

 

4) 확인하기

잘된당!!

 

G. 베스트 스코어 기록하기

1. 데이터를 보관하는 방법 

PlayerPrefs : 앱을 껐다 켜도 데이터가 유지되게 - 유니티에서 데이터를 보관하는 방법!

key, value로 항상 저장됨

 

a. 데이터 저장하기

PlayerPrefs.SetFloat("bestScore", 어떤숫자값);
PlayerPrefs.SetString("bestScore", 어떤문자열);

 

b. 데이터 불러오기

어떤숫자값 = PlayerPrefs.getFloat("bestScore");
어떤문자열 = PlayerPrefs.getString("bestScore");

 

c. 데이터를 저장했었는지 확인

true / false로 return

PlayerPrefs.HasKey("bestScore")

 

d. 데이터 저장하기

PlayerPrefs.DeleteAll();

 

2. 최고 점수 보여주기

a. 로직 생각하기

최고점수가 없으면 생성, 있을때 비교 후 저장

if (최고 점수가 없으면)
{
	최고점수 = 지금점수
}
else
{
	if (최고점수 < 지금점수)
	{
		최고점수 = 지금점수
	}
}

 

b. 구현하기

public void gameOver()
{
    isRunning = false;
    Time.timeScale = 0.0f;
    thisScoreTxt.text = alive.ToString("N2");
    endPanel.SetActive(true);

    if (PlayerPrefs.HasKey("bestScore") == false)
    {
        PlayerPrefs.SetFloat("bestScore", alive);
    }
    else
    {
        if (PlayerPrefs.GetFloat("bestScore") < alive)
        {
            PlayerPrefs.SetFloat("bestScore", alive);
        }
    }
}

 

c. 최고 점수 띄워주기

 

gameManager.cs에서구현

 

public Text bestScoreTxt;

...

void GameOver()
{
	bestScoreTxt.text = PlayerPrefs.GetFloat("bestScore").ToString("N2");
}

 

d. 확인하기

잘된당 근데 게임이 진짜 어렵다;;

 

 

H. 풍선 애니메이션 전환하기

1. 풍선이 터지면서 끝나게 하기(★) - 기능 생성

터지는 애니메이션을 만들어두고 → 풍선이 네모와 닿으면 "전환" 

 

a. 터지는 애니메이션(balloon_die) 만들기

0) Animation에 ballon_die animation 생성하고 Loop Time 체크 해제

1) ballon_die 더블클릭해서 Animation 창 팝업

2) 팝업된 Animation창에 balloon을 클릭하면 놓으면 ballon_idle이 있음

 

어피치를 클릭하세용

 

3) 추가로 add New Clip 해서 파일로 클릭해서 ballon_die.anim을 지목하기

 

 

4) 바꾸시겠습니까? OK

 

 

b. 풍선 CSS를 세팅하기

 

그대로 Animation에서 생성하면 됨 / 빨간 버튼 누르고 실행하쟈!!

 

만들쟈

 

1) 0.00초에 원래 풍선 CSS를 세팅하기

2) 0.20초에 rgba 255, 0 ,0, 125 / Scale: 2, 2

3) 실행하면 터지는 모션이 생성됨

 

팟팟팟!

 

c. balloon animator

balloon animator 창을 열어서, idle → die로 transition 만들기

 

우클릭 후 maketransition 하면 화살표로 드래그 할 수 있음

 

d. Parameters에, bool 형식의 isDie 를 만들기

이제 언제 die가 실행되어야 하는지 알려주기 위해 Boolean 형식을 생성해 줌

애니메이터 변수로 isDie를 생성함

 

Boolean 형식으로 생성해준다

 

e. transition을 클릭하고 아래와 같이 세팅하기

생성한 화살표를 클릭하면 Inspector가 뜸

1) Has Exit Time 체크 해제 (딜레이)

2) Condition : isDie 변수로 인해 실행되게 설정 / true

3) 저장하고 닫기

 

 

2. 풍선 애니메이션 전환하기 - 기능부여

a. gameManager.cs 에서 - animator를 받기

public Animator anim;

 

풍선에 에임 바로 연결!

 

b. gameOver() 할 때 isDie 값을 바꿔주기

public void gameOver()
{
    anim.SetBool("isDie", true);

    isRunning = false;
    Time.timeScale = 0.0f;
    thisScoreTxt.text = alive.ToString("N2");
    endPanel.SetActive(true);

    if (PlayerPrefs.HasKey("bestScore") == false)
    {
        PlayerPrefs.SetFloat("bestScore", alive);
    }
    else
    {
        if (PlayerPrefs.GetFloat("bestScore") < alive)
        {
            PlayerPrefs.SetFloat("bestScore", alive);
        }
    }
    bestScoreTxt.text = PlayerPrefs.GetFloat("bestScore").ToString("N2");
}

 

c. Invoke 처리하기

 

바로 멈춰버리면 애니메이션이 나올 틈이 없이 끝남 (Time.timeScale = 0.0f)

→ 0.5초 후에 시간을 멈추도록 Invoke 로 처리하기!

 

public void gameOver()
{
    anim.SetBool("isDie", true);

    isRunning = false;
    Invoke("timeStop", 0.5f);
    thisScoreTxt.text = alive.ToString("N2");
    endPanel.SetActive(true);

    if (PlayerPrefs.HasKey("bestScore") == false)
    {
        PlayerPrefs.SetFloat("bestScore", alive);
    }
    else
    {
        if (PlayerPrefs.GetFloat("bestScore") < alive)
        {
            PlayerPrefs.SetFloat("bestScore", alive);
        }
    }
    bestScoreTxt.text = PlayerPrefs.GetFloat("bestScore").ToString("N2");
}

void timeStop()
{
    Time.timeScale = 0.0f;
}

 

d. 다시 확인하기

 

잘된당!!

 

I. 떨어지는 네모를 없애기

1. square.cs 수정하기

 

Update()함수로 수시로 네모의 위치를 파악하면서, 선을 넘으면 삭제되게 하기

 

void Update()
{
    if(transform.position.y < -5.0f){
        Destroy(gameObject);
    }
}

잘 없어진당!