9-2. 첫 번째 프로젝트 (결승점, 장면, 스테이지 추가, UI생성, 빌드)

2023. 7. 12. 02:39C# & Unity 공부

5. 결승점과 장면이동

다음 스테이지로 넘어가는 결승점을 제작해야 한다.

 

우선 결승점 모양을 만들기로 하자.

저번에 제작했던 윈드존과 비슷하게 Cylinder를 만들어주고

이름을 Point라고 하자.

Albedo를 통해 색깔을 넣고, 렌더링 모드를 Transparent로 바꾼 뒤,

Emission을 통해 빛을 넣자.

또한 영역을 통해 다음 스테이지로 이동하므로 IsTrigger을 표시하고

Finish라는 태그를 붙여주자.

만들어진 결승점 모양

우리는 이제 결승점의 모양을 만들었으니, 이 결승점에 닿으면

다음 장면으로 넘어가는 것을 구현해야 한다.

그전에 조건식을 먼저 구현해야 하는데...

 

다음 스테이지로 넘어가긴 위해서 아이템을 다 먹어야 한다.

아이템의 총 개수를 불러와야 한다.

이것을 보통 관리하는 오브젝트를 매니저라고 한다.

 

매니저의 특징은 형태가 없으며, 전반적인 로직을 가졌다.

 

 

Hierarchy 우클릭 > Create Empty를 클릭해주고 이름을 GameManager으로 바꾸자.

후에 C# Script를 만들고 GameManager 오브젝트 안으로 넣어주자.

 

GameManagerLogic.cs :

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

 

public class GameManagerLogic : MonoBehaviour
{
    public int TotalItemCount;

}

 

위와 같이 코드를 짤 수 있다.

 

그리고 Inspector 창의 GameManager의 TotalItemCount을 현재 Item의 총 개수로 설정해주자.

 

다시 PlayerBall.cs로 넘어와서,

변수 선언 부분에 public GameManagerLogic manager;로 변수를 선언해주자.

이것은 GameManagerLogic 클래스 변수를 하나 만들어주었기 때문에,

Hierarchy부분에서 GameManager 오브젝트를 끌고와서 Player에 넣을 수 있다.

 

PlayerBall.cs의 OnTriggerEnter(Collider other) 함수 안 내용에

다음과 같이 짠 코드를 추가로 넣을 수 있다.

 

 else if (other.tag == "Finish")
        {
            //GameObject.FindGameObjectWithTag => Find 계열은 부하가 올 가능성이 있음 => 변수로 쓰는 방법이 있다.
            if(itemCount==manager.TotalItemCount)
            {
                //Game Clear!   
            }
            else
            {
                //Restart..
            }
        }

 

Finish 태그에 해당되는 영역에 트리거 이벤트가 발생하면,

만약 Manager의 TotalItemCount와 Player의 itemCount가 같다면,

GameClear가 발생하고 그렇지 않다면 Restart(재시작) 이벤트가 발생하는 것이다.

 

그럼 장면이동을 한번 구현해보자.

우선 현재 프로젝트를 저장 한 번 해주고,

좌측 위의 File > New Scene을 클릭해주자.

그리고 다시 Save를 해주자. 이때 파일의 이름을 "Example1_1"이라고 저장해주자.

 

그러면 Assets 창에

과 같이 새로운 Scene이 생긴다.

 

다음에는 File > Build Settings를 눌러

Add Open Scenes만 눌러 장면을 추가해주고 x를 클릭한다.

 

이렇게 되면 넘어갈 수 있는 장면을 만들어 준 것이다.

이제 코드를 작성하여 넘어갈 수 있게 짜주기만 하면 된다.

 

GameManagerLogic.cs : 

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

 

public class GameManagerLogic : MonoBehaviour
{
    public int TotalItemCount;
    public int stage;

}

 

PlayerBall.cs : 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement; //장면관리

public class PlayerBall : MonoBehaviour
{
    Rigidbody rigid;
    AudioSource audio;
    public int itemCount;
    public float JumpPower;
    public GameManagerLogic manager;
    bool isJump;

    void Awake()
    {
        isJump = false;
        rigid = GetComponent<Rigidbody>();
        audio = GetComponent<AudioSource>();
    }

    void Update()
    {
        if (Input.GetButtonDown("Jump")&&(!isJump))
        {
            isJump = true;
            rigid.AddForce(new Vector3(0, JumpPower, 0), ForceMode.Impulse);
        }
    }

    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.tag == "Ground")
            isJump = false;
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Item")
        {
            itemCount++;
            audio.Play();   
            other.gameObject.SetActive(false);
        }
        else if (other.tag == "Finish")
        {
            //GameObject.FindGameObjectWithTag => Find 계열은 부하가 올 가능성이 있음 => 변수로 쓰는 방법이 있다.
            if(itemCount==manager.TotalItemCount)
            {
                //Game Clear!   
                SceneManager.LoadScene("Example1_" + (manager.stage + 1).ToString());
            }
            else
            {
                //Restart..
                SceneManager.LoadScene("Example1_"+(manager.stage).ToString());
                //문자열에서 숫자를 더하면 문자열이 됨
            }
        }
    }

    void FixedUpdate()
    {
        float h = Input.GetAxisRaw("Horizontal");
        float v = Input.GetAxisRaw("Vertical");

        rigid.AddForce(new Vector3(h, 0, v), ForceMode.Impulse);
    }
}

 

주의할 점!!

1. 장면을 넘어가는 명령문인 SceneManager 클래스 안의 LoadScene함수를 쓰기 위해선,

using UnityEngine.SceneManagement를 꼭 써주어야 한다.

2. 또한 새로운 Scene (=스테이지)를 만들 때마다 복사해주는 Player에다가 GameManager을

끌어서 넣어야 하고 GameManager 오브젝트의 Inspector 창에 나타나는 stage를 스테이지 수와 일치해서

넣어주어야 한다.

 

6. 스테이지 추가

이제 스테이지를 넘어가는 방법을 배웠으니 

장면을 추가하면서 스테이지를 추가하고 지형을 만들면서 점점 게임처럼 사이즈를 늘려보자.

 

여기서 하나 놓친게 있다.

 

아이템을 다 먹든 안 먹든 결승점에 도착하면, 새로운 씬이 나오지만,

맵 바깥으로 낙하하면, 다시 시작되지 않고 무한 낙하하는 버그가 생긴다.

 

게임 매니저를 통해서 수정해줄 것이다.

 

우선 게임매니저를 맵 밑에 박아둔다.

그리고 Add Component를 하고, Box Collider를 선택한다.

IsTrigger을 선택하고 충분히 크기를 늘려

장판처럼 만들어준다.

 

저 밑에 초록색 큰 정사각형 범위에 들어가면

다시 재시작하는 트리거 이벤트를 만들 것이다.

 

GameManagerLogic.cs : 

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

 

public class GameManagerLogic : MonoBehaviour
{
    public int TotalItemCount;
    public int stage;

 

    private void OnTriggerEnter(Collider other)
    {
        if(other.gameObject.tag=="Player")
        {
            SceneManager.LoadScene(stage);
        }
    } 
}

 

다음과 같이 짤 수 있다.

using UnityEngine.SceneManagement를 써줄 것을 유의하자!!

스테이지 0
스테이지 1
스테이지 2

7. Ui 구현

저번 시간에 Ui를 구현하는 법을 배웠었다.

그래서 아이템 먹은 것을 알려주기 위한 Ui를 꾸미기 위해

위 사진과 같이 만들어준다.

 

우리가 원하는 것은 0 / 0이 아닌,

(현재 먹은 아이템 개수) / (다음 스테이지를 가기 위한 아이템 개수)이어야 한다.

 

GameManagerLogic.cs : 

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

public class GameManagerLogic : MonoBehaviour
{
    public int TotalItemCount;
    public int stage;
    public Text stageCountText;
    public Text playerCountText;
    
    void Awake()
    {
        stageCountText.text = "/" + TotalItemCount;
    }

    public void GetItem(int count)
    {
        playerCountText.text = count.ToString();
    }

    private void OnTriggerEnter(Collider other)
    {
        if(other.gameObject.tag=="Player")
        {
            SceneManager.LoadScene(stage);
        }
    }
}

 

PlayerBall.cs :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement; //장면관리

public class PlayerBall : MonoBehaviour
{
    Rigidbody rigid;
    AudioSource audio;
    public int itemCount;
    public float JumpPower;
    public GameManagerLogic manager;
    bool isJump;

    void Awake()
    {
        isJump = false;
        rigid = GetComponent<Rigidbody>();
        audio = GetComponent<AudioSource>();
    }

    void Update()
    {
        if (Input.GetButtonDown("Jump")&&(!isJump))
        {
            isJump = true;
            rigid.AddForce(new Vector3(0, JumpPower, 0), ForceMode.Impulse);
        }
    }

    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.tag == "Ground")
            isJump = false;
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Item")
        {
            itemCount++;
            audio.Play();   
            other.gameObject.SetActive(false);
            manager.GetItem(itemCount);
        }
        else if (other.tag == "Finish")
        {
            //GameObject.FindGameObjectWithTag => Find 계열은 부하가 올 가능성이 있음 => 변수로 쓰는 방법이 있다.
            if(itemCount==manager.TotalItemCount)
            {
                //Game Clear!   
                SceneManager.LoadScene("Example1_" + (manager.stage + 1).ToString());
            }
            else
            {
                //Restart..
                SceneManager.LoadScene("Example1_"+(manager.stage).ToString());
                //문자열에서 숫자를 더하면 문자열이 됨
            }
        }
    }

    void FixedUpdate()
    {
        float h = Input.GetAxisRaw("Horizontal");
        float v = Input.GetAxisRaw("Vertical");

        rigid.AddForce(new Vector3(h, 0, v), ForceMode.Impulse);
    }
}

 

1. using UnityEngine.Ui를 사용하여 Text와 관련된 것을 불러올 수 있게 한다.

2. GameManagerLogic에다가 text 변수를 2개 설정한다.

3. Inspector (GameManager) 창에 text와 관련된 오브젝트를 2개 끌여다 놓는다.

4. stageCountText.text는 변하지 않아도 되니 Awake()함수에 초기화를,

    playerCountText.text 는 Player가 아이템을 먹을 때마다 바뀌므로 함수를 선언하고

    이 함수를 PlayerBall.cs의 OnTriggerEnter() 함수에 넣어서 실행한다.

 

게임이 잘 적용되었다.

8. 빌드

이제 게임을 다  만들었으니, 실행시킬 수 있는 형태로 만들어야 한다.

File > Build Settings > Build를 누르면 된다.

 

잘 저장된 것을 확인할 수 있다
시작 화면
게임 화면