[Unity][2D-Game] Undead Survivor (13)

suhan0304·2023년 11월 10일
0

유니티 - Undead Survivor

목록 보기
16/21
post-thumbnail
post-custom-banner

Review

  • 레벨업 시스템을 구축했다.
  • 레벨업 시 LevelUp 창이 뜨도록 오브젝트 및 스크립트 구현했다.
    - LevelUp 창이 뜨면 게임 시간이 멈춘다.
    - LevelUp 창의 아이템을 선택하면 다시 재생한다.
  • LevelUp 창에 랜덤된 아이템이 3개 뜨도록 구현했다.
    - 만렙 아이템은 자동으로 음료 아이템으로 변경되도록 로직 구성

강의영상 (13) -


개발

게임 시작

게임 시작 버튼을 만들어서 해당 버튼을 누르면 isLive bool이 true로 바뀌도록 오브젝트와 스크립트를 작성한다.

GameStart라는 빈 오브젝트 생성 후 타이틀을 담당하는 이미지 오브젝트를 추가한다.

  • 이름을 Title로 설정
  • Image를 Title 0으로 설정 후 Set Native Size를 눌러준다.
  • 체인 버튼을 활성화 시켜준 후 스케일을 1.5로 수정한다
  • Shadow 컴포넌트를 추가해준 후 a(투명도)를 90으로 설정
  • Pos Y = 40으로 설정

이제 시작 버튼을 만들기 위해 버튼 오브젝트를 추가해준다.

  • 이름을 Button Start로 설정
  • image를 Panel로 설정
  • Width / Height = 60 / 20 으로 설정
  • Navigation 속성을 None으로 설정
  • Shadow 컴포넌트를 추가
  • Pos Y = -40으로 설정
  • 자식 Text의 글꼴을 neodgm, 사이즈를 10, 흰색, 문구를 "게임 시작"으로 설정
  • 자식 Text 오브젝트에 OutLine 컴포넌트를 0.6 / 0.6 추가

버튼을 누르면 게임 시작 되므로 게임 시작 버튼의 OnClick에 GameStart 오브젝트를 드래그 드랍하고 SetActive 함수를 넣어준다.

추가적으로 HUD라는 빈 오브젝트를 생성한후 Exp, Level, Kill, Timer, Health를 HUD안으로 넣어준 후 HUD를 비활성화 시켜준다. 이제 위와 동일하게 게임 시작 버튼을 누를 시 HUD가 다시 활성화 되도록 동일하게 OnClick > HUD 오브젝트 드래그 드랍 > SetActive 함수 호출

이제 isLive가 true로 바뀌도록 스크립트의 Start를 다음과 같이 수정한다.

GameManager.cs

private void GameStart()
{
    health = maxHealth;
    uiLevelUp.Select(0); //0번째 무기 버튼 Click이벤트 호출
    isLive = true;
}

이제 위와 동일하게 게임 시작 버튼의 OnClick에서 GameManager의 GameStart 함수를 연결시켜준다.


플레이어 피격

이제 플레이어의 피격 판정을 만들어준다.
이 때 자료형 오류가 발생하는데 Player의 health와 maxHealth의 자료형을 float로 변경해주면 오류가 없어진다.

Player.cs

private void OnCollisionStay2D(Collision2D collision)
{
    if (!GameManager.Instance.isLive) //살아있을때만 실행
        return;

    // 프레임마다 이벤트가 실행되기 때문에 DeltaTime을 곱해주어야 한다.
    GameManager.Instance.health -= Time.deltaTime * 10;

    if(GameManager.Instance.health < 0)
    {
        for(int i=2;i<transform.childCount;i++) //자식 오브젝트들을 비활성화
        {
            //Spawner부터 Hand 모두 비활성화
            transform.GetChild(i).gameObject.SetActive(false); 
            //자식의 transform이 반환되므로 다시 gameobject로 올라가서 비활성화
        }

        //죽음 애니메이션 실행
        anim.SetTrigger("Dead");
    }
}

GetChild : 주어진 인덱스의 자식 오브젝트의 트랜스폼을 반환하는 함수


게임 오버

완성된 게임시작 오브젝트를 복사하여 게임결과로 활용한다.

  • Title의 이미지를 title 1로 설정
  • Title 이름을 TitleOver로 설정
  • 버튼을 Button Restart로 설정
  • 버튼 텍스트의 문구를 "돌아가기"로 설정

이제 돌아가기 버튼 이벤트를 스크립트로 구현해보자.

GameManager.cs

using UnityEngine.SceneManagement;

public void GameOver()
{
    StartCoroutine(GameOverRoutine());
}

IEnumerator GameOverRoutine()
{
    isLive = false; //모든 작업 정지

    yield return new WaitForSeconds(0.5f);

    uiResult.SetActive(true);
    Stop();
}

public void GameRetry()
{
    SceneManager.LoadScene(0);//0번째 Scene을 불러온다.
}

SceneManager를 사용하기 위해 SceneManagement 네임스페이스를 추가해주어야 한다.

SecenManager.LoadSene : 이름 혹은 인덱스로 장면(Scene)을 새롭게 부르는 함수

  • File > Build Settings 를 통해 이름과 인덱스를 확인할 수 있다.

이제 GameOver 함수를 플레이어 스크립트의 사망 로직에서 호출해준다.

Player.cs

if(GameManager.Instance.health < 0)
{
    for(int i=2;i<transform.childCount;i++) //자식 오브젝트들을 비활성화
    {
        //Spawner부터 Hand 모두 비활성화
        transform.GetChild(i).gameObject.SetActive(false); 
        //자식의 transform이 반환되므로 다시 gameobject로 올라가서 비활성화
    }

    //죽음 애니메이션 실행
    anim.SetTrigger("Dead");
    GameManager.Instance.GameOver();
}

마지막으로 돌아가기 버튼의 OnClick에 게임 매니저의 Retry 함수 호출을 연결 시켜준다.


게임 승리

시간이 모두 끝나면 몬스터들을 모두 제거해주기 위해 몬스터 정리 전용 빈 오브젝트 EnemyCleaner를 하나 생성한다.

  • Box Collider 2D 컴포넌트를 추가한 후 Size를 x / y = 1000 / 1000으로 설정한다.
  • Box Collider 2D의 is Trigger을 선택해준다.
  • 이후 Bullet 컴포넌트를 추가한후 데미지를 매우 높게 설정해준다.
  • Bullet이기 때문에 Tag를 Bullet으로 변경해준다.
  • 비활성화 시켜준다.

기존 GameResult 오브젝트에서 Title Over을 복사해 Title Victory를 만들어준다.

  • 이미지를 title 1로 설정한다.
  • Set Native Size를 선택한다.

이제 생존 여부에 따라 게임 결과가 바뀌어야 하므로, 게임 결과를 보여주는 스크립트 Result를 새롭게 작성해준 후 GameResult 오브젝트의 컴포넌트로 추가한다.

Result.cs

public class Result : MonoBehaviour
{
    public GameObject[] titles;

    public void Lose()
    {
        titles[0].SetActive(true);
    }

    public void Win()
    {
        titles[1].SetActive(true);
    }
}

이후 게임 매너지에서 기존 uiResult의 변수 타입을 Result로 변경해준다. 그 이후 아래의 uiResult를 uiResult.GameObject로 수정해 추가로 발생되는 오류를 해결한다.

GameManager.cs

IEnumerator GameOverRoutine()
{
    isLive = false; //모든 작업 정지

    yield return new WaitForSeconds(0.5f);

    uiResult.gameObject.SetActive(true);
    uiResult.Lose();
    Stop();
}

위와 같이 수정 후에 스크립트 수정으로 연결이 끊긴 것들을 인스펙터로 다시 연결해준다.

  • GameManager에 uiResult에는 GameResult오브젝트를
  • GameResult의 Titles의 size를 2로 수정후 Element 0에는 Title Over 텍스트를 Element 1에는 Title Victory를 추가해준다.

게임 매니저에 게임 승리 시 적을 정리하는 클리너 변수를 선언해주고 EnemyCleaner 오브젝트를 드래그드랍해서 초기화해준다.

이제 승리 시 로직을 GameManager 스크립트를 아래와 같이 작성해서 구현한다.

GameManager.cs

public void GameStart()
{
    health = maxHealth;
    uiLevelUp.Select(0); //0번째 무기 버튼 Click이벤트 호출
    Resume();
}
public void GameVictory()
{
    StartCoroutine(GameVictoryRoutine());
}

IEnumerator GameVictoryRoutine()
{
    isLive = false; //모든 작업 정지

    enemyCleaner.SetActive(true);
    yield return new WaitForSeconds(0.5f);

    uiResult.gameObject.SetActive(true);
    uiResult.Win();
    Stop();
}
 void Update()
{
    if (!isLive)
        return;

    //DeltaTime : 한 프레임에 걸린 시간
    gameTime += Time.deltaTime;

    //1초마다 Spawn 실행
    if (gameTime > maxGameTime)
    {
        gameTime = maxGameTime;
        GameVictory();
    }
}
public void GetExp()
{
    if (!isLive) // 끝났을때 경험치가 오르는 상황 방지
        return; 
    exp++;

    if(exp == nextExp[Mathf.Min(level, nextExp.Length-1)])
    {
        level++;
        exp = 0;
        uiLevelUp.Show();
    }
}

이제 Title Over와 Title Victory를 비활성화 해준 상태로 GameReulst를 비활성화시킨 후 다시 GameStart를 활성화 시킨다.


결과물

profile
Be Honest, Be Harder, Be Stronger
post-custom-banner

0개의 댓글