Unity - Week 09

이응민·2025년 2월 2일

Unity

목록 보기
9/12

종스크롤 2D 슈팅 게임 만들기(5)

이번에는 옵션창에서 오디오 크기를 조절하는 것을 구현한다.


위 그림은 AudioListener에 AudioSource가 들어오는 방식이다. AudioSource를 AudioMixer로 더하고 AudioMixer들의 소리가 AudioListener로 들린다.

위 사진이 AudioMixer의 사진이다. MasterMixer 아래에 그룹으로 BGM(배경음악)과 SFX(효과음)이 들어가있다. 그리고 exposed parameter를 설정해서 외부에서 접근할 이름을 설정해준다. 이 Parameter를 이용해서 스크립트에서 해당 이름에 해당하는 Mixer에 접근할 수 있다.

그리고 소리가 나오는 오브젝트에서 AudioSource 컴포넌트를 넣고 AudioClip과 OutPut으로 원하는 Mixer를 선택해서 넣어준다. 그리고 LobbyScene에서 UI와 오디오를 제어하기 위해 LobbySceneManager 스크립트를 만들어서 오브젝트에 넣는다.

public void ChangeVolume(TextMeshProUGUI text,Slider slider, SAVE_Type type, float newVolume)
{
    text.text = (newVolume * 100.0f).ToString("0");
    slider.value = newVolume;
    valueF = newVolume * 30.0f - 30.0f;
    audioMaster.SetFloat(type.ToString(), valueF);
}
public void SFX_ValueChange(float value)
{
    PlayerPrefs.SetFloat(SAVE_Type.SAVE_SFX.ToString(), value);
    ChangeVolume(sfxText, sfxSlider, SAVE_Type.SAVE_SFX, value);
}
public void BGM_ValueChange(float value)
{
    PlayerPrefs.SetFloat(SAVE_Type.SAVE_BGM.ToString(), value);
    ChangeVolume(bgmText, bgmSlider, SAVE_Type.SAVE_BGM, value);
}

위 코드를 통해서 slider로 소리를 변경할 수 있게 했다. 그리고 InitLobbyScene에서 초기화를 한다. 그리고 slider의 이벤트를 설정할 때는 dynamic에 있는 함수로 설정해야한다. static 값을 받는 함수를 지정하면 값을 변경할 수 없다.

그리고 오디오 소스를 10개를 만들었는데 11개의 오디오를 만들어버리면 소리를 꺼버리고 새로 재생한다. 오디오 소스를 미리 몇개 만들어놓고 소스 안에 값만 바꿔줘서 소리를 출력할 수 있다.

위 사진은 BattleScene의 SoundManager이다. SoundManager는 싱글턴으로 만들어졌다. 미리 10개의 SFXPlayer를 만들어놓고 사운드가 필요할때마다 SFX List에 있는 소리를 꺼내서 사용한다.

SoundManager에서는 먼저 Inspector창에서 오디오 소스와 오디오 클립을 지정해준다. ChangeBGMClip 코루틴에서 BGM을 다루는데 BGM에서 재생되고 있는 오디오는 점점 작아지고 새롭게 재생될 오디오의 소리는 점점 커지게 설저해서 소리가 점점 작아졌다가 커지면서 새롭게 시작되도록 한다. PlaySFX 함수에서는 sfxPlayer 배열을 만들어서 거기서 소리가 재생되면 하나씩 오디오 소스를 채워나간다. 그리고 PlayerWeapon에서 SoundManager.Instance.PlaySFX(SFX_Type.SFX_Fire)로 투사체를 발사할 때마다 소리가 출력되도록 하고 Enemy에서 몬스터가 사망할 때마다 SoundManager.Instance.PlaySFX(SFX_Type.SFX_Explosion)로 소리가 출력되도록 한다.

위 그림은 스킬을 찍을 수 있는 제련소(Enchant) 팝업창이다. 스크롤을 이용해 화면보다 큰 영역의 오브젝트들을 아래로 내려가면서 보려면 UI에서 Scroll View를 생성해야한다. Scroll View는 View Port와 Scrollbar Vertical과 Scrollbar Horizontal이 있는데 Veiw Port는 보이는 영역이고 Scrollbar들은 각각 수직과 수평의 스크롤 바를 의미한다. 그리고 Scroll View의 Scroll Rect 영역에서 Movement Type은 영역을 벗어났을 때 어떻게 처리할 것인지를 의미하는데 unrestricted는 제한이 없이 쭉 내려가는 것이고 Elastic은 탄력적으로 밖으로 벗어났다가 다시 돌아온다. 그리고 Clamped는 영역에 맞춰서 딱 멈춘다. Enchant 팝업에서는 버튼으로 스킬을 찍을 수 있게 만들어 놨다. 그리고 스킬간의 선후관계가 있어서 선행 스킬을 찍어야 다음 스킬을 찍을 수 있도록 만들었다. 스킬 버튼에 대한 처리는 EnchantButton 스크립트로 제어한다. 그리고 Skill버튼에 EnchantButton 스크립트를 넣어둔다.

위 스크립트에서는 선후 관계의 버튼을 Inspector 창에서 지정하도록 설정해주고 업그레이드가 안된다면 잠금 이미지가 있고 업그레이드가 가능하다면 잠금 이미지가 없어지도록 했다. 스크립트의 위에서 enum으로 스킬의 타입과 버튼의 상태를 정의했다.

위 사진은 버튼 중 하나의 Inspector 창이다. 선후관계에 있는 스킬들을 지정해주고 클릭을 하면 스킬에 대한 설명이 나오도록 하는 ToolTip을 지정했다.


ToolTip에서는 현재 Player가 가지고 있는 돈을 받아와서 스킬을 구매가능한지를 나타낸다. 다른 곳을 눌렀을 때 ToolTip 창이 내려가는 것은 Update에서 다른 곳이 마우스로 눌리면 SetActive로 비활성화한다. 그리고 버튼을 누르면 PlayerPrefs에 스킬이름의 값을 1로 바꿔서 배운것으로 처리한다. PlayerWeapon에서 스킬을 적용한다.

public void InitWeapon()
{
    projectilePrefab = projectilePrefabs[0];
    currentType = ProjectileType.PLAYER01;
    numOfProjectiles = 1;

    if (PlayerPrefs.GetInt(SkillType.Skill_PowerUP.ToString()) > 0)
    {
        projectilePrefab = projectilePrefabs[1];
        currentType = ProjectileType.PLAYER02;
    }

    if (PlayerPrefs.GetInt(SkillType.Skill_PowerUP2.ToString()) > 0)
    {
        projectilePrefab = projectilePrefabs[2];
        currentType = ProjectileType.PLAYER03;
    }

    if (PlayerPrefs.GetInt(SkillType.Skill_DoubleShot.ToString()) > 0)
    {
        numOfProjectiles = 3;
    }

    if (PlayerPrefs.GetInt(SkillType.Skill_TripleShoot.ToString()) > 0)
    {
        numOfProjectiles = 5;
    }
}

PlayerPrefs에서 스킬명에 해당하는 값이 1이라면 스킬이 적용된 것으로 판단해서 플레이어의 무기를 바꿔준다.

다음으로는 플레이어가 죽었을때 GameOverPopup이 나오도록 한다. GameOverPopup UI를 제작하고 GameOverPopup 스크립트를 제작해서 GameOverPopup 오브젝트에 넣는다.

플레이어가 사망시 이벤트를 받아서 GameOverPopup이 나오도록 했다. 그리고 LeanTween 클래스를 이용해서 팝업 이미지의 애니메이션을 설정했는데 이것은 유니티 에셋으로 이동과 스케일을 선형적으로 정해서 다이나믹하게 보여지게 할 수 있다. 그리고 setEase를 통해 이전에 curve로 Lerp의 정도를 다르게했던것처럼 빨라졌다가 느려지게하거나 느려졌다가 빨라지게 할 수 도있다. 그리고 SetOnComplete는 해당 움직임 후에 해야될 함수를 호출할 수 있다. 그래서 같은 팝업 창에 있는 이미지들이라도 시간차가 있게 나타날수 있다.

3D 액션 게임 만들기(1)


위 사진은 3D 프로젝트를 들어갔을 때 처음으로 보이는 화면이다. 여기서는 빛이 중요한데 Window->Rendering->Lighting을 통해서 빛을 설정할 수 있다.

위 사진은 그 설정창이다.

https://docs.unity3d.com/kr/2018.4/Manual/GlobalIllumination.html#Environment

위 링크에서 자세하게 볼 수 있다.

먼저 마을 역할을 하는 BaseScene에서 배경을 만들었다. 산으로 둘러싸서 캐릭터가 밖으로 못나가게 만들고 제련소, 잡화상점, 워프를 만들었다. 그리고 에셋을 사용해서 캐릭터 prefab을 불러올 때 캐릭터의 RigPelvis 항목에서 Rig->Gizmo에 각각에 맞는 아이템들이나 모델링들을 지정해줄수 있다. 그리고 캐릭터 prefab에 Animator에 맞는 Animator를 넣어준다.

Character라는 빈 오브젝트를 만들어서 자식 오브젝트에 prefab를 저장해준다. 이렇게 하면 활성화 비활성화를 통해서 여러개의 prefab을 이용해서 캐릭터를 바꿔가면서 게임을 플레이하게 할수 있다. 예를 들어 원신같은 게임이 있다. 그리고 Character 오브젝트에 Character Controller 컴포넌트를 추가한다. 그리고 이 Character Controller 컴포넌트를 통해서 캐릭터의 이동을 구현한다. CharController 스크립트를 만들어서 Character 오브젝트에 넣는다.

위 스크립트에서는 키보드로 Vertical 값과 Horizontal 값을 받아서 moveDelta에 저장하고 카메라 방향을 기준으로 x축으로 이동 z축으로 이동을 구현하기 위해 Camera의 transform.forward갑과 transform.right값을 가져와서 moveDelta와 결합해준다. 그런데 지금 카메라는 아래 그림처럼 약간 기울어져있다.

그래서 Camera의 forward 값을 가져올때 y값을 0으로 해서 가져온다. 그리고 이동 중이라면 이동하는 방향을 바라보도록 rotation을 Quaternion.LookRotation 함수에 인자로 이동 방향을 넣어줘서 이동방향을 향해 회전하도록 설정해주면 이동방향을 보고 움직이게 된다.

transform의 forward, up, right 벡터는 해당 오브젝트의 앞을 보는 방향, 오른쪽 방향, 위쪽방향을 월드 공간 기준으로 반환해준다. 그리고 회전도 포함하고 있다. Chararcter Controller를 통해서 캐릭터의 움직임을 구현한 이유는 Chararcter Controller에는 충돌까지 포함되어있기 때문이다. 그래서 자동으로 건물들과 충돌했을때 통과되지 않고 부딪히게 된다.

0개의 댓글