[SerializeField] : private으로 선언했지만 인스펙터에서 접근할 수 있도록 함
scoreLebel.text = GameManager.Instance.TimeLimit.ToString("#.##");
▲ 소수점 아래 자리 제한 (#.##은 두번째자리까지 표시하겠다는 의미)
private void OnEnable()
{
Time.timeScale = 0f;
if (GameManager.Instance.IsCleared)
{
resultTitle.text = "Clear!";
scoreLabel.text = GameManager.Instance.TimeLimit.ToString("#.##");
SaveHighScore();
}
else
{
resultTitle.text = "Game Over";
scoreLabel.text = "";
}
scoreLabel.text = GameManager.Instance.TimeLimit.ToString("#.##");
}
public void TryAgainButton()
{
SceneManager.LoadScene("GameScene");
Time.timeScale = 1f;
}
OnEnable 함수는 오브젝트가 켜질때 호출됨
timeScale : 모든 것을 다 멈추게한다(애니메이션, 플레이어 등) deltatIme에도 영향을 받는다
using TMPro;
using Unity.Cinemachine;
using UnityEngine;
public class GameManager : MonoBehaviour
{
..생략
private bool isCleared;
public bool IsCleared
{
get { return isCleared; }
}
void GameOver()
{
isCleared = false;
popUpCanvas.SetActive(true);
}
public void GameClear()
{
isCleared = true;
popUpCanvas.SetActive(true);
}
}
GameClear 함수로 popup을 띄워주고 isCleared의 bool값에 따라 text를 다르게 출력해준다.
public class PopUpCanvas : MonoBehaviour
{
[SerializeField]
private TMP_Text resultTitle;
[SerializeField]
private TMP_Text scoreLabel;
[SerializeField]
GameObject highScoreObject;
private void OnEnable()
{
Time.timeScale = 0f;
if (GameManager.Instance.IsCleared)
{
resultTitle.text = "Clear!";
scoreLabel.text = GameManager.Instance.TimeLimit.ToString("#.##");
SaveHighScore();
}
else
{
resultTitle.text = "Game Over";
scoreLabel.text = "";
}
scoreLabel.text = GameManager.Instance.TimeLimit.ToString("#.##");
}
}
클리어했을 경우
게임 오버시
public class ResultCanvas : MonoBehaviour
{
void SaveHighScore()
{
float highScore = PlayerPrefs.GetFloat("highscore", 0);
if(GameManager.Instance.TimeLimit > highScore)
{
highScoreObject.SetActive(true);
PlayerPrefs.SetFloat("highscore", GameManager.Instance.TimeLimit);
PlayerPrefs.Save();
}
}
}
highScoreObject가 활성화되면서 가장 높은 점수일때 표시된다
string cureentScoreString = score.ToString("#.##");
string savedScoreString = PlayerPrefs.GetString("HighScores", "");
if (savedScoreString == "")
{
PlayerPrefs.SetString("HighScores", cureentScoreString);
}
else
{
string[] scoreArray = savedScoreString.Split(',');
}
배열을 만들어서 , 로 분류한다.
public class ResultCanvas : MonoBehaviour
{
[SerializeField]
private TMP_Text resultTitle;
[SerializeField]
private TMP_Text scoreLabel;
[SerializeField]
GameObject highScoreObject;
[SerializeField]
GameObject highScoreCanvas;
private void OnEnable()
{
Time.timeScale = 0f;
if (GameManager.Instance.IsCleared)
{
resultTitle.text = "Clear!";
scoreLabel.text = GameManager.Instance.TimeLimit.ToString("#.##");
SaveHighScore();
}
else
{
resultTitle.text = "Game Over";
scoreLabel.text = "";
}
scoreLabel.text = GameManager.Instance.TimeLimit.ToString("#.##");
}
void SaveHighScore()
{
float score = GameManager.Instance.TimeLimit;
float highScore = PlayerPrefs.GetFloat("highscore", 0);
if (GameManager.Instance.TimeLimit > highScore)
{
highScoreObject.SetActive(true);
PlayerPrefs.SetFloat("highscore", score);
PlayerPrefs.Save();
}
else
{
highScoreObject.SetActive(false);
}
string cureentScoreString = score.ToString("#.##");
string savedScoreString = PlayerPrefs.GetString("HighScores", "");
if (savedScoreString == "")
{
PlayerPrefs.SetString("HighScores", cureentScoreString);
}
else
{
string[] scoreArray = savedScoreString.Split(',');
List<string> scoreList = new List<string>(scoreArray);
for(int i = 0; i< scoreList.Count; i++) //적절한 위치에 새 스코어 넣기
{
float savedScore = float.Parse(scoreList[i]);
if(savedScore < score) // 나보다 낮은 점수가 들어온다면
{
scoreList.Insert(i, cureentScoreString); // 뒤로 밀어버린다
break;
}
}
if (scoreArray.Length == scoreList.Count) // 적절한 위치를 못 찾았다면 넌 꼴찌
{
scoreList.Add(cureentScoreString);
}
if(scoreList.Count>10) // 10개 넘으면 맨 끝 빼기
{
scoreList.RemoveAt(10);
}
string result = string.Join(",", scoreList); // 리스트를 하나의 스트링으로 합치기
Debug.Log(result);
PlayerPrefs.SetString("HighScores", result);
}
}
public void TryAgainButton()
{
SceneManager.LoadScene("GameScene");
Time.timeScale = 1f;
}
public void Quit()
{
Application.Quit();
}
public void OnHighScoreCanvas()
{
highScoreCanvas.SetActive(true);
}
}
score : 현재 남은 시간
highScore : 저장된 highscore (저장된게 없으면 0)void SaveHighScore() { float score = GameManager.Instance.TimeLimit; float highScore = PlayerPrefs.GetFloat("highscore", 0);
현재 TimeLimit (남은시간)이 저장된 highScore보다 크면
=(최고기록을 세우면)highscore을 다시 저장함
if (GameManager.Instance.TimeLimit > highScore) { highScoreObject.SetActive(true); PlayerPrefs.SetFloat("highscore", score); PlayerPrefs.Save(); }
cureentScoreString : 현재 점수
savedScoreString : 저장된 점수(처음에는 빈 스트링)
string cureentScoreString = score.ToString("#.##"); string savedScoreString = PlayerPrefs.GetString("HighScores", "");
저장된 점수가 빈 스트링이면 현재 스코어를 저장함
if (savedScoreString == "") { PlayerPrefs.SetString("HighScores", cureentScoreString); }
scoreList(string)을 float로 형변환해서 savedScore 변수에 넣어준다
비교해서 낮은 점수가 들어오면 적절한 위치에 넣거나 맨 끝에 넣음
float savedScore = float.Parse(scoreList[i]); if(savedScore < score) // 나보다 낮은 점수가 들어온다면 { scoreList.Insert(i, cureentScoreString); // 뒤로 밀어버린다 break; } if (scoreArray.Length == scoreList.Count) // 적절한 위치를 못 찾았다면 넌 꼴찌 { scoreList.Add(cureentScoreString); }
10개가 넘으면 맨 끝을 제거하고, result를 하나로 합친 후 저장
if(scoreList.Count>10) // 10개 넘으면 맨 끝 빼기 { scoreList.RemoveAt(10); } string result = string.Join(",", scoreList); // 리스트를 하나의 스트링으로 합치기 Debug.Log(result); PlayerPrefs.SetString("HighScores", result);
최고 기록 나열
using TMPro;
using UnityEngine;
public class HighscoreCanvas : MonoBehaviour
{
public TMP_Text ScoreLabel;
private void OnEnable()
{
string[] scores = PlayerPrefs.GetString("HighScores", "").Split(',');
string result = "";
for(int i=0; i<scores.Length; i++)
{
result += (i + 1) + ". " + scores[i] + "\n";
}
ScoreLabel.text = result;
}
public void ClosedPopUp()
{
gameObject.SetActive(false);
}
}
아래의 패널이 생기면 실행되는 함수로 저장된 최고기록들을 scores라는 배열에 저장한다.
최고기록들을 1. ~~~ 2. ~~로 출력하게 해준다.
using UnityEngine;
public class Bullet : MonoBehaviour
{
public Vector2 Velocity = new Vector2(10, 0);
void Start()
{
}
private void FixedUpdate()
{
transform.Translate(Velocity * Time.fixedDeltaTime);
}
void Update()
{
}
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject.tag == "Terrain")
{
Destroy(gameObject);
}
else if (collision.gameObject.tag == "Enemy")
{
Destroy(gameObject);
collision.GetComponent<EnemyController>().Hit(1);
}
}
}
프리팹으로 만들어주고 isTrigger, rigd2D를 Kinematic으로 설정
using UnityEngine;
public class EnemyController : MonoBehaviour
{
public int Hp = 3;
...생략
private void FixedUpdate()
{
// GetComponent<Rigidbody2D>().MovePosition
transform.Translate(vx*Time.fixedDeltaTime);
}
public void Hit(int damage)
{
Hp -= damage;
if(Hp <= 0 )
{
GetComponent<Rigidbody2D>().constraints = RigidbodyConstraints2D.None; //Freeze OFF
GetComponent<Rigidbody2D>().angularDamping = 720; //빙글빙글
GetComponent<Rigidbody2D>().AddForce(new Vector2(0, 10), ForceMode2D.Impulse);//한번에 힘을 주기
GetComponent<BoxCollider2D>().enabled = false;
Invoke("DestroyThis", 2f);
}
}
void DestroyThis()
{
Destroy(gameObject);
}
}
플레이어가 Die하듯이 적도 똑같이 지정해준다.
using TMPro;
using Unity.Cinemachine;
using UnityEngine;
public class GameManager : MonoBehaviour
{
..생략
void Update()
{
TimeLimit -= Time.deltaTime;
TimeLimitLabel.text = "Time Left " + ((int)TimeLimit);
if(TimeLimit<0)
{
GameOver();
}
}
if(TimeLimit<0)
간단하게 이 조건으로 완료!
아래와 같이 게임 루프에 instantiate가 많으면 렉이 발생할 확률이 높아진다.
ObjectPool 스크립트 생성
public class ObjectPool : MonoBehaviour
{
public GameObject Prefab;
public int InitialObjectNumber = 30;
List<GameObject> objs;
private void Start()
{
objs = new List<GameObject>();
for (int i = 0; i < InitialObjectNumber; i++)
{
GameObject go = Instantiate(Prefab, transform); //부모 지정
go.SetActive(false);
objs.Add(go);
}
}
public GameObject GetObject()
{
foreach (GameObject go in objs)
{
if (!go.activeSelf)
{
go.SetActive(true);
return go;
}
}
//준비해둔 30개를 다 쓰면 인스턴스로 생성
GameObject obj = Instantiate(Prefab, transform);
objs.Add(obj);
return obj;
}
}
Instantiate :
GameObject Object.Instantiate<GameObject>GameObject original, Vector3 position, Quaternion rotation
라고 사용
objs에 go(bullet : Prefab으로 지정한 오브젝트) 추가
using UnityEngine;
public class Bullet : MonoBehaviour
{
public Vector2 Velocity = new Vector2(10, 0);
void Start()
{
}
private void FixedUpdate()
{
transform.Translate(Velocity * Time.fixedDeltaTime);
}
void Update()
{
if(!GetComponent<SpriteRenderer>().isVisible)
{
gameObject.SetActive(false);
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject.tag == "Terrain")
{
gameObject.SetActive(false);
}
else if (collision.gameObject.tag == "Enemy")
{
gameObject.SetActive(false);
collision.GetComponent<EnemyController>().Hit(1);
}
}
}
gameObject.SetActive(false);
으로 수정
화면 밖을 나가면 비활성화된다
if(!GetComponent<SpriteRenderer>().isVisible)
{
gameObject.SetActive(false);
}
isVisible : 화면에 보이는지의 여부