나 개발자 진짜 되냐?

모바일 게임 만들어보기 2 - 4 풍선을 지켜라 게임 본문

유니티를 공부해봐요!

모바일 게임 만들어보기 2 - 4 풍선을 지켜라 게임

Snow Rabbit 2024. 9. 18. 14:45

 

 

 

즐거운 추석 보내고 계신가요?

날씨가 너어어무 더워서

어제 나갔다가 기절하는 줄 알았답니다..ㅎㅎ

 

 

 오늘은 마무리 느낌으로

 

최고점수를 구현 해보고

풍선이 게임 오버될 때 펑하고 사라지는

애니메이션을 만들어보자!

 


 

 최고점수를 구현하려면

새로운 문법을 공부해야 한다.

 

그 친구 이름은

PlayerPrefs

플레이어 프리팹이네요!

 

유니티에서 데이터를 보관할 수 있게

앱을 껐다 켜도 데이터가 유지되게 만들어진 친구예요!

 

 

PlayerPrefs.SetFloat("bestScore", 숫자값);

 

float형으로 저장한다.라는

매개변수는 두 개!!

 

괄호 안에 있는 변수값을 우리는 매개변수 라고 합니다.

 

bestScore키 값, 이름이라고 생각해 주면 되고

bestScore라는 이름으로 숫자값 좀 저장할게요.

라고 해석 할 수 있다.

 

 

PlayerPrefs. SetString("bestScore", 문자열);

 

마찬가지로 String자료형저장하겠다는 뜻이다.

 

 

데이터를 저장했으니

불러와야겠죠

 

어떤 숫자값 = PlayerPrefs.GetFloat("bestScore");

어떤 문자열 = PlayerPrefs.GetString("bestScore");

 

가져올 땐 GET을 써주면

bestScore라는 키 값가져올게요!라고 해석할 수 있다.

 

 

과연..

데이터가 저장되었을까?

 

확인하는 코드는

 

PlayerPrefs.HasKey("bestScore")

 HasKey라는 친구로 찾을 수 있다.

 

있으면 true, 없으면 false를 사용하게 된다.

 

 

저장했으니 삭제도 해야겠죠??

PlayerPrefs.DeleteAll();

 다 지워버리겠다!

 

 

자, 이제 코드를 진짜 작성해 보자

 

우리는 GameOver 됐을 때 생긴 그 기록으로 비교해줘야 하니까

GameOver로 가보자. 

 

로직을 짜기 전 구상을 해보자

 

만약에 최고점수의 기록이 없다면

최고점수 기록이 현재점수 기록이 될 것이다.

 

만약에 기록이 있다면

또 거기서

기록 중에서도 현재점수랑 최고점수랑 비교해서

크면 최고점수 갱신

작으면 현재점수 출력

 

이 나와야 한다.

 

public void GameOver()
{
    isPlay = false;
    Time.timeScale = 0.0f;
    nowScore.text = time.ToString("N2");


    if (PlayerPrefs.HasKey(key))  // 최고점수가 있다면
    {
        //최고점수 불러오기, 그 값을 변수에 저장
        float best = PlayerPrefs.GetFloat(key);

        //그 변수값이 시간보다 작다면, 현재점수 > 최고점수, 갱신
        if (best < time)
        {
            PlayerPrefs.SetFloat(key,time); //갱신한 값 time을 넣어준다.
            //그 다음에 Text에 넣어서 띄우기
            bestScore.text = time.ToString("N2");
        }
        else // 현재점수 < 최고점수
        {
            //변한게 없으니 그냥 best값을 계속 띄워주면 된다.
            bestScore.text = best.ToString("N2");
        }
        
    }
    else  // 최고점수가 없다면
    {
        PlayerPrefs.SetFloat(key, time); // 그냥 있던 값 가져오기
        bestScore.text = time.ToString("N2");
    }

    endPanel.SetActive(true);
    // 현재점수 저장

}

 

코드 보며 하나하나 익히도록 하자!

 

그렇게 해주면!

 

자라라

 

 완성!

 

자 이제 마지막으로

 

풍선 애니메이션을 구현해 보자

 

 먼저 처음에 우리

풍선 깜박거리게 해 주었던

그 애니메이션

기억나나요?

 

Balloon_Idle

 

 

 들어가 보면 저기

Balloon_Idle 옆 역삼각형 눌러서

Create New Clip

 

엇...

안 눌리신다고요?!

 

기억하시나요?

Balloon 오브젝트를 눌러야 한다는 사실을..!!

 

해주면 익숙한... 나의 컴퓨터가 뜹니다.

맨 위에 Animation 폴더 안에

Balloon_Die라고 이름을 바꿔주고 

 

저장!

 

 그다음에

녹화버튼 클릭!

 

하얀색 선을 0:20에 맞춰두고

 

오른쪽에 Inspector > Color 255 0 0 125 설정

터지는 느낌 나게

사이즈도 Scale

X 2 , Y 2

 

다음에 여기서 중요한 건

게임오버 될 때 한 번만 터져야 하니까

 

Loop Time을 껴줘야 한다.

 

 그다음에!

 

Idle위에 있는

Animator을 눌러준다.

 

 

 

 이동키는 Alt를 눌러주면서 왼쪽 마우스 버튼을 움직여 준다.

 

우리는 Balloon_Idle이라는 친구가

게임이 오버됐을 때 Balloon_Die로 바뀌어야 한다.

 

그래서 Idle에서 오른쪽 마우스 클릭

Make Transition

 

그러면 선이 생기는데 Die에 연결해 주면 된다.

 

그다음에 왼쪽 위에 보면 

Layers 말고 옆에 Parameters가 있다.

눌러주고

 

 

+버튼

bool 클릭, 그러면 이름이 생기는데

isDie로 설정해 준다.

 

자 틀을 설명해 보자면

우리는 Idle에서 true가 되면

Die가 실행되도록 만들 것이다.

 

방금 그려 넣은 transform 가운데 화살표를 누르면

 

설정창이 열리는데

 

여기서

 

Has exit time 버튼을 해지해준다.

 

이 친구를 해지해야만

언제든지

다음 애니메이션으로 넘어갈 수 있는 준비가 됐다는 뜻을 가지고 있다.

 

밑에 Setting

 

Transition Duration 값 0

 

 

맨 밑에 Conditions 컴포넌트 + 버튼 누르고

isDie true라고 설정해 주면! 끝!

 

 

이렇게 해주면 잘 됐다.

 

자 이제 우리는 이 애니메이션을 

게임매니저 스크립트에 넣어주어야 한다.

 

애니메이션을 넣고,

죽었을 때는 이제 애니메이션이 바뀌게 나와야 한다.

 

스크립트 창에 가서 

 먼저

 애니메이션을 가져와 하니까

변수 선언

 

Public Animator anim;

GameOver함수로 가서

isPlay 바로 밑에부터 작성해 주면 된다.

 

 

anim.SetBool("isDie", true);

 

 이 친구를 적어주면 되는데

 

불값을 바꿔준다.

isDie라는 키값

true로 

 

이렇게 해주면 오류가 하나 발생한다.

 

우리가 timeScale을 바로밑에

0으로 줬기 때문에,

 

애니메이터도 동작을 하지 않는 사태가 발생!!

 

그래서 우리는 이 timeScale을

살짝 지연 후 실행시켜줘야 한다.

 

지연해주던 함수 

❗❗ InVoke ❗❗

 

InVoke 함수를 먼저 제일 밑에 따로 만들어준다.

그 함수 안에 Time.timeScale = 0.0f; 값을 적어주고

 

InVoke로 0.5초 있다가 실행시켜!라는 의미의

Invoke("TimeStop", 0.5f);

TimeStop라는 함수를

0.5초 정도 있다가 실행될 수 있도록 해줘!

 

라는 뜻이다.

 

 

 

 자 다됐으면 실행!!

 

아!!

 

애니메이터 드래그 드롭 잊지 말기!!

 

 

 

 바로 저처럼 됩니다..^^

 

 

 

끝!!

 

코드공유

 

< GameManager.cs >

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

public class GameManager : MonoBehaviour
{

    public GameObject square;

    //시간을 담는 변수 생성
    float time = 0.00f;

    //시간을 컴포넌트에 넣기 위한 변수
    public Text timeTxt;

    //게임 종료후 점수판 올리기 변수
    public GameObject endPanel;

    //시간을 담은 변수를 현재점수에 넣기위한 현재점수 변수
    public Text nowScore;

    //bool값을 이용해 작은 오차를 줄인다.
    bool isPlay = true;

    //최고점수를 넣어줄 변수
    public Text bestScore;

    //데이터 저장시 키값의 오타우려가 있으니 변수로 지정
    string key = "bestScore";

    //애니메이터 가져오는 변수
    public Animator anim;

    //싱글톤은 단 하나만 존재한다.너는 딱 하나야! 라는것을 통해 다른곳에서 나를 부를 수 있게 하는것.
    public static GameManager instance;
    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }
        
    }

    // Start is called before the first frame update
    void Start()
    {
        Time.timeScale = 1.0f;
        InvokeRepeating("MakeSquare", 0f, 1f);
    }

    // Update is called once per frame
    void Update()
    {
        if (isPlay == true) // ispaly만 써도 된다.  같은뜻 만약에 false를 쓰려면 !isplay라고 해주면 된다.
        {
            time += Time.deltaTime;
            timeTxt.text = time.ToString("N2");
        }
        
    }

    void MakeSquare()
    {
        Instantiate(square);
    }
    
    public void GameOver()
    {
        isPlay = false;
        anim.SetBool("isDie", true); //값을 바꿔주는 것
        Invoke("TimeStop", 0.5f);
        nowScore.text = time.ToString("N2");


        if (PlayerPrefs.HasKey(key))  // 최고점수가 있다면
        {
            //최고점수 불러오기, 그 값을 변수에 저장
            float best = PlayerPrefs.GetFloat(key);

            //그 변수값이 시간보다 작다면, 현재점수 > 최고점수, 갱신
            if (best < time)
            {
                PlayerPrefs.SetFloat(key,time); //갱신한 값 time을 넣어준다.
                //그 다음에 Text에 넣어서 띄우기
                bestScore.text = time.ToString("N2");
            }
            else // 현재점수 < 최고점수
            {
                //변한게 없으니 그냥 best값을 계속 띄워주면 된다.
                bestScore.text = best.ToString("N2");
            }
            
        }
        else  // 최고점수가 없다면
        {
            PlayerPrefs.SetFloat(key, time); // 그냥 있던 값 가져오기
            bestScore.text = time.ToString("N2");
        }

        endPanel.SetActive(true);
        // 현재점수 저장
    }
    void TimeStop()
    {
        Time.timeScale = 0.0f;
    }

}

 

 < Square.cs >

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

public class NewBehaviourScript : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        // 랜덤한 위치에 두는 함수 Random.Range
        float x = Random.Range(-3.0f, 3.0f);
        float y = Random.Range(3.0f, 5.0f);

        // 랜덤한 사이즈 변경
        float size = Random.Range(0.5f, 1.5f);

        //이 값을 우리는 Transform > position에 넣어줘야한다.
        transform.position = new Vector2(x, y);

        //랜덤한 사이즈는 scale 인데 앞에 local이 꼭 붙어야한다.
        transform.localScale = new Vector2(size, size);
        
    }

    // Update is called once per frame
    void Update()
    {   
        if (transform.position.y < -4.5f)
        {
            Destroy(gameObject);
        }
        
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("Player"))
        {
            GameManager.instance.GameOver();
        }
    }
}

 

 < Shield.cs >

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

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

    // Update is called once per frame
    void Update()
    {   
        // 마우스포인트와 게임상 쉴드의 위치를 같게 한다.
        Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        //이 값을 쉴드 오브젝트에 transform 컴포넌트에 position에 넣어준다.
        transform.position = mousePos;
    }
}

 

 < Retry. cs >

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

public class RetryButton : MonoBehaviour
{
  public void Retry()
    {
        //mainscene 데려오면 된다.
        SceneManager.LoadScene("MainScene");
    }
  
}

 

 

 

< 추가 학습 >

 

플레이버튼을 누르면

떨어지는 네모들이 계속 쌓이게 된다.

 

이 친구들을 없애는 방법은?!

 

코드는 단 두줄..

 

 

사실 엄청 쉬웠는데

나는 답을 봐버렸다..

흑흑

 

0. 반복적으로 사라져야 하니깐 Update에

 

1. 일정 거리만큼 내려갔을 경우

( If문 사용 )

 

2. 파괴 

( Destroy ) , gameObject 즉 자기 자신 square를

if (transform.position.y < -4.5f)
{
    Destroy(gameObject);
}

 

 

진짜 끝!! 

 

 

 

 

< 이 프로젝트는 스파르타 코딩수업에서 배운 내용을 복습 한 내용입니다. >