Carrot
본문 바로가기
Unity/멋쟁이사자처럼 부트캠프

[멋쟁이사자처럼부트캠프] 유니티 게임 개발 5기(30일차) - 2D 플랫포머 게임 (5)

by 독기품은토끼 2025. 6. 27.
✅ 오늘의 학습 목표
1. Sound 적용
2. 설정창 만들기
3. 포탈 만들기 - 씬 전환까지
4. Rule 타일 맛보기

 

1. Sound

배경음악이나 문을 열 때나 등 사운드 효과를 넣어주려고 한다.

🥕 예행 작업
1. Assets 다운로드
 

LUShvalleySound: Fantasy BGM – Free Pack Vol.01 | 음향 음악 | Unity Asset Store

Layer in the sounds of LUShvalleySound: Fantasy BGM – Free Pack Vol.01 from LUShvalleySound for your next project. Browse all audio options on the Unity Asset Store.

assetstore.unity.com

 

8-Bit RPG Adventure Music Pack | 전자음 음악 | Unity Asset Store

Layer in the sounds of 8-Bit RPG Adventure Music Pack from Chris Kohler for your next project. Browse all audio options on the Unity Asset Store.

assetstore.unity.com

 

8 Bit RPG Adventure and Fantasy Music Pack || Pixel Adventures Vol. 1 | 음향 음악 | Unity Asset Store

Layer in the sounds of 8 Bit RPG Adventure and Fantasy Music Pack || Pixel Adventures Vol. 1 from domi.wav for your next project. Browse all audio options on the Unity Asset Store.

assetstore.unity.com

 

Door, Cabinets & Lockers (Free) | 기타 효과음 효과음 | Unity Asset Store

Layer in the sounds of Door, Cabinets & Lockers (Free) from Syntoca for your next project. Browse all audio options on the Unity Asset Store.

assetstore.unity.com

using UnityEngine;

public class SoundController : MonoBehaviour
{
    [SerializeField] private AudioSource bgmAudio;
    [SerializeField] private AudioSource eventAudio;

    [SerializeField] private AudioClip[] clips;

    // 음악
    public void BgmSoundPlay(string clipName)
    {
        foreach (var clip in clips)
        {
            if (clip.name == clipName)
            {
                bgmAudio.clip = clip;
                bgmAudio.Play();
                return; // 메서드 종료
            }
        }
        Debug.Log($"{clipName} 파일을 찾지 못하였습니다.");
    }

    // 효과음
    public void EventSoundPlay(string clipName)
    {
        foreach (var clip in clips)
        {
            if (clip.name == clipName)
            {
                // PlayOneShot은 한번 실행되면 제어 불가능
                eventAudio.PlayOneShot(clip);
                return; // 메서드 종료
            }
        }
        Debug.Log($"{clipName} 파일을 찾지 못하였습니다.");
    }
}

 

오디오 소스 하나로 배경음악이랑 효과음 둘 다 재생하려고 각각 따로 메서드를 만들어 주었고,
AudioClip[] 배열에 필요한 소리들을 넣어두고 이름으로 찾아서 재생하게끔 하였다.
배경음악은 Play()로, 효과음은 PlayOneShot()으로 실행하게 구현하였는데 PlayOneShot의 경우 한번 실행되면 정지나 재생같은 제어 기능을 사용할 수 없다.
(참고로 AudioListener는 카메라에 자동으로 들어가 있으니 따로 신경 안 써도 된다)

 

 

코드를 다 작성하였으면 이제 오디오 클립들을 넣어주면 되는데 이때 플레이 시 음악이 자동으로 시작되지 않도록 Play On Awake를 체크 해제해준다.

 

// 배경 음악
public class SoundController : MonoBehaviour
{
    void Start()
    {
        BgmSoundPlay("Town BGM");
    }
}

// 효과음
public class InteractionEvent : MonoBehaviour
{
    public SoundController soundController;
    
    IEnumerator DoorRoutine(Transform player)
    {
        soundController.EventSoundPlay("Door Open");

        yield return StartCoroutine(fade.Fade(3f, Color.black, true));

        map.SetActive(isHouse);
        house.SetActive(!isHouse);

        var pos = isHouse ? outDoorPos : inDoorPos;
        player.transform.position = pos;

        isHouse = !isHouse;

        soundController.EventSoundPlay("Door Close");

        yield return new WaitForSeconds(1f);
        yield return StartCoroutine(fade.Fade(3f, Color.black, false));
    }
}

 

배경 음악은 게임 시작할 때 바로 재생되면 되니까  
SoundController 스크립트의 Start()에서 BgmSoundPlay("Town BGM")을 실행해주었고,
반면 문을 여닫는 연출에는 효과음이 들어가야 하니까,  
Door 이벤트를 처리하는 InteractionEvent 스크립트 안에서 EventSoundPlay("Door Open/Close")를 호출해주었다.

 

2. Settings

이번에는 게임 설정 창을 만들어주려고 한다.

 

 

원하는 위치에 설정 아이콘을 만들어 주고

 

 

설정 창을 만들어주었다.

 

 

설정 창 안에 있는 슬라이더나 토글은 UI를 통해서 만들 수 있다.

설정 창을 끄는 기능도 필요하니 우측 상단에 버튼도 만들어주었다.

 

 

이제 설정창을 열고 닫는 이벤트를 처리해주어야 하는데 별도로 스크립트를 만들진 않고 Unity에서 기본으로 제공하는 Button 컴포넌트의 On Click() 이벤트를 활용해서 처리했다.

[Button] Settings 버튼에는 Setting Popup 오브젝트를 SetActive(true)로 설정해서 설정창이 열리도록 했고,
[Button] Close 버튼에는 SetActive(false)로 설정해서 닫히도록 만들었다.

 

 

설정 창에 사운드 관련 UI도 추가했으니 이제 실제로 사운드가 조절되도록 연동해주어야 한다.
Unity에서는 Slider의 value, Toggle의 isOn 같은 값으로 볼륨과 음소거 여부를 바로 제어할 수 있다.
Slider와 Toggle 컴포넌트에는 값이 바뀔 때 자동으로 호출되는 OnValueChanged 이벤트도 기본으로 있어서
별도 로직 없이 메서드만 연결해 주면 바로 적용되도록 만들 수 있다.

 

using UnityEngine.UI;

public class SoundController : MonoBehaviour
{
    [SerializeField] private Slider bgmVolume;
    [SerializeField] private Toggle bgmMute;

    [SerializeField] private Slider eventVolume;
    [SerializeField] private Toggle eventMute;

    void Awake()
    {
        bgmVolume.value = bgmAudio.volume;
        eventVolume.value = eventAudio.volume;

        bgmMute.isOn = bgmAudio.mute;
        eventMute.isOn = bgmAudio.mute;
    }

    void Start()
    {
        BgmSoundPlay("Town BGM");

        bgmVolume.onValueChanged.AddListener(OnBgmVolumeChanged);
        eventVolume.onValueChanged.AddListener(OnEventVolumeChanged);

        bgmMute.onValueChanged.AddListener(OnBgmMute);
        eventMute.onValueChanged.AddListener(OnEventMute);
    }

    public void OnBgmVolumeChanged(float volume)
    {
        bgmAudio.volume = volume;
    }
    
    public void OnEventVolumeChanged(float volume)
    {
        eventAudio.volume = volume;
    }
    
    public void OnBgmMute(bool isMute)
    {
        bgmAudio.mute = isMute;
    }

    public void OnEventMute(bool isMute)
    {
        eventAudio.mute = isMute;
    }
}

 

그래서 Start()에서는 각 UI 요소에 이벤트를 등록하였고,
Awake()에서는 처음 시작할 때 오디오 상태와 UI 상태를 동기화해 주기 위해 슬라이더의 value와 토글의 isOn 값을 코드로 초기화해 주었다.

지금은 코드가 좀 긴 감이 있는데 나중에 람다나 조건문 활용해서 적어주면 많이 간략해질 수 있을 것 같다.

 

동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.

 

 

3. 포탈

🥕 예행 작업
1. Script 생성 (PortalController)
2. Asset 다운로드
 

Free Quick Effects Vol. 1 | 시각 효과 파티클 | Unity Asset Store

Add depth to your next project with Free Quick Effects Vol. 1 from Gabriel Aguiar Prod. Find this & more 시각 효과 파티클 on the Unity Asset Store.

assetstore.unity.com

에셋을 다운로드 받으면 패키지 형태로 저장될 텐데 URP 패키지를 더블 클릭해서 Import 해주면 된다.

 

1. 포탈 효과

 

포탈&포탈 효과 프리팹을 갖고 와서 Layer 위치를 설정해 주고 콜라이더와 스크립트까지 다  추가해 주었다.

 

using System.Collections;
using UnityEngine;

public class PortalController : MonoBehaviour
{
    public PlatformFade fade;
    public GameObject portalEffect;

    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            StartCoroutine(PortalRoutine());
        }
    }

    IEnumerator PortalRoutine()
    {
        portalEffect.SetActive(true);

        // Fade 코루틴이 끝날 때 까지 대기
        yield return StartCoroutine(fade.Fade(3f, Color.white, true));
    }
}

 

 

2. 씬 전환

2.1. 로딩 화면 구현

씬이 전환될 때 로딩 화면을 중간에 넣어보려고 한다.

 

Sprite 타입의 이미지를 만들어주고

이미지 타입을 Filled로 설정한 다음 아래 설정들을 추가해 준다.

  • Fill Method: Horizontal (좌 → 우 진행형이라)
  • Fill Origin: Left (왼쪽에서 차오르게 하려고)
  • Fill Amount : 0 (0부터 1까지 차올라야 하니까)

 

public class PortalController : MonoBehaviour
{
    public GameObject loadingImage;
    public Image progressBar;

    IEnumerator PortalRoutine()
    {
        loadingImage.SetActive(true);
        yield return StartCoroutine(fade.Fade(3f, Color.white, false));

        while (progressBar.fillAmount < 1f) // 로딩 페이크
        {
            progressBar.fillAmount += Time.deltaTime * 0.3f;
            yield return null;
        }
    }
}

 

Image에 있는 FillAmount 값을 활용해서 게이지가 차는 듯한 연출을 주었다.

정말 로딩되는 건 아니고.. 페이크다.. ㅎ0ㅎ

 

주의해야 할 점은 레이어의 영향을 받으니 로딩 오브젝트가 Fade 오브젝트보다 상단에 있어야 제대로 동작된다.

 

 

 

2.2. 씬 전환

이제 다른 씬으로 전환되는 것을 구현해 보겠다.

 

 

예전에 Cat 게임 빌드할 때 한번 건드려보았던 빌드 프로필을 열어준다.

기존 Cat 씬은 지워주고 이번에 사용할 Town 씬과 Adventure 씬을 드래그 앤 드롭해준다.

이때 우측에 표시되는 숫자가 바로 씬의 인덱스 번호인데 이 번호를 이용해서 씬을 불러올 수 있다.

 

using UnityEngine.SceneManagement;

public class PortalController : MonoBehaviour
{
    IEnumerator PortalRoutine()
    {
        SceneManager.LoadScene(1);
    }
}

 

씬 매니저를 사용해서 LoadScene(1)을 통해 Adventure 씬으로 이동할 수 있게 된다.

 

 

 

4. Rule Tile

Rule Tile은 주변 타일의 배치 패턴에 따라 자동으로 타일 스프라이트를 바꿔주는 스마트한 타일맵이라고 생각하면 된다.

오늘은 룰 타일을 정말 깔짝! 한 5분? 해봤고 다음주 월요일에 제대로 구현한다 하셨으니 이 부분은 그냥 스샷만 남긴다..

 

 

스프라이트 이미지 타입의 이미지를 넣고

규칙에 맞게 패턴을 적용시켜 주면 아래와 같이 타일이 그려진다.

 

 

 


 

 

옛날에 씬 변환 구현할 때 직접 씬 매니저라는 스크립트 만들어서 노가다 작업 해줬던 기억이 있는데..

이게 버전이 업데이트되면서 좋아진 건지 아님 그냥 내가 그때 트롤이었던 건지.. 아마 후자일 텐데 진짜 씬 전환이 엄청 간단했구나ㅜㅜ

점점 쉬운 방법을 터득할 때마다 왁! 에바다!를 외치는 중.. 이래서 이래서.. 맨땅 헤딩보다는 역시 강의를 들어야해..~