[C#] 유니티 리듬게임 만들기(상점)
- 유튜브 '케이디' 님의 리듬게임 영상을 공부하면서 진행하였습니다.
영상 모두 진행한 후 Chapter 19 이후부터 추가적인 요소를 혼자 힘으로 만들어 보는 중
▶상점 구현하기
간단한 뽑기 상점겸 인벤토리 역활을 하는 STORE 메뉴 구현
◆ 필수 기능
1. 뽑기 버튼을 눌렀을 때 자신의 코인이 N만큼 차감
2. 뽑기 버튼을 눌렀을 때 랜덤하게 스킨 중 하나 획득
3. 자신이 뽑은 스킨은 보유 중 표시
4. 보유 중인 스킨을 누르면 해당 스킨으로 변경
5. Back버튼 눌렀을 때 메인화면으로 이동
6. 기본 스킨은 처음 부터 사용가능
![]() |
![]() |
▷StoreMenu 구현
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class StoreMenu : MonoBehaviour
{
[SerializeField] Text txtCoin = null;
[SerializeField] GameObject goMainUI = null;
[SerializeField] GameObject goWarning = null;
[SerializeField] GameObject goArm = null;
[SerializeField] GameObject showResult = null;
[SerializeField] GameObject[] slot = null;
[SerializeField] Animator warnningAnimator = null;
[SerializeField] Animator armAnimator = null;
[SerializeField] Animator resultAnimator = null;
[SerializeField] Image skinResult = null;
[SerializeField] Text changeSkin = null;
string warn = "Warn";
int r;
PlayerController thePlayer;
DatabaseManager theDatabase;
void OnEnable()
{
//AudioManager에서 Store BGM라면 Loop = true
AudioManager.instance.StopBGM();
AudioManager.instance.PlayBGM("Store");
if (theDatabase == null)
{
theDatabase = FindObjectOfType<DatabaseManager>();
thePlayer = FindObjectOfType<PlayerController>();
}
//DB에서 받아온 자신의 코인
txtCoin.text = string.Format("{0:#,##0}", theDatabase.coin);
SetInvent();
}
//인벤토리 세팅
public void SetInvent()
{
for (int i = 0; i < theDatabase.invent.Length; i++)
{
if (theDatabase.invent[i] == true)
slot[i].SetActive(true);
}
}
//Skin 버튼 클릭 이벤트
public void BtnSkin0()
{
if (theDatabase.invent[0])
{
thePlayer.SetMat(0);
changeSkin.text = "스킨(빨강)이 변경되었습니다.";
AudioManager.instance.PlaySFX("Change");
goArm.SetActive(true);
armEffect();
}
}
public void BtnSkin1()
{
if (theDatabase.invent[1])
{
thePlayer.SetMat(1);
changeSkin.text = "스킨(노랑)이 변경되었습니다.";
AudioManager.instance.PlaySFX("Change");
goArm.SetActive(true);
armEffect();
}
}
public void BtnSkin2()
{
if (theDatabase.invent[2])
{
thePlayer.SetMat(2);
changeSkin.text = "스킨(초록)이 변경되었습니다.";
AudioManager.instance.PlaySFX("Change");
goArm.SetActive(true);
armEffect();
}
}
public void BtnSkin3()
{
if (theDatabase.invent[3])
{
thePlayer.SetMat(3);
changeSkin.text = "스킨(파랑)이 변경되었습니다.";
AudioManager.instance.PlaySFX("Change");
goArm.SetActive(true);
armEffect();
}
}
public void BtnSkin4()
{
if (theDatabase.invent[4])
{
thePlayer.SetMat(4);
changeSkin.text = "스킨(그레이)이 변경되었습니다.";
AudioManager.instance.PlaySFX("Change");
goArm.SetActive(true);
armEffect();
}
}
public void BtnSkin5()
{
if (theDatabase.invent[5])
{
thePlayer.SetMat(5);
changeSkin.text = "스킨(검정)이 변경되었습니다.";
AudioManager.instance.PlaySFX("Change");
goArm.SetActive(true);
armEffect();
}
}
public void BtnSkin6()
{
thePlayer.SetMat(6);
changeSkin.text = "기본스킨으로 변경되었습니다.";
AudioManager.instance.PlaySFX("Change");
goArm.SetActive(true);
armEffect();
}
//Back버튼 이벤트
public void BtnMain()
{
goMainUI.SetActive(true);
this.gameObject.SetActive(false);
AudioManager.instance.StopBGM();
}
//상점 이팩트
public void WarnnigEffect()
{
warnningAnimator.SetTrigger(warn);
}
public void armEffect()
{
armAnimator.SetTrigger("Arm");
}
public void resultEffect()
{
resultAnimator.SetTrigger("Show");
}
//뽑기버튼 이벤트
public void BtnBuy()
{
if (theDatabase.coin >= 1) {
AudioManager.instance.PlaySFX("Buy");
r = Random.Range(0, 6);
theDatabase.coin -= 1;
theDatabase.SaveCoin();
txtCoin.text = string.Format("{0:#,##0}", theDatabase.coin);
theDatabase.invent[r] = true;
theDatabase.SaveInvent();
SetInvent();
showResult.SetActive(true);
ShowResult();
}
else
{
AudioManager.instance.PlaySFX("Err");
goWarning.SetActive(true);
WarnnigEffect();
}
}
//뽑기 결과
public void ShowResult()
{
resultEffect();
switch(r){
case 0:
skinResult.color = Color.red;
break;
case 1:
skinResult.color = Color.yellow;
break;
case 2:
skinResult.color = Color.green;
break;
case 3:
skinResult.color = Color.blue;
break;
case 4:
skinResult.color = Color.gray;
break;
case 5:
//검은색일경우 화면에 안보여서 보일만큼 어둠게 조절
skinResult.color = new Color(0.3f, 0.3f, 0.3f);
break;
default : break;
}
}
//다이얼로그 창 X버튼 이벤트
public void BtnX()
{
goWarning.SetActive(false);
goArm.SetActive(false);
showResult.SetActive(false);
}
}
▷필요 요소(PlayerController)
public class PlayerController : MonoBehaviour
{
public Color basic;
public Color[] currentSkin = { Color.red, Color.yellow, Color.green, Color.blue, Color.gray, Color.black};
//setMat
public void SetMat(int c_num)
{
if (c_num == 6)
realCube.GetComponent<Renderer>().material.color = basic;
else
realCube.GetComponent<Renderer>().material.color = currentSkin[c_num];
theDatabase.skin = c_num;
theDatabase.SaveSkin();
}
Playcontroller내에 따로 스킨배열을 생성하여 선택만 해주었음. (배열을 StoreManu Class로 옮겨서 사용해도 상관없을 듯)
◐기본 스킨 설정시 에러발생
처음 기본스킨을 핑크로 해놔서 다시 선택할 때,
public Color basic = new Color(//대충 핑크색 RGB) 로 받았더니 게임 시작시 공이 새 하얗게 변함.
이것도 무슨 레어스킨같긴 한데.. 암튼 목적과 달라서 해결 방법을 찾아봄 무슨 HSV값도해보고 RGB에서 /255f 방법도 써봤는데
그대로임...
◑ 해결방법
그렇게 찾아보던 중.. 컬러코드를 이용해서 스크립트에 색상을 받아오는 방법을 발견 위 코드처럼
Color basic 선언해놓고 void start() 내에
ColorUtility.TryParseHtmlString("#F480FF", out basic);
이렇게 작성해주면 색상코드를 맞는 형태로 basic에 넣어 줌.
특정 색상값 받을때는 이게더 쉬우면서 확실한것 같네
▷필요 요소(DataBase)
public class DatabaseManager : MonoBehaviour
{
public int coin = 100; //실험용으로 100 넣어 둠
public int skin;
public bool[] invent;
void Start()
{
LoadCoin();
LoadSkin();
LoadInvent();
}
//적용된 스킨 저장
public void SaveSkin()
{
PlayerPrefs.SetInt("Skin", skin);
}
//인벤토리에 들어있는 데이터 저장
public void SaveInvent()
{
for (int i = 0; i < invent.Length; i++)
{
PlayerPrefs.SetInt("HasSkin" + i, System.Convert.ToInt32(invent[i]));
}
}
//인벤토리 불러오기
public void LoadInvent()
{
if (PlayerPrefs.HasKey("HasSkin0"))
{
for (int i = 0; i < invent.Length; i++)
{
invent[i] = System.Convert.ToBoolean(PlayerPrefs.GetInt("HasSkin" + i));
}
}
}
//스킨 불러오기
public void LoadSkin()
{
if (PlayerPrefs.HasKey("Skin"))
{
skin = PlayerPrefs.GetInt("Skin");
}
}
//코인저장
public void SaveCoin()
{
PlayerPrefs.SetInt("Coin", coin);
}
//코인불러오기
public void LoadCoin()
{
if (PlayerPrefs.HasKey("Coin"))
{
coin = PlayerPrefs.GetInt("Coin");
}
}
유니티랑 C#이 처음 써보는거라 그냥 Coin이나 Skin은 Score저장 방법이랑 비슷하게 진행함
◆ 막힌부분
문제는 인벤토리였음 bool형의 스킨배열을 만들고 획득하면 그 스킨에 맞는 인덱스를 true로 바꿔주기로 했는데
PlayerPrefs.GetBool <이런거 없어서.. 한참 고민하다가 bool형을 int로 받을 수있게만 해주면 될 것 같아
ToBoolean을 사용해 봄 (효과는 굉장하였다) 아무 문제없이 생각한데로 동작 함
▷필요 요소(Result)
public class Result : MonoBehaviour
{
public void ShowResult()
{
int t_coin = (t_currentScore / 50);
theDatabase.coin += t_coin;
theDatabase.SaveCoin();
코인은 결과창에서 점수 나누기 50한만큼 Database에 누적해서 Save해줬음
간단하지만 처음 유니티랑 C#을 건드려본 나에게는 너무 힘들었다... 다음에는 장애물을 만들어 볼 예정