Level Selector Scene에서 레벨 1을 클리어해야 레벨 2이 언락되고 레벨 2를 클리어해야 레벨 3이 해금되도록 레벨 해금 기능을 구현해보자.
public Button[] levelButtons;
public void Start()
{
for (int i = 0; i < levelButtons.Length; i++)
{
levelButtons[i].interactable = false; //시작하면 일단 모든 버튼은 상호작용 불가 (클릭안됨)
}
}
위와 같이 버튼을 초기화해놓고 인스펙터에서 레벨 버튼들을 배열에 추가해준다.
이제 버튼이 interactable 상태일 때 다른 버튼의 모양을 가지도록 애니메이션을 수정한다. Button 애니메이션 컨트롤러에서 Disabled 애니메이션을 수정한다.
이 때 까먹지말고 Normal에서 줄여놓은 alpha 값을 다시 원상복귀 시키는 애니메이션을 추가한다.
실행해보면 모든 버튼이 Disabled에서 조정한 애니메이션 효과를 적용받아 투명해지고 클릭이 안되는 상태로 변한 것을 확인할 수 있다.
현재 진행가능한 레벨까지 버튼을 사용가능하도록 활성화 시키도록 한다.
public void Start()
{
int levelReached = PlayerPrefs.GetInt("levelReached", 1); //값이 있으면 levelReached 가져오기, 없으면 1을 가져오기
for (int i = 0; i < levelButtons.Length; i++)
{
if ( i + 1 > levelReached )
levelButtons[i].interactable = false; //시작하면 일단 모든 버튼은 상호작용 불가 (클릭안됨)
}
}
위와 같이 버튼을 비활성화 해주면 기존에 도달했던 레벨까지는 버튼이 비활성화되지 않고 그 위 레벨의 버튼든만 비활성화된다. PlayerPrefs에 levelReached가 없으면 가져오는 값이 레벨 1이므로 실행 시에 레벨 1 버튼만 활성화 되어있는 것을 확인할 수 있다.
WaveSpawner에서 waves.Length 만큼 wave를 모두 진행했다면 레벨이 클리어 된 것이고 더 높은 레벨을 진행할 수 있도록 LevelReached를 업데이트하도록 구현한다.
IEnumerator SpawnWave() //코루틴
{
PlayerStats.Rounds++;
Wave wave = waves[waveIndex];
for (int i = 0; i < wave.count; i++) //웨이브 레벨만큼 몬스터 소한
{
SpawnEnemy(wave.enemy);
yield return new WaitForSeconds(1f / wave.rate);
}
waveIndex++;//웨이브가 올때마다 레벨업
if (waveIndex == waves.Length)
{
gameManager.WinLevel(); //레벨 클리어
this.enabled = false; //WaveSpawner 스크립트를 비활성화
}
}
public string nextLevel = "Level02";
public int levelToUnrock = 2;
public SceneFader sceneFader;
public void WinLevel()
{
Debug.Log("LEVEL WON!");
PlayerPrefs.SetInt("levelReached", levelToUnrock);
sceneFader.FadeTo(nextLevel);
}
인스펙터에서 SceneFader를 초기화해준다.
위 코드를 설명하면 WaveSpawner에서 모든 Wave를 클리어하면 WinLevel 함수가 실행되고, 해당 함수에서는 Log를 한 번 출력하고 levelReached 값을 정해둔 levelToUnrock으로 설정해주고 다음 레벨 Scene으로 FadeTo로 넘어가는 함수이다.
추가적으로 Level03 장면을 복사해서 붙여넣고 Level02의 GameManager를 다음과 같이 수정하면 Level02 클리어 시에도 Level03을 진행할 수 있다.
각 장면마다 WaveSpanwer에 GameManager를 연결시켜주어야한다.
기존에는 Enemy가 생성되면 EnemiesAlive Enemy 오브젝트를 죽이면 EnemiesAlive가 감소되고 0이면 다음 웨이브로 넘어가는식으로 구현했는데 이 때 웨이브가 시작할 때 Enemy를 instantiate하기 전에 EnemisAlive의 0을 인식해버리는 문제가 있는데 해당 문제를 다음과 같이 수정해서 고친다.
IEnumerator SpawnWave() //코루틴
{
PlayerStats.Rounds++;
Wave wave = waves[waveIndex];
EnemiesAlive = wave.count;
for (int i = 0; i < wave.count; i++) //웨이브 레벨만큼 몬스터 소한
{
SpawnEnemy(wave.enemy);
yield return new WaitForSeconds(1f / wave.rate);
}
waveIndex++;//웨이브가 올때마다 레벨업
if (waveIndex == waves.Length)
{
gameManager.WinLevel(); //레벨 클리어
this.enabled = false; //WaveSpawner 스크립트를 비활성화
}
}
void SpawnEnemy(GameObject enemy)
{
//미리 지정해둔 스폰 포인트에서 몬스터를 복사해서 소환
Instantiate(enemy, spawnPoint.position, spawnPoint.rotation);
}
위와 같이 Enemy를 스폰하기 전에 EnemiesAlive를 그냥 wave의 count 값으로 설정해버리는 방식으로 수정해서 오류를 픽스할 수 있다.