2D 콘텐츠 제작

팀 프로젝트 골드메탈 슈팅게임 [#2]

송현호 2023. 10. 16. 13:34

이번엔 팀원과 회의해서 나는 오브젝트풀링을 담당하고 나머지 팀원들 (1명 늘었다)는 보스 공격패턴과 아이템을 담당하기로 하였다. 먼저 풀링을 하기 전에 씬전환을 먼저 만들어주기로 했다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Chaosmoney8
{
    public class AppMain : MonoBehaviour
    {
        private void Awake()
        {
            DontDestroyOnLoad(this.gameObject);
        }
        private void Start()
        {
            AsyncOperation oper = SceneManager.LoadSceneAsync("LogoScene");
            oper.completed += OnLoadCompleteLogoScene;
        }

        private void OnLoadCompleteLogoScene(AsyncOperation obj)
        {
            LogoMain logoMain = GameObject.FindObjectOfType<LogoMain>();
            AsyncOperation oper = SceneManager.LoadSceneAsync("TitleScene");
            oper.completed += OnLoadCompleteTitleScene;
            
        }

        private void OnLoadCompleteTitleScene(AsyncOperation obj)
        {
            TitleMain titleMain = GameObject.FindObjectOfType<TitleMain>();
            titleMain.onChangeScene = () =>
            {
                AsyncOperation oper = SceneManager.LoadSceneAsync("GameScene");
            };
        }
    }
}

 

App -> Logo -> Title -> Game <-> GameEnd순으로 씬이 전개되고 로고 부분에서 풀링을 리스트에 넣은 뒤 게임신에서 사용할 예정이다. 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Chaosmoney8
{
    public class LogoMain : MonoBehaviour
    {
        [SerializeField]
        private GameObject bullet;
        [SerializeField]
        private GameObject bullet2;
        [SerializeField]
        private GameObject enemyA;
        [SerializeField]
        private GameObject enemyB;
        [SerializeField]
        private GameObject enemyC;
        [SerializeField]
        private GameObject boom;
        [SerializeField]
        private GameObject coin;
        [SerializeField]
        private GameObject power;

        private List<GameObject> bulletList = new List<GameObject>();
        private List<GameObject> bullet2List = new List<GameObject>();
        private List<GameObject> enemyAList = new List<GameObject>();
        private List<GameObject> enemyBList = new List<GameObject>();
        private List<GameObject> enemyCList = new List<GameObject>();
        private List<GameObject> boomList = new List<GameObject>();
        private List<GameObject> coinList = new List<GameObject>();
        private List<GameObject> powerList = new List<GameObject>();
        private List<GameObject> targetList = new List<GameObject>();
        // Start is called before the first frame update
        private void Awake()
        {
            DontDestroyOnLoad(this.gameObject);
        }
        void Start()
        {
            for(int i = 0;  i < 20; i++)
            {
                var go = Instantiate(bullet);
                go.SetActive(false);
                DontDestroyOnLoad(go);
                bulletList.Add(go);
            };
            for (int i = 0; i < 20; i++)
            {
                var go = Instantiate(bullet2);
                go.SetActive(false);
                DontDestroyOnLoad(go);
                bullet2List.Add(go);
            };
            for (int i = 0; i < 10; i++)
            {
                var go = Instantiate(enemyA);
                go.SetActive(false);
                DontDestroyOnLoad(go);
                enemyAList.Add(go);
            };
            for (int i = 0; i < 10; i++)
            {
                var go = Instantiate(enemyB);
                go.SetActive(false);
                DontDestroyOnLoad(go);
                enemyBList.Add(go);
            };
            for (int i = 0; i < 10; i++)
            {
                var go = Instantiate(enemyC);
                go.SetActive(false);
                DontDestroyOnLoad(go);
                enemyCList.Add(go);
            };
            for (int i = 0; i < 5; i++)
            {
                var go = Instantiate(boom);
                go.SetActive(false);
                DontDestroyOnLoad(go);
                boomList.Add(go);
            };
            for (int i = 0; i < 5; i++)
            {
                var go = Instantiate(coin);
                go.SetActive(false);
                DontDestroyOnLoad(go);
                coinList.Add(go);
            };
            for (int i = 0; i < 5; i++)
            {
                var go = Instantiate(power);
                go.SetActive(false);
                DontDestroyOnLoad(go);
                powerList.Add(go);
            };
        }
        public List<GameObject> GetTargetPool(string name)
        {
            switch (name)
            {
                case "bullet":
                    targetList = bulletList;
                    break;
                case "bullet2":
                    targetList = bullet2List;
                    break;
                case "enemyA":
                    targetList = enemyAList;
                    break;
                case "enemyB":
                    targetList = enemyBList;
                    break;
                case "enemyC":
                    targetList = enemyCList;
                    break;
                case "boom":
                    targetList = boomList;
                    break;
                case "coin":
                    targetList = bulletList;
                    break;
                case "power":
                    targetList = bulletList;
                    break;
            }
            return targetList;
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Chaosmoney8
{
    public class TestGameManager : MonoBehaviour
    {
        /*
     -아이템 생성하는 매니저

    -적기를 생성하는 매니저

    -오브젝트 풀링 매니저 
        
     */
        [SerializeField]
        private Enemy[] enemes;
        [SerializeField]
        private GameObject[] items;
        [SerializeField]
        private GameObject explosion;

        private LogoMain objectPool;
        // Start is called before the first frame update
        void Start()
        {
            objectPool = GameObject.FindObjectOfType<LogoMain>();
            // 게임 매니저로 Die 대리자 호출
            foreach (var enemy in enemes)
            {
                enemy.Die = () =>
                {
                    StartCoroutine(CoExplosion(enemy.gameObject.transform.position));
                    StartCoroutine(CoDropItem(enemy.gameObject.transform.position));
                    Destroy(enemy.gameObject);
                };
            }
            StartCoroutine(CoCreateEnemyA());
            StartCoroutine(CoCreateEnemyB());
            StartCoroutine(CoCreateEnemyC());
        }
        // 게임 매니저에서 적 삭제, 폭발 이펙트 생성
        private IEnumerator CoDropItem(Vector3 position)
        {
            yield return new WaitForSeconds(0.6f);
            int i = Random.Range(0, items.Length);
            GameObject coItem = Instantiate(this.items[i]);
            coItem.transform.position = position;
        }
        private IEnumerator CoExplosion(Vector3 position)
        {
            GameObject coExplosion = Instantiate(this.explosion);
            coExplosion.transform.position = position;
            yield return new WaitForSeconds(1f);
            Destroy(coExplosion);
        }

        private IEnumerator CoCreateEnemyA()
        {
            while(true)
            {
                
                //적기의 리스트 가져옴
                var listA = objectPool.GetTargetPool("enemyA");
                //적기가 비활성화 상태이면 활성화
                

                if(Time.time >= 0 && Time.time <15)
                {
                    foreach (var enemy in listA)
                    {
                        if (enemy.activeSelf == false)
                        {
                            enemy.SetActive(true);
                            enemy.transform.position = new Vector3(Random.Range(-2.6f, 2.6f), 8, this.transform.position.z);
                            yield return new WaitForSeconds(2f);
                        }
                    }
                }
                yield return null;
            }
        }
        private IEnumerator CoCreateEnemyB()
        {
            while (true)
            {

                //적기의 리스트 가져옴
                var listB = objectPool.GetTargetPool("enemyB");
                //적기가 비활성화 상태이면 활성화


                if (Time.time >= 15 && Time.time < 30)
                {
                    foreach (var enemy in listB)
                    {
                        if (enemy.activeSelf == false)
                        {
                            enemy.SetActive(true);
                            enemy.transform.position = new Vector3(Random.Range(-2.6f, 2.6f), 8, this.transform.position.z);
                            yield return new WaitForSeconds(2f);
                        }
                    }
                }

                yield return null;
            }
        }
        private IEnumerator CoCreateEnemyC()
        {
            while (true)
            {

                //적기의 리스트 가져옴
                var listC = objectPool.GetTargetPool("enemyC");
                //적기가 비활성화 상태이면 활성화


                if (Time.time >= 30 )
                {
                    foreach (var enemy in listC)
                    {
                        if (enemy.activeSelf == false)
                        {
                            enemy.SetActive(true);
                            enemy.transform.position = new Vector3(Random.Range(-2.6f, 2.6f), 8, this.transform.position.z);
                            yield return new WaitForSeconds(2f);
                        }
                    }
                }

                yield return null;
            }
        }

    }
}

이 과정에서 GetTargetPool메서드를 사용해 리스트를 가져오는데 리스트가 Null로 호출됐다. Null로 떴다면 경험상 호출 순서문제일 것 같아서 확인해봤는데 예상대로 objectPool = GameObject.FindObjectOfType<LogoMain>();를 적기 생성보다 늦게 실행해서 발생한 문제였다.

 

풀링을 끝내고 나선 합치는 작업에 들어갔는데 생각보다 합치는데 문제가 발생해서 작업이 더뎠다 그래서 스크립트를 먼저 정리한 뒤 서로 작업한걸 합치기로 했다.

 

using Chaosmoney8;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

namespace sum
{
    public class GameManager : MonoBehaviour
    {
        [SerializeField]
        private Enemy[] enemes;
        [SerializeField] 
        private BossController boss;
        [SerializeField]
        private GameObject[] items;
        [SerializeField]
        private GameObject explosion;
        [SerializeField]
        private Player player;
        [SerializeField]
        private TMP_Text scoreText;
        [SerializeField]
        private int score = 0;

        public System.Action PowerUp;
        private LogoMain objectPool;
        // Start is called before the first frame update
        void Start()
        {
            objectPool = GameObject.FindObjectOfType<LogoMain>();
            var listA = objectPool.GetTargetPool("enemyA");
            var listB = objectPool.GetTargetPool("enemyB");
            var listC = objectPool.GetTargetPool("enemyC");

            // 게임 매니저로 Die 대리자 호출
            foreach (var enemy in enemes)
            {
                enemy.Die = () =>
                {
                    StartCoroutine(CoExplosion(enemy.gameObject.transform.position));
                    StartCoroutine(CoDropItem(enemy.gameObject.transform.position));
                    // 점수 증가
                    this.score = score + 10;
                    Destroy(enemy.gameObject);
                };
                player.GetItem = (name) =>
                {
                    if (name == "Coin(Clone)")
                    {
                        // 코인 증가
                        Debug.Log("coin");
                    }
                    else if (name == "Boom(Clone)")
                    {
                        // 폭탄
                        Debug.Log("boom");
                    }
                    else if (name == "Power(Clone)")
                    {
                        // 파워 증가
                        this.PowerUp();
                        Debug.Log("power");
                    }
                };
            }
            StartCoroutine(CoCreateEnemyA());
            StartCoroutine(CoCreateEnemyB());
            StartCoroutine(CoCreateEnemyC());
            StartCoroutine(CoCreateBoss());
        }
        // 게임 매니저에서 적 삭제, 폭발 이펙트 생성
        private IEnumerator CoDropItem(Vector3 position)
        {
            yield return new WaitForSeconds(0.6f);
            int i = Random.Range(0, items.Length);
            GameObject coItem = Instantiate(this.items[i]);
            coItem.transform.position = position;
        }
        private IEnumerator CoExplosion(Vector3 position)
        {
            GameObject coExplosion = Instantiate(this.explosion);
            coExplosion.transform.position = position;
            yield return new WaitForSeconds(1f);
            Destroy(coExplosion);
        }

        private IEnumerator CoCreateEnemyA()
        {
            var listA = objectPool.GetTargetPool("enemyA");
            while (true)
            {
                //적기가 비활성화 상태이면 활성화


                foreach (var enemy in listA)
                {

                    if (enemy.activeSelf == false)
                    {
                        enemy.SetActive(true);
                        enemy.transform.position = new Vector3(Random.Range(-2.6f, 2.6f), 8, this.transform.position.z);
                        var ene = enemy.GetComponent<Enemy>();
                        ene.Init(1);
                        ene.Die = () =>
                        {
                            StartCoroutine(CoExplosion(enemy.gameObject.transform.position));
                            StartCoroutine(CoDropItem(enemy.gameObject.transform.position));
                            // 점수 증가
                            this.score = score + 10;
                            this.scoreText.text = score.ToString();
                            ene.gameObject.SetActive(false);
                        };
                        yield return new WaitForSeconds(2f);
                    }
                }
                yield return null;
            }
        }
        private IEnumerator CoCreateEnemyB()
        {
            var listB = objectPool.GetTargetPool("enemyB");
            while (true)
            {
                //적기가 비활성화 상태이면 활성화


                if (Time.time >= 15)
                {
                    foreach (var enemy in listB)
                    {
                        if (enemy.activeSelf == false)
                        {

                            enemy.SetActive(true);
                            enemy.transform.position = new Vector3(Random.Range(-2.6f, 2.6f), 8, this.transform.position.z);
                            var ene = enemy.GetComponent<Enemy>();
                            ene.Init(2);
                            ene.Die = () =>
                            {
                                StartCoroutine(CoExplosion(enemy.gameObject.transform.position));
                                StartCoroutine(CoDropItem(enemy.gameObject.transform.position));
                                // 점수 증가
                                this.score = score + 20;
                                this.scoreText.text = score.ToString();
                                ene.gameObject.SetActive(false);
                            };
                            yield return new WaitForSeconds(3f);
                        }
                    }
                }

                yield return null;
            }
        }
        private IEnumerator CoCreateEnemyC()
        {
            var listC = objectPool.GetTargetPool("enemyC");
            while (true)
            {
                //적기가 비활성화 상태이면 활성화


                if (Time.time >= 30)
                {
                    foreach (var enemy in listC)
                    {
                        if (enemy.activeSelf == false)
                        {
                            enemy.SetActive(true);
                            enemy.transform.position = new Vector3(Random.Range(-2.6f, 2.6f), 8, this.transform.position.z);
                            var ene = enemy.GetComponent<Enemy>();
                            ene.Init(3);
                            ene.Die = () =>
                            {
                                StartCoroutine(CoExplosion(enemy.gameObject.transform.position));
                                StartCoroutine(CoDropItem(enemy.gameObject.transform.position));
                                // 점수 증가
                                this.score = score + 30;
                                this.scoreText.text = score.ToString();
                                ene.gameObject.SetActive(false);
                            };
                            yield return new WaitForSeconds(5f);
                        }
                    }
                }

                yield return null;
            }
        }

        private IEnumerator CoCreateBoss()
        {
            yield return new WaitForSeconds(15f);
            var go = Instantiate(boss);
            go.transform.position = new Vector3(0, 8, this.transform.position.z);
            var ene = go.GetComponent<Enemy>();
            ene.Die = () =>
            {
                StartCoroutine(CoExplosion(ene.gameObject.transform.position));
                StartCoroutine(CoDropItem(ene.gameObject.transform.position));
                // 점수 증가
                this.score = score + 1000;
                this.scoreText.text = score.ToString();
                Destroy(ene.gameObject);
            };
        }
    }
}

 

시간이 지날수록 더 강한 적기가 나오도록 설정하였고 팀원이 작업한 보스를 45초 뒤에 생성하도록 설정하였다.

그리고 점수표시를 추가해서 적기를 잡을때마다 점수가 오르도록 만들었다.