[멋쟁이사자처럼 부트캠프 TIL] 멋쟁이사자처럼 유니티게임스쿨 5일차

굥지·2024년 10월 7일
0

[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 줄이기(오브젝트 풀링)

아래와 같이 게임 루프에 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 : 화면에 보이는지의 여부

0개의 댓글

관련 채용 정보