카드 만들기 - 애니메이션과 뒤집기(5-1)
5강 목표 - 주변기능 학습
- 이번 챕터에서는 앱을 배포하고 런칭하는 데 필요한 주변 기능 학습에 대해 배워보자.
- 게임에 음악 입히기, 스플래시 화면 붙이기, 광고 붙이기, 무료 에셋 구경하기
시작 화면 만들기
- '르탄이를 찾아라'라는 글씨와 함께 르탄이 애니메이션과 시작하기 버튼을 만들어 주자.
- 이 화면을 넣어주기 위해 StartScene을 만들자.
- Assets의 Scene 폴더에다 Scene 생성 -> 'StartScene'
- StartScene으로 가서 MianScene과 똑같이 배경색, 텍스트 세팅을 해주자.

- 기본적인 세팅을 해줬다. 이제 르탄이 애니메이션을 만들자.
- Canvas에서 UI -> Image -> 너비길이 400 -> rtan0 이미지 넣기
- 이제 이 르탄이가 rtan0부터 7까지 반복해서 교체돼야 한다.
- Create -> Animation Clip -> 'StartImage' -> 루프 체크
- StartImage를 드래그해 Image 게임 오브젝트에 드롭 -> Image Animation Coltroller 생성 완료
- StartImage 더블클릭 -> Image 클릭 -> rtan0-7 모두 선택 후 애니메이션 창에 드래그 드롭 -> 오른쪽 바를 35까지 끌어줌
- 플레이 해보면 원하던 대로 르탄이 이미지가 빠르게 바뀌는 애니메이션이 보여진다.
- 이제 시작하기 버튼을 눌렀을 때 MainScene으로 이동할 수 있는 로직을 만들어야 하는데~ 이건 '다시하기' 때 이미 만들어 놨다.
- StartBtn에 RetryButton 스크립트 넣기 -> On Click + -> Retry() 적용
- 플레이 해보면, 먼저 StartScene이 뜨고 시작하기 버튼을 눌렀을 때 게임이 시작된다.
스플래시 이미지 만들기(5-2)
- 스플래시 이미지를 세팅해 보자.
- 스플래시 이미지: 앱을 켰을 때 떴다가 사라지는 이미지(넷마블~)
- 이 스플래시 이미지는 StartScene -> MainScene 때처럼 LoadScene을 통해 만들어 주는 게 아니라, 유니티에서 이미 제공해주고 있는 툴을 사용해 세팅만 해주면 적용이 가능하다.
- 유니티로 돌아가자. 스플래시 이미지를 세팅해주는 곳은 상단 메뉴. Edit -> Project Settings -> Player -> Splash Image
- Preview를 눌러보면 Unity 로고가 나타났다가 사라졌다. 이 로고는 기본세팅. 이 로고가 뜬 다음 우리가 원하는 로고를 보여줄 수 있다.
- 다운 받은 이미지를 Assets -> Images 폴더에 넣어주자.
- spartaMsg 이미지 클릭 -> Mesh Type을 Full Rect로 변경 -> Apply
- 이제 스플래시 이미지로 활용할 수 있는 준비 끝.
- 세팅창으로 다시 돌아가서 Draw Mode를 All Sequential으로 변경 -> + -> None 클릭 -> spartaMsg 적용 -> Animation 속성을 Static으로 변경
- 프리뷰 해보면, 유니티 로고가 뜨고 spartaMsg 이미지가 뜨는 걸 볼 수 있다.
소리 & 배경음악 넣기(5-3)
효과음 넣기
- 게임이 시작하면 배경음악을 넣고, 카드를 뒤집거나 맞췄을 때 효과음을 넣어주자.
- Sounds를 다운 받아 Assets 폴더에 넣기
- 먼저 카드를 뒤집을 때와 맞췄을 때 효과음을 적용해 보자.
- Card 프리팹 열기 -> Add Component -> Audio Source 추가
- 이 Audio Source 컴포넌트를 Card 스크립트에서 컨트롤해 줄 것.
AudioSource audioSource;
- Card 스크립트에 AudioSource 변수 추가
- 그리고 같은 위치에 있었으니 로 가지고 올 수 있겠다.
void Start()
{
audioSource = GetComponent<AudioSource>();
}
- Start에 적어준다.
- 이제 이 오디오 소스 안에다가 음악 파일을 넣어줘야 한다. 음악 파일은 AudioClip
AudioSource audioSource; // Audio Source 컴포넌트 변수
public AudioClip clip; // AudioClip 변수
- 그러니 AudioClip 변수도 만들어 주자.
- 이 오디오 소스에다가 clip을 넣어주고 플레이를 해주면 되는 것. 이 부분을 코드로 작성하자.
- 카드가 열릴 때 효과음을 내줘야 하니 isOpen이 true가 되기 전에 작성해주자.
public void OpenCard() // 카드를 뒷면에서 앞면으로
{
audioSource.PlayOneShot();
anim.SetBool("isOpen", true); // isOpen 애니메이션 실행
front.SetActive(true); // 앞면 카드 활성화
back.SetActive(false); // 뒷면 카드 비활성화
- Play가 아니라 PlayOneShot이라고 하는 메소드를 호출해 준다.
- Play와 다른 점은 이 PlayOneShot이라는 메소드를 쓰게 되면 AudioClip끼리, 다른 효과음들끼리 겹치지 않는다. 한마디로 연속적으로 Audio Source를 재생시켜도 겹치지 않고 딱 한 번만 실행된다.
public void OpenCard() // 카드를 뒷면에서 앞면으로
{
audioSource.PlayOneShot(clip);
anim.SetBool("isOpen", true); // isOpen 애니메이션 실행
front.SetActive(true); // 앞면 카드 활성화
back.SetActive(false); // 뒷면 카드 비활성화
- 이 매개변수 안에다가 넣어줘야 할 Audio Clip을 넣어주면 된다.
- 그러면 Prefeb에다가, clip 변수에다가 재생시켜 주고 싶은 음악 파일만 잘 넣어 주면 되겠다. 이 부분까지 세팅하자.
- 유니티로 돌아가서 Clip 변수에다가 flip이라는 AudioClip을 넣어준다.
- 플레이 해보면, 카드를 뒤집었을 때 flip 효과음이 나고 있다.
- 이제 카드가 맞춰줬을 때(파괴될 때) 효과음을 넣어주자.
- GameManager에다가 Audio Source 컴포넌트를 붙여주자.
- 파괴되는 로직은 GameManager 스크립트에 있으니 그리로 이동
AudioSource audioSource;
public AudioClip clip;
void Start()
{
Time.timeScale = 1.0f; // 시간을 다시 1로, 게임 시작
audioSource = GetComponent<AudioSource>();
}
- Start에도 역시 AudioSource를 변수에다가 GetComponent를 통해 넣어준다.
- 두 장의 카드가 같았을 때(파괴될 때) 효과음을 재생시켜 줘야 한다.
public void Matched() // 카드 두 장을 매치해주는 함수
{
if(firstCard.idx == secondCard.idx) // 만약 두 Card에 있는 idx가 같다면
{
// 파괴해라.
audioSource.PlayOneShot(clip);
firstCard.DestroyCard();
secondCard.DestroyCard();
- Destroy 위에 작성
- 유니티로 돌아가서 GameManager의 Clip 변수에 'match' 클립을 넣어준다.
- 플레이 해보면, 두 장의 카드를 맞췄을 때 띠링~하는 효과음이 난다.
BGM 넣기
- 이제 게임이 진행되는 동안에 계속해서 BGM이 나오게 해 주자.
- BGM은 AudioManager라고 하는 별도의 스크립트를 만들어서 관리해 주자.
- AudioManager 오브젝트와 스크립트 생성
AudioSource audioSource;
public AudioClip clip;
- AudioManager 스크립트에도 역시 변수 추가
void Start()
{
audioSource.Play();
}
- 이번에는 PlayOneShot이 아난 Play 함수를 이용해 보자.
void Start()
{
audioSource.clip = this.clip;
audioSource.Play();
}
- Play 해주기 전, 이번에는 AudioSource에 Clip에다가 먼저 넣어주자.
- audioSource.clip이라고 하는 변수에다가 AudioManager 스크립트에 있는 clip을 넣어주면 되겠다. 그래서 this.clip이라고 적어주면 됨(this는 생략 가능)
- 이렇게 적어주면 재생시켜 주고 싶은 AudioClip을 변수를 통해서 잘 넣어주겠다. 그리고 그 Clip을 AudioSource에 있는 Clip 속성에다가 넣어주게 됨. 그리고 나서 AudioSource를 Play해 주면 BGM이 재생 될 것.
- 유니티로 돌아가서, AudioManager에도 Audio Source 컴포넌트와 스크립트를 붙여주자.
- Clip 변수에 bgmusic을 넣어주자. 그러면 이 bgmusic Clip이 Audio Source 컴포넌트에 있는 AudioClip안으로 들어가게 되는 것이다. 그리고 나서 Play가 되는 구조
- Play on Awake 체크는 해제해 준다.
- 플레이 해보면 NullReferenceException: Object reference not set to an instance of an object 오류가 뜨며 BGM도 재생이 안되고 있다.
- 아~ GetComponent를 안해줬다.
void Start()
{
audioSource = GetComponent<AudioSource>();
audioSource.clip = this.clip;
audioSource.Play();
}
- 역시 추가해줬다.
- 다시 플레이 해보면 BGM이 잘 나온다.
- 효과음과 배경음 모두 잘 적용이 됐다.
- 그런데 이 BGM이 MainScene으로 들어왔을 때 재생이 되는 게 아니라 StartScene에서부터 재생해서 그대로 끊기지 않고 이어졌으면 좋겠다. 이 부분을 코드로 작성해 보자.
- StartScene에서 시작돼야 하니 StartScene으로 이동해서 AudioManager 오브젝트를 만들어 주자.
- AudioManager 스크립트와 Audio Source 컴포넌트 붙여주고 Clip 변수에 BGM 넣기
- 이 Aidio Manager의 BGM이 끊기지 않고 그대로 MainScene까지 유지가 되려면 스크립트에서 한 줄의 코드를 작성해야 한다.
- 그 전에 AudioManager도 싱글톤으로 만들어 주자.
public static AudioManager Instance;
private void Awake()
{
if(Instance == null)
{
Instance = this;
}
}
- Instance 변수 추가, Instance가 null일 때만 나 자신(this)넣어주기
- 그리고 밑에다가 한 줄 더 추가하자.
private void Awake()
{
if(Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
}
- 이렇게 하면 씬을 이동해도 이 AudioManager 게임 오브젝트는 파괴되지 않는다.
- AudioManager 게임 오브젝트가 파괴되지 않으면 거기에 붙어있는 AudioSource, 그리고 이 AudioManager 스크립트도 파괴되지 않겠다.
- 그럼 음악도 컴포넌트 파괴가 안되니까 그대로 유지되면서 넘어가게 된다.
- 유니티로 가서 플레이 해보면, MainScene으로 넘어와도 Hierarchy 창에 DontDestroyOnLoad가 뜨면서 AudioManager를 유지해주고 있다.
- 문제는 BGM이 두 개가 틀어졌다. 왜냐면 MainScene에도 AudioManager가 있었기 때문에 StartScene에서 끌고 온 것까지 총 두 개가 틀어진 것.
- 이렇게 AudioManager가 여러 개 생길 수 있다. 그런데 문제는 싱글톤은 나 자신, 딱 하나만 있어야 되는 속성을 가지기 때문에 이 싱글톤이 두 개가 됐을 때, 싱글톤을 단 게임 오브젝트가 2개가 있을 때는 하나를 파괴시켜 줘야 한다. 이 예외처리 코드를 작성해 주자.
if(Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
- Instance가 null이라는 것은 모두가 접근할 수 있는 이 Instance 변수에 아직 아무것도 담겨있지 않다는 뜻
- 근데 Instance = this를 해줬다면 이 Instance가 더 이상 null이 아닐 것. 이미 '나 하나'가 존재할 때 새로운 게 생성되려고 하면 그걸 파괴시켜 줘야 함.
private void Awake()
{
if(Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
- 그래서 else문을 만들어 Destroy(gameObject)라고 적는다.
- AudioManager를 StartScene에서 먼저 만들어줬다. 그러면 StartScene에서 만들어진 AudioManager가 있는 상태에서 MainScene에 있는 AudioManager가 이 Awake문인 Instance == null이라는 조건문을 탈 때, 이미 StartScene에서 만들어 놓은 Instance가 있기 때문에 위의 if문을 타는 게 아니라 else문을 타게 된다. 그래서 파괴가 됨
- 그럼 이제 AudioManager는 딱 하나만 존재하게 될 거고 BGM도 하나만 나올 것
- 유니티로 돌아가서 플레이 해보면, BGM이 끊기지 않고 하나만 유지된다. Hierarchy 창을 봐도 기존에 있던 MainScene의 AudioManager가 파괴됐다.
- 방금 작성해 준 예외처리 코드 때문에 이미 싱글톤이 존재해서 새로 만들려고 하는 이 싱글톤은 파괴된 것