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초 뒤에 생성하도록 설정하였다.
그리고 점수표시를 추가해서 적기를 잡을때마다 점수가 오르도록 만들었다.