[Unity] 2D 엔드리스 러너 게임 만들기 (5) - 스테이지 추가, 장애물 추가

Kim Yuhyeon·2023년 4월 17일
0

게임개발

목록 보기
84/135

참고

초간단 유니티로 엔드리스 러너 만들기!

스테이지

GameManager.cs

[System.Serializable]
public class Stage
{
    public Sprite[] grounds;
    public GameObject[] mobs; 
}

public int curStage; // 현재 스테이지
public int[] stageScore; // 다음 스테이지로 넘어가기 위한 점수
public Stage[] stages;


    IEnumerator AddScore()
    {
        while (isPlay)
        {
            // 각 스테이지에 필요한 점수를 도달했을 때
            if (stageScore[curStage] <= score)
                curStage++;
     
            score++;
            scoreText.text = score.ToString();
            gameSpeed += 0.01f; // 게임이 점점 빨라지게 
            yield return new WaitForSeconds(0.1f);
        }
    }
    
    public void PlayBtnClick()
    {
        playBtn.SetActive(false);
    
        // 스테이지 초기화
        curStage = 0;
        
        isPlay = true;
        onPlay.Invoke(isPlay);
        
        // 점수 초기화
        score = 0;
        scoreText.text = score.ToString();
        
        // 점수 증가 시작
        StartCoroutine(AddScore());
    }

GroundScroller.cs


// public Sprite[] groundImg;
private GameManager gm;
    
    
    void Start()
    {
        gm = GameManager.instance;
        temp = tiles[0];
    }
    
    void Update()
	{
      	...
    
     	tiles[i].sprite = gm.stages[gm.curStage].grounds[Random.Range(0, gm.stages[gm.curStage].grounds.Length)];
    
    	...
    }

장애물

RespawnManager.cs

[System.Serializable]
public class StageMob
{
    public List<GameObject> mobs = new List<GameObject>();
}

스테이지별로 따로 관리

public class RespawnManager : MonoBehaviour
{
    public List<StageMob> MobPool = new List<StageMob>();
    public int objCnt = 5;
    GameManager gm;
    
    void Awake()
    {
        
        gm = GameManager.instance;

        if (gm == null)
        {
            gm = FindObjectOfType<GameManager>();

            if (gm == null)
            {
                Debug.LogError("GameManager not found in scene.");
                return;
            }
        }

        for (int i = 0; i < gm.stages.Length; i++)
        {
            StageMob stage = new StageMob();
            
            for (int j = 0; j < gm.stages[i].mobs.Length; j++)
            {
                for (int q = 0; q < objCnt; q++)
                {
                    stage.mobs.Add(CreateObj(gm.stages[i].mobs[j], transform));
                }
            }
            
            MobPool.Add(stage);
        }
    }

영상대로 하니 여기서 자꾸 Null 오류나서, GPT형 도움받았다 ㅎ..

gm 변수를 GameManager.instance로 초기화하면 NullReferenceException이 발생하는 이유는 다음과 같습니다.

GameManager 스크립트의 instance 변수는 정적으로 선언되어 있습니다. 정적 변수는 클래스의 인스턴스화 없이도 사용할 수 있습니다.

하지만 instance 변수는 GameManager 객체를 참조하도록 초기화되어 있으므로, GameManager 객체가 생성되기 전에 instance 변수를 사용하려고 하면 NullReferenceException이 발생합니다.

따라서 Awake() 함수에서 gm 변수에 GameManager.instance 값을 할당하기 전에, GameManager 객체가 생성되었는지 확인하고 생성되어 있지 않다면 FindObjectOfType() 함수를 이용하여 GameManager 객체를 찾아 할당하는 것이 좋습니다.

이렇게 함으로써 GameManager 객체가 생성되기 전에 NullReferenceException이 발생하는 것을 방지할 수 있습니다.

void PlayGame(bool isPlay)
    {
        if (isPlay)
        {
            // 시작 전 장애물 비활성화
            for (int i = 0; i < MobPool.Count; i++)
            {
                for (int j = 0; j < MobPool[i].mobs.Count; j++)
                {
                    if (MobPool[i].mobs[j].activeSelf)
                        MobPool[i].mobs[j].SetActive(false);
                }
                
            }
            StartCoroutine(CreateMob());
        }
        else 
            StopAllCoroutines();
    }

    IEnumerator CreateMob()
    {
        yield return new WaitForSeconds(0.5f);
        while (GameManager.instance.isPlay)
        {
            MobPool[gm.curStage].mobs[DeactiveMob(MobPool[gm.curStage].mobs)].SetActive(true);
            yield return new WaitForSeconds(Random.Range(1f, 3f));
        }
    }

    int DeactiveMob(List<GameObject> mobs)
    {
        List<int> num = new List<int>();
        for (int i = 0; i < mobs.Count; i++)
        {
            if (!mobs[i].activeSelf)
                num.Add(i);
        }

        int x = 0;
        if (num.Count > 0)
            x = num[Random.Range(0, num.Count)];
        
        return x;
    }

이렇게 하면 끝!

결과

총 소요시간 : 하루 ..? 영상 따라한 것 치고 오래걸렸다 ㅠ.ㅠ

배운 것

  • 애니메이션
  • delegate
  • 싱글톤
  • 그라운드 스크롤링 구현 > 요건 다시 해봐야겠다

추후 할 것

  • 이제 이미지 바꾸고
  • 사운드 추가
  • 글씨체
  • UI

바꿔서 크롬 공룡 게임 모작해봐야딩~

0개의 댓글