마지막 단계로 캐릭터가 빗방울을 받을 시에 점수가 올라가고, 반대로 빨간 빗방울을 받으면 점수가 깎이는 것까지 구현해주면 된다.
1. 폰트 적용
폰트 적용은 필요한 폰트를 다운받아 Assets에 담아 사용하면 된다. 이전에 캐릭터 이미지를 Assets에 관리한것과 같이 Folder를 생성하여 폰트를 적용해주면 된다.
2. UI TEXT 만들기
UI로 Text를 만들기 위해서는 Canvas를 만들어야 한다.
Canvas란?
모든 UI 요소는 Canvas 안에 위치해야 하며 캔버스는 Canvas 컴포넌트가 있는 게임 오브젝트이며 모든 UI 요소는 반드시 어떤 캔버스의 자식이어야 한다.
MainScene에서 우클릭 -> GameObject -> UI -> Canvas 를 생성하고, Canvas아래에 UI탭에 Text를 만들어 준다.
이제 텍스트 창을 보면 아래와 같이 뜨는데 이를 꾸며주면 다음과 같다. 사진 속 빨간부분만 변경하였으며 먼저 화살표부분을 눌러 Reset해준 다음 똑같이 바꿔주면 된다. Font적용은 Assets에 등록한 폰트를 드래그 앤 드롭하여 설정해주면 된다.
이제 같은 파일을 그대로 Ctrl + d로 복사하여 pos x축과 폰트를 건드려서 자기 입맛대로 커스텀해주면 된다.
필자는 좌측부터 x축을 -250, -130, 100, 250 순으로 했다.
Text에서 글자 모양을 바꿔줄 수 있으니 편하게 바꿔주면된다.
이제 UI를 완성했으니 빗방울을 받았을 때 해당하는 점수와 남은시간이 흘러가게끔 해야한다. 여기서 필요한게 바로 싱글톤이다.
3. 싱글톤
싱글톤 패턴은 런타임 동안 단 하나의 인스턴스만을 생성하는 패턴을 의미한다. 싱글톤 패턴이 적용된 객체는 하나의 인스턴스만 생성할 수 있으며 다른 객체에서 싱글톤 객체의 인슨턴스를 생성하려 할 경우 기존에 생성된 인스턴스가 있다면 해당 인스턴스를 반환하는 형태이다.
GameManager같은 경우에는 사용하는 빈도수도 높고, 단 하나만 존재해야 하기 때문에 이를 싱글톤패턴으로 처리해줘야 한다.
코드는 다음과 같다.
public static GameManager I;
void Awake()
{
I = this;
}
Awake함수는 Start와 다른점이 게임 시작 전에 변수를 초기화 하기위해 사용하고, 스크립트 실행시 가장 먼저 읽히는 부분이기도 하다. 즉 스크립트 실행했을때 I를 GameManager.I를 통해 호출했다면 여기로 불러와라는 뜻으로 해석할 수 있다.
싱글톤 패턴을 추가해줫다면 이제 점수가 올라가는 함수를 만들어야 한다.
점수가 올라가는 로직은 totalScore변수를 하나 정한 후 빗방울을 먹을 때 마다 Score를 더해서 올려주면 된다.
int totalScore = 0;
public void addScore(int score)
{
totalScore += score;
}
그리고 캐릭터에 맞으면 점수가 올라가야 하기 때문에 캐릭터에 tag를 적용하고, collider를 주면 된다. 저번에 땅에 충돌하는 것과 같이 Collider Component를 추가해주고, 캐릭터에 tag를 추가해주면된다. 캐릭터 tag이름을 Rtan으로 하겠다.
여기까지 잘 적용했으면 마지막으로 Rain Script로 와서 아래 만들어둔 OnCollisionEnter2D 함수의 if문에 새로 추가해주면 그만이다.
void OnCollisionEnter2D(Collision2D coll)
{
if (coll.gameObject.tag == "Ground")
{
Destroy(gameObject);
}
if (coll.gameObject.tag == "Rtan")
{
Destroy(gameObject);
GameManager.I.addScore(score);
}
}
이전에 싱글톤화 해놨기 때문에 위와 같이 gameManager에 있는 addScore함수를 호출할 수 있고, 위에서 타입마다 다른 Score를 담아서 보내줄 수 있는 것이다.
gameManager.cs에서 addScore함수에 Debug.Log(totalScore); 로 로그를 확인해보면 점수가 잘 들어오고 있다는 것을 알 수 있다.
4. 점수 및 시간 로직
UI Text를 받기위해서는 먼저 가장 윗줄에 UnityEngine을 추가해 줘야 한다. 아래 코드를 추가해주자.
using UnityEngine.UI;
public Text scoreText;
위 코드를 추가해주면 Text를 이용해 UI에 변하는 점수를 전달하여 이를 나타내줘야하는데, 그렇다면 역시 addScore함수 내에있는 totalScore를 계속 scoreText에 담아줘서 UI를 변하게 하면 된다.
public void addScore(int score)
{
totalScore += score;
scoreText.text = totalScore.ToString();
//Debug.Log(totalScore);
}
시간 표기도 마찬가지로 Text timeText 변수를 선언하여 시간의 경우 게임이 진행되는 동안의 변화이기 때문에 update내에서 해주도록 하자
float limit = 60.0f;
void Update()
{
limit -= Time.deltaTime;
if (limit < 0)
{
Time.timeScale = 0.0f;
limit = 0.0f;
}
timeText.text = limit.ToString("N2");
}
Time.deltaTime은 이전 프레임부터 현재 프레임까지 걸린 시간을 측정하는 함수이다. 이는 프레임과 관련됐지만, 컴퓨터의 성능차이가 있음에도 다 동일하게 계산되기 때문에 시간을 계산하는데 용이하다.
기존에 시작시간 60초로 정해두고 deltaTime으로 시간을 계속 빼주면 시간이 흐르는것과 같이 보인다.
if문은 limit가 0 이되면 게임이 멈춰야 하기 때문에 timeScale을 0으로 줘서 게임을 멈추게 하는 역할을 한다.
5. UI에 점수와 시간 표기하기
마지막으로 점수와 시간의 변화를 표기하기 위해서는 gameManager에 적용해줘야 한다. 앞에서 아래 두 가지 코드를 적용시켰을 것이다.
public Text scoreText;
public Text timeText;
gameManager에서 해당 코드를 입력하게 되면 Unity로 돌아왔을 때 얘네를 연결해달라고 나와있을 것이다. 여기서 scoreText는 Canvas의 score를, timeText는 Canvas의 time을 각각 드래그 앤 드롭으로 연결해주면 끝이다.
재생해보면 시간이 흘러가는 것을 볼 수 있다.
최종 코드
gameManger.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
public GameObject rain;
public static GameManager I;
public Text scoreText;
public Text timeText;
// 제한 시간
float limit = 60f;
int totalScore = 0;
void Awake()
{
I = this;
}
// Start is called before the first frame update
void Start()
{
initGame();
// 0.5초 마다 makeRain 함수를 호출한다.
InvokeRepeating("makeRain", 0, 1f);
}
// Update is called once per frame
void Update()
{
limit -= Time.deltaTime;
// 0초가 될 시에 게임이 멈춤
if(limit < 0)
{
// timeScale 시간을 멈출지 빠르게 느리게할지 정해주는 역할
Time.timeScale = 0.0f;
limit = 0.0f;
}
// N2 => 소수점 두자리까지 체크
timeText.text = limit.ToString("N2");
}
void makeRain()
{
Instantiate(rain);
//Debug.Log("비가 내린다!");
}
public void addScore(int score)
{
totalScore += score;
scoreText.text = totalScore.ToString();
//Debug.Log(totalScore);
}
Rain.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rain : MonoBehaviour
{
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, 5);
if (type == 1)
{
size = 1.2f;
score = 3;
// GetComponent<SpriteRenderer>() 는 C#에서 SpriteRenderer를 제어하는 함수,
GetComponent<SpriteRenderer>().color = new Color(100 / 255f, 100 / 255f, 100 / 255f, 100 / 255f);
}
else if (type == 2)
{
size = 1.2f;
score = 2;
GetComponent<SpriteRenderer>().color = new Color(130 / 255f, 130 / 255f, 130 / 255f, 255 / 255f);
}
else if(type == 3)
{
size = 0.8f;
score = 1;
GetComponent<SpriteRenderer>().color = new Color(150 / 255f, 150 / 255f, 255 / 255f, 255 / 255f);
}
else
{
size = 0.8f;
score = -5;
GetComponent<SpriteRenderer>().color = new Color(255 / 255.0f, 100.0f / 255.0f, 100.0f / 255.0f, 255.0f / 255.0f);
}
transform.localScale = new Vector3(size, size, 0);
}
// Update is called once per frame
void Update()
{
}
void OnCollisionEnter2D(Collision2D coll)
{
if (coll.gameObject.tag == "Ground")
{
Destroy(gameObject);
}
if (coll.gameObject.tag == "Rtan")
{
Destroy(gameObject);
GameManager.I.addScore(score);
}
}
}
Rtan.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rtan : MonoBehaviour
{
float direction = 0.05f;
float toward = 1.0f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
toward *= -1;
direction *= -1;
}
if (transform.position.x > 2.8f)
{
direction = -0.05f;
toward = -1.0f;
}
else if (transform.position.x < -2.8f)
{
direction = 0.05f;
toward = 1.0f;
}
transform.localScale = new Vector3(toward, 1, 1);
// Debug.Log(transform.position.x);
}
void FixedUpdate()
{
transform.position += new Vector3(direction, 0, 0);
}
}
'Unity' 카테고리의 다른 글
PlayerPrefs를 이용해 데이터 저장하기 (2) | 2023.10.31 |
---|---|
[Unity](빗방울 게임 마무리) 게임 끝내기 (1) | 2023.10.27 |
[Unity] 빗방울 랜덤으로 자동 생성 (0) | 2023.10.26 |
[Unity] 빗방울 추가 및 랜덤으로 빗방울 내리게하기 (0) | 2023.10.25 |
[Unity] Unity와 Visual Studio 연동 및 C#으로 마우스 좌클릭시 캐릭터 좌우 움직임 주기 (0) | 2023.10.25 |