지난번 기사에서 Bird가 파이프에 부딪치면 동작을 멈추게 했다.
이번에는 Bird가 파이프를 통과 할 때 한 점씩 점수를 얻으려고합니다.
그 전에 이전 기사에서 Bird가 멈추었지만 막상 파이프의 반복 생성을 막는 것을 놓쳤다.
그리고 오류 하나, 또 놓치고 ㅠㅠ
Bird가 초반 Ready 상태일 때도 파이프가 계속 생성되고 있다.
그걸 먼저 잡아 가야 해..,
매우 간단합니다.
(간단한 것을 놓쳤다 ~)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnPoint : MonoBehaviour
{
// 파이프 프리팹
public GameObject pipePrefab;
// 스폰 시간
(SerializeField) float spawnTime = 1;
// 타이머
private float countdown = 0;
// 랜덤하게 나올 스폰 타임
(SerializeField) float spawnMaxTime = 1.1f;
(SerializeField) float spawnMinTime = 0.9f;
// 랜덤하게 나올 스폰 위치
(SerializeField) float spawnMaxY = 2.3f;
(SerializeField) float spawnMinY = -1.3f;
void Update()
{
// Death 상태이거나 Start 전이면 프리팹 생성을 멈춘다
if(GameManager.isStart == false || GameManager.isDeath == true)
{
return;
}
// 타이머 구현
countdown += Time.deltaTime;
if (countdown >= spawnTime)
{
SpawnPipe();
countdown = 0;
// 시간을 랜덤하게 스폰하기
spawnTime = Random.Range(spawnMinTime, spawnMaxTime);
}
}
void SpawnPipe()
{
// 위치를 랜덤하게 스폰하기
float spawnY = transform.position.y + Random.Range(spawnMinY, spawnMaxY);
Vector3 randomPosition = new Vector3(transform.position.x, spawnY, transform.position.z);
// 파이프 프리팹 생성
Instantiate(pipePrefab, randomPosition, Quaternion.identity);
}
}
단지 조건에 맞추어 return시켜 주면 된다.
그런 다음 파이프를 통과 할 때 점수를 누적하여 점수를 얻습니다.
UI를 활용해 만들 예정이다.
이 게임의 UI를 관리하는 캔버스를 만듭니다.
(모든 UI가 화면에 표시되려면 무조건 캔버스에 표시해야 합니다.
)
히라키 창에서 오른쪽 클릭 → UI → Canvas를 클릭
빈 객체로 PlayUI와 UI 폴더를 별도로 나누었다.
(나중에 혼란을 주기 위해 미리 폴더를 정리합시다.
)
숫자를 입력하기 위해 TextMeshPro사용합니다.
히라기 윈도우 오른쪽 클릭 → UI → Text – TextMeshPro를 클릭
개인적으로 UI는 결국 개인 센스 감각에 따라 바뀌었다고 생각한다.
물론 어느 정도 기술과 지식은 당연히 가지고 있어야 하지만..^_ㅠ
나도 일단 대략 장식해 보았다… .. . ..
위의 숫자 00은 누적된 점수가 표시되는 곳입니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
// 플레이어 죽음 체크하기
public static bool isDeath = false;
// 플레이어 시작 체크하기
public static bool isStart = false;
// 스코어
public static int score = 0;
void Start()
{
isDeath = false;
isStart = false;
score = 0;
}
}
GameManager에서는 통상 score, life, bool형 등 대규모를 관리한다.
점수도 마찬가지 Static을 사용했으므로 0으로 항상 초기화한다.
using UnityEngine;
using TMPro;
public class PlayUI : MonoBehaviour
{
public TextMeshProUGUI scoreText;
void Update()
{
scoreText.text = GameManager.score.ToString();
}
}
PlayUI 스크립트를 작성하고 text를 누적하여 수신할 변수를 선언합니다.
인스펙터 윈도우에서 자신을 드래그해 넣어준다.
(텍스트를 필드 선언 할 때 using TMPro;를 추가하십시오.)
그리고 GameManager에서 선언한 점수를 문자열 형식으로 받습니다.
void GetScore()
{
GameManager.score++;
}
void OnTriggerEnter2D(Collider2D coll)
{
if(coll.gameObject.tag == "Score")
{
GameManager.isDeath = false;
GetScore();
}
}
그리고 플레이어 스크립트로 돌아와 Bird가 파이프를 통과했을 때
GameManager 점수가 하나씩 누적 추가되도록 메서드 GetScore를 만들고 만들고,
Trigger가 호출될 때 GetScore 메서드가 실행되도록 구현했습니다.
점수가 1씩 올라가는 것을 확인할 수 있다.
완전한 코드
↓
SpawnPoint.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnPoint : MonoBehaviour
{
// 파이프 프리팹
public GameObject pipePrefab;
// 스폰 시간
(SerializeField) float spawnTime = 1;
// 타이머
private float countdown = 0;
// 랜덤하게 나올 스폰 타임
(SerializeField) float spawnMaxTime = 1.1f;
(SerializeField) float spawnMinTime = 0.9f;
// 랜덤하게 나올 스폰 위치
(SerializeField) float spawnMaxY = 2.3f;
(SerializeField) float spawnMinY = -1.3f;
void Update()
{
// Death 상태이거나 Start 전이면 프리팹 생성을 멈춘다
if(GameManager.isStart == false || GameManager.isDeath == true)
{
return;
}
// 타이머 구현
countdown += Time.deltaTime;
if (countdown >= spawnTime)
{
SpawnPipe();
countdown = 0;
// 시간을 랜덤하게 스폰하기
spawnTime = Random.Range(spawnMinTime, spawnMaxTime);
}
}
void SpawnPipe()
{
// 위치를 랜덤하게 스폰하기
float spawnY = transform.position.y + Random.Range(spawnMinY, spawnMaxY);
Vector3 randomPosition = new Vector3(transform.position.x, spawnY, transform.position.z);
// 파이프 프리팹 생성
Instantiate(pipePrefab, randomPosition, Quaternion.identity);
}
}
GameManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
// 플레이어 죽음 체크하기
public static bool isDeath = false;
// 플레이어 시작 체크하기
public static bool isStart = false;
// 스코어
public static int score = 0;
void Start()
{
isDeath = false;
isStart = false;
score = 0;
}
}
PlayUI.cs
using UnityEngine;
using TMPro;
public class PlayUI : MonoBehaviour
{
public TextMeshProUGUI scoreText;
void Update()
{
scoreText.text = GameManager.score.ToString();
}
}
Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
// Jump 구현
Rigidbody2D rb;
(SerializeField) float Speed = 5f;
private bool keyJump = false;
// Rotate 구현
(SerializeField) private float upRotate = 5f;
(SerializeField) private float downRotate = -5f;
private Vector3 birdRotation;
// Move 구현
(SerializeField) private float moveSpeed = 5f;
// Ready 구현
(SerializeField) private float readyPower = 0.3f;
void Start()
{ // RigidBody2D 컴포넌트를 rb라는 변수를 통해 가져온다
rb = this.GetComponent<Rigidbody2D>();
}
void Update()
{
InputBird();
if(GameManager.isStart == false)
{
ReadyBird();
return;
}
RotateBird();
MoveBird();
}
private void FixedUpdate()
{
// 게임 물리 연산은 FixedUpdate 메서드 안에서 진행한다
// 입력받은 Jump값이 true라면
if (keyJump == true)
{
// JumpBird메서드 받기
JumpBird();
// 그리고 다시 keyJump값은 false로 만들어준다
keyJump = false;
}
}
void ReadyBird()
{
if (rb.velocity.y < 0)
{
rb.velocity = Vector2.up * readyPower;
}
}
void JumpBird()
{ // Rigidbody의 velocity 는 Speed 만큼 올라간다
rb.velocity = Vector3.up * Speed;
}
void InputBird()
{
if(GameManager.isDeath == true)
{
return;
}
// 스페이스바 혹은 마우스 좌버튼을 눌렀을 때
keyJump |= Input.GetKeyDown(KeyCode.Space);
keyJump |= Input.GetMouseButtonDown(0);
// Bird가 시작했을 때 내려오지 않는 버그 수정
if(GameManager.isStart == false && keyJump == true)
{
GameManager.isStart = true;
}
}
void RotateBird()
{
// upRotate와 downRotate를 누적해서 저장할 변수 degree 초기화
float degree = 0;
if(rb.velocity.y > 0)
{
// upRotate 누적
degree = upRotate;
}
else if(rb.velocity.y < 0)
{
// downRotate 누적
degree = downRotate;
}
// birdRotation을 오일러각으로 변환하여 최댓값 30, 최솟값 -90을 받는다
birdRotation = new Vector3(0, 0, Mathf.Clamp((birdRotation.z + degree), -90, 30));
transform.eulerAngles = birdRotation;
}
void MoveBird()
{
if(GameManager.isDeath == true)
{
return;
}
// Bird가 앞으로 이동하는 것 구현하기
transform.Translate(Vector3.right * moveSpeed * Time.deltaTime, Space.World);
}
void GetScore()
{
GameManager.score++;
}
void OnTriggerEnter2D(Collider2D coll)
{
if(coll.gameObject.tag == "Score")
{
GameManager.isDeath = false;
GetScore();
}
}
void OnCollisionEnter2D(Collision2D coll)
{
if(coll.gameObject.tag == "Pipe" || coll.gameObject.tag == "Ground")
{
GameManager.isDeath = true;
}
}
}