타이틀 화면의 BGM은 TitleManager 스크립트에서 실행합니다. Start메서드에 다음과 같이 추가합니다.
SoundManager클래스의 soundManager변수는 맨처음 생성된 SoundManager가 저장된 변수입니다.
이 값으로 SoundManager클래스의 메서드를 호출할 수 있습니다. BGMType.title을 인수로 전달해 PlayBgm메서드를 호출할 수있습니다.
void Start() {
string sceneName = PlayerPrefs.GetString("LastScene"); //저장 된 씬
if (sceneName == "")
{
~생략
}
//타이틀 BGM 재생
SoundManager.soundManager.PlayBgm(BGMType.Title);
}
게임중/보스전 BGM
게임중 각 씬의 BGM은 RoomManager의 Start 메서드에서 실행합니다. 현재 저장된 현재의 씬이름을 PlayerPrefs.GetString 으로 읽어 보스 스테이지의 씬 이름인지 확인후 재생할 BGM을 바꿉니다.
Start()
void Start()
{
//플레이어 캐릭터 위치
//출입구를 배열로 얻기
~생략
// 씬 이름 얻기
string scenename = PlayerPrefs.GetString("LastScene");
if (scenename == "BossStage") {
//보스 BGM 재생
SoundManager.soundManager.PlayBgm(BGMType.InBoss);
} else{
// 게임 중 BGM 재생
SoundManager.soundManager.PlayBgm(BGMType.InGame);
}
}
재시도후 SE
UIManager클래스의 Retry 메서드에도 다음과 같이 사운드 재생코드를 추가합니다. soundManager의playingBGM에 BGMType.None을 설정한 후 초기화하면 씬을 불러온 뒤 각 스테이지의 BGM이 재생됩니다.
Retry()
public void Retry()
{
//HP 되돌리기
PlayerPrefs.SetInt("PlayerHP", 3);
//BGM 제거
SoundManager.plyingBGM = BGMType.None;
//게임 중으로 설정
SceneManager.LoadScene(retrySceneName); //씬 이동
}
사이드뷰 게임에서는 씬이 바뀔때 마다 BGM을 처음부터 재생했습니다. 이번 예제에서는 씬이 바귀어도 게임이 이어지기 때문에 타이틀화면, 게임화면, 보스전등에서만 BGM이 바뀌도록 합니다.
게임 클리어, 게임오버, 활을 쏠때만 SE(사운드이펙트)를 적용합니다. 예제에서는 버튼이 눌릴때 문이열릴때 문이 닫힐대 아이템을얻을때 대미지를 받을때 적 사망,보스사망등 다양한 곳에 SE를 적용했습니다.
사운드 재생 오브젝트와 스크립트 만들기
하이라키에 빈오브젝트를 만들고 이름을 SoundManager라고 합니다. SoundManager스크립트를 만들어 하이라키의 SoundManager게임오브젝트에 어태치합니다.
AddComponent로 Audio Source를 추가하고 Play On Awake 체크해제하고 Loop는 체크합니다. BGM제어는 나중에 스크립트에서 제어합니다. Audio 클립은 비워둡니다.
씬이 바뀌어도 BGM이 끊어지지 않게 재생한다.
씬이 바뀌어도 BGM이 끊어지지 않게 재생하려면 SoundManager가 같은 게임 오브젝트로 존재해야 합니다.
열거형
public enum BGMType
{
None, //없음
Title, //타이틀
InGame, //게임 중
InBoss, //보스전
}
//SE 종류
public enum SEType
{
GameClear, //게임 클리어
GameOver, //게임 오버
Shoot, //활 쏘기
}
변수
public AudioClip bgmInTitle; //타이틀 BGM
public AudioClip bgmInGame; //게임 중 BGM
public AudioClip bgmInBoss; //보스전 BGM
public AudioClip meGameClear; //게임 클리어
public AudioClip meGameOver; //게임 오버
public AudioClip seShoot; //활 쏘기
static 변수
씬이 바뀌어도 값이 변화되지 않게 static변수를 마련합니다. 자신을 저장하는 soundManager와 재생중이 BGMType을 저장합니다.
public static SoundManager soundManager; //첫 SoundManager를 갖는 변수
public static BGMType plyingBGM = BGMType.None; //재생 중인 BGM
Awake()
Start()보다 앞에서 호출되는 Awake()에서 이전에 실행되었던 soundManager가 있으면 정리합니다.
게임이 실행되고 맨처음 SoundManager가 실행되면 soundManager변수는null입니다. 그때 DontDestroyOnLoad메서드를 호출해 게임 오브젝트가 파기되지 않도록 합니다. soundManager변수는 static이므로 씬이 바뀌어도 값이 유지됩니다.
DontDestroyOnLoad(gameObject)를 이용 씬이 바뀌어도
private void Awake()
{
//BGM 재생
if (soundManager == null)
{
soundManager = this; //static 변수에 자기 자신을 저장
//씬이 바뀌어도 게임 오브젝트를 파기하지 않음
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);//게임 오브젝트르 파기
}
}
PlayBgm()
플레이할 BGM타입이 다르면 AudioSource컴포넌트를 이용해 오디오 클립의 이름을 바꿔서 Play()합니다.
public void PlayBgm(BGMType type)
{
if (type != plyingBGM)
{
plyingBGM = type;
AudioSource audio = GetComponent<AudioSource>();
if (type == BGMType.Title)
{
audio.clip = bgmInTitle; //타이틀
}
else if (type == BGMType.InGame)
{
audio.clip = bgmInGame; //게임 중
}
else if (type == BGMType.InBoss)
{
audio.clip = bgmInBoss; //보스전
}
audio.Play();
}
}
StopBgm()
BGM을 정지합니다.
public void StopBgm()
{
GetComponent<AudioSource>().Stop();
plyingBGM = BGMType.None;
}
SEPlay(SEType type)
상황에 맞는 사운드 이펙트를 재생합니다.
public void SEPlay(SEType type)
{
if (type == SEType.GameClear)
{
GetComponent<AudioSource>().PlayOneShot(meGameClear); //게임 클리어
}
else if (type == SEType.GameOver)
{
GetComponent<AudioSource>().PlayOneShot(meGameOver); //게임 오버
}
else if (type == SEType.Shoot)
{
GetComponent<AudioSource>().PlayOneShot(seShoot); //활 쏘기
}
}
보스는 무한히 총을 쏠수 있고 플레이어는 돌아 다니면서 화살을 줏어야 보충할 수 있습니다.
화살의 위치는 랜덤으로 몇군데 배치하겠습니다.
최종 보스용씬은 BossStage라는 이름으로 씬을 만들고 BuildSetting에 등록합니다. 타일맵으로 맵을 만듭니다.
예제를 다운로드하고 로딩하면 SoundManager에러가 나는데 일단 씬뷰에서 지워줍니다. 전 Cavas도 에러가 났는데 교재에서 다운받아 UIManager에 깔아줬습니다.
게임 스테이지로 설정하기 위해 지금까지 만들었던 프리팹을 배치합니다.
Player : 프리팹을 추가하면 됩니다.
RoomManager : UIManager의 Retry Scene Name에 다시 시도할 때 불러올 씬 이름을 설정합니다.
Canvas : Main Camera를 설정합니다.
EventSystem : +>UI>Event System
아이템을 자동으로 배치하는 기능 만들기
이제 아이템(화살)을 자동으로 배치하는 기능을 추가합니다.
화살의 수를 항상 확인한다
화살의 수가 0이 되면 화살을 랜덤위치에 배치합니다.
오브젝트 발생기
계측뷰 +>CreateEmpty를 클릭해 빈게임오브젝트를 만들오 Boss폴더에 이름을 ObjGen으로 하고 칼라아이콘을 추가합니다.
ObjectGenPoint 스크립트를 만들기
ObjGen에 어태치합니다. 씬에 배치할 위치와 프리팹을 지정해 오브젝트를 만드는 스크립트입니다.
변수
public GameObject objPrefab; //발생 시킬 Prefab 데이터
ObjectCreate() 메소드
현재 위치에 프리팹으로 게임오브젝트를 배치합니다. 외부에서 호출합니다.
public void ObjectCreate() {
Vector3 pos = new Vector3(transform.position.x,transform.position.y,-1.0f);
//Prefab으로 GameObject 만들기
Instantiate(objPrefab, pos, Quaternion.identity);
Item 폴더의 Arrow 프리팹을 끌어다 Obj Prefab에 지정합니다.
ObjGen을 Boss폴더로 끌어다 프리팹으로 만듭니다.
프리팹을 끌어다 씬뷰에 10개정도 추가합니다. 화살이 생성될 위치입니다.
ObjectGenManager스크립트
다음으로 배치된 ObjectGenPoint를 관리하고 화살의 수를 감시해 화살의 갯수가 0이 되면 배치하는 기능입니다.
완성후 하이라키뷰의 RoomManager에 어태치합니다. 프리팹이 아닌 씬에 배치된 오브젝트에 어태치해야 해당 씬에서만 스크립트가 동작합니다.
씬에서 Item을 찾아 화살이 있다면 리턴하고 없고 플레이어도 화살을 가지고 있지 않다면 임의의 위치에 화살을 배치합니다.
void Update() {
//ItemData 찾기
ItemData[] items = GameObject.FindObjectsOfType<ItemData>();
//반복문으로 화살 찾기
for (int i = 0; i < items.Length; i++) {
ItemData item = items[i];
if (item.type == ItemType.arrow) {
return; //화살이 있으면 아무것도 하지 않고 메서드에서 빠져나가기
}
}
//플레이어가 존재하는지와 화살의 수 확인
GameObject player = GameObject.FindGameObjectWithTag("Player");
if (ItemKeeper.hasArrows == 0 && player != null) {
//화살 개수가 0이고 플레이어가 존재하면
//배열의 개수 범위 안에서 난수 생성
int index = Random.Range(0, objGens.Length);
ObjectGenPoint objgen = objGens[index];
objgen.ObjectCreate(); //아이템 배치
}
}
// 체력
public int hp = 10;
// 반응 거리
public float reactionDistance = 7.0f;
public GameObject bulletPrefab; //총알
public float shootSpeed = 5.0f; //총알 속도
//공격중인지 여부
bool inAttack = false;
Update()
"Player" Tag로 Player를 찾아서 공격범위이면 inAttack=true, 공격 애니메이션 Play("BossAttack")등 공격처리를 합니다.
void Update() {
if (hp > 0) {
//Player 게임 오브젝트 가져오기
GameObject player = GameObject.FindGameObjectWithTag("Player");
if (player != null) {
//플레이어와의 거리 확인
Vector3 plpos = player.transform.position;
float dist = Vector2.Distance(transform.position, plpos);
if (dist <= reactionDistance && inAttack == false) {
//범위 안 & 공격 중이 아니면 공격 애니메이션
inAttack = true;
// 애니메이션 변경
GetComponent<Animator>().Play("BossAttack");
} else if (dist > reactionDistance && inAttack) {
inAttack = false;
// 애니메이션 변경
GetComponent<Animator>().Play("BossIdle");
}
} else {
inAttack = false;
// 애니메이션 변경
GetComponent<Animator>().Play("BossIdle");
}
}
}
스테이지 마지막에 싸울 보스 캐릭터와 보스 스테이지를 위한 씬을 만들어봅시다. 보스 캐릭터는 다음과 같이 동작합니다.
플레이어 캐릭터와 접촉하면 플레이어가 대미지를 받는다.
플레이어 캐릭터가 접근하면 총알을 발사해 공격한다.
HP를 설정할 수 있다. 화살을 일정량 맞으면 쓰러진다.
보스 캐릭터와 관련된 데이터는 Boss폴더를 만들고 저장합니다. 사용할 이미지도 Boss 폴더로 옮겨둡니다. 지금 바로 Boss폴더를 만듭니다.
보스 캐릭터 게임 오브젝트 만들기
먼저 보스 캐릭터의 이미지 에셋을 준비합니다. Boss가 보스 캐릭터용 이미지입니다.
Boss_0~1:대기, Boss_2~3:공격 ,Boss_4: 사망 애니메이션입니다.
보스 캐릭터의 애니메이션 만들기
대기애니메이션 만들기
Boss_0~1을 씬뷰에 끌어다 놓으면 애니메이션 데이터를 만듭니다. 클립 이름을 BossIdel로 합니다. 배치한 보스 캐릭터 게임 오브젝트의 이름은 Boss, 애니메이션 컨트롤러의 이름은 BossAnime로 이름을 변경합니다.
Sprite Renderer의 Order in Layer를 2로 설정하고, Circle Collider2D를 어태치 합니다. 보스 캐릭터는 움직이지 않으니 Rigidbody2D는 쓰지 않습니다. 보스 캐릭터에 Enemy태그와 Enemy Layer를 만들어 적용합니다. 나중에 보스가 발사하는 총알의 충돌 판정에 사용합니다.
CreateEmpty를 하나만들어 gate로 이름 바꾸고 Boss의 자식으로 하고 가슴쯤에 배치합니다. 씬뷰에서 구별하기 쉽게 칼라아이콘을 설정합니다. 총알이 발사될 위치로 사용합니다.
BossIdle 애니메이션을 열고 하이라키의 Boss를 선택한후 Samples를 2로 설정합니다. ▶클릭해서 확인해봅니다.
공격 애니메이션
Animation창에서 BossIdel을 클릭하고 Create New Clip을 선택하고 창이 뜨면 이름은 BossAttack으로 합니다.
Boss_2~3을 끌어 씬 뷰에 끌어다 애니메이션 클립을 만듭니다.
Sample을 4로 합니다. 약간 포즈를 취한뒤 공격을 하기 위해 0프레임의 키프레임을 카피해 그 다음 프레임어 넣어줍니다.
사망 애니메이션
Boss_4 이미지를 이용해 사망애니메이션을 만들고 이름을 BossDead로 합니다. Sprite Renderer.Color Property를 추가하가 마지막 프레임은 알파값이 0이 되도록 저장합니다.
애니메이션 컨트롤러
BossAnime을 열고 3개의 애니메이션이 다 있는지 확인합니다. 없으면 끌어다 놓습니다.
다룰수 있는 데이터형은 ,숫자,문자열,논리형, null, 배열 등입니다. {}로 감싼 데이터 자체를 값으로 가질 수도 있습니다.
유니티는 JsonUtility라는 클래스가 있어 쉽게JSON 형식을 사용할 수 있습니다.
배치 데이터를 저장하려면 JsonUtility 클래스를 사용 JSON형식(텍스트)으로 변환하고 PlayerPrefs 클래스를 활용 텍스트로 저장합니다, JSON자체는 텍스트이므로 PlayerPrefs클래스의 SetString메서드로 읽고 쓸수있습니다.
예제에서는 열린문, 열린상자, 획득한 아이템, 쓰러트린적 의 정보를 저장합시다. 저장하는 정보는 게임오브젝트를 식별할 수 있는 번호와 종류입니다. 번호는 9장까지 만들었던 Door, ItemBox, ItemData, EnemyController클래스의 arrnageID변수를 사용합니다. 종류는 각 게임오브젝트의 태그를 이용합니다.
배치된 정보를 기록하는 스크립트 만들기
JSON을 기록하려면 먼저 저장할 JSON과 같은 구조를 가진 클래스를 정의해야 합니다. SaveData라는 이름의 스크립트를 RoomManager폴더에 만들고 다음과 같이 작성합니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class SaveData
{
public int arrangeId = 0; //배치 ID
public string objTag = ""; //배치된 오브젝트의 태그
}
[System.Serializable]
public class SaveDataList
{
public SaveData[] saveDatas; //SaveData 배열
}
[System.Serializable]는 이 클래스는 저장할 대상입니다를 의미합니다. JSON으로 만들기 위해 필요한 것이라고 합시다.
SaveData 클래스는 배치된 오브젝트 하나를 나타내고. SaveDataList는 이들을 여러개 배열로 저장하는 데이터입니다.
두 클래스는 JSON형식(텍스트) 데이터를 클래스로 변환했을 때의 형을 정의합니다.
다음은 JSON데이터를 읽거나 써서 배치된 데이터를 관리하는 스크립트를 만들어보겠습니다.
SaveDataManager 스크립트를 RoomManager폴더에 만들고 RoomManager의 프리팹에 어태치합니다.
변수
SaveDataList클래스의 객체를 public static으로 선언합니다.
public static SaveDataList arrangeDataList; //베치 데이터
Start메서드
void Start() {
//SaveDataList 초기화
arrangeDataList = new SaveDataList();
arrangeDataList.saveDatas = new SaveData[] { };
//씬 이름 불러오기
string stageName = PlayerPrefs.GetString("LastScene");
//씬 이름을 키로하여 저장 데이터 읽어오기
string data = PlayerPrefs.GetString(stageName);
if (data != "") {
//--- 저장 된 데이터가 존재할 경우 ---
//JSON에서 SaveDataList로 변환하기
arrangeDataList = JsonUtility.FromJson<SaveDataList>(data);
for (int i = 0; i < arrangeDataList.saveDatas.Length; i++) {
SaveData savedata = arrangeDataList.saveDatas[i]; //배열에서 가져오기
//태그로 게임 오브젝트 찾기
string objTag = savedata.objTag;
GameObject[] objects = GameObject.FindGameObjectsWithTag(objTag);
for (int ii = 0; ii < objects.Length; ii++) {
GameObject obj = objects[ii]; //배열에서 GameObject 가져오기
//GameObject의 태그 확인하기
if (objTag == "Door") { //문
Door door = obj.GetComponent<Door>();
if (door.arrangeId == savedata.arrangeId) {
Destroy(obj); //arrangeId가 같으면 제거
}
} else if (objTag == "ItemBox") { //보물 상자
ItemBox box = obj.GetComponent<ItemBox>();
if (box.arrangeId == savedata.arrangeId) {
box.isClosed = false; //arrangeIdd가 같으면 열기
box.GetComponent<SpriteRenderer>().sprite = box.openImage;
}
} else if (objTag == "Item") { //아이템
ItemData item = obj.GetComponent<ItemData>();
if (item.arrangeId == savedata.arrangeId) {
Destroy(obj); //arrangeId가 같으면 제거
}
}
else if (objTag == "Enemy") { //적
EnemyController enemy = obj.GetComponent<EnemyController>();
if (enemy.arrangeId == savedata.arrangeId) {
Destroy(obj); //arrangeId가 같으면 제거
}
}
}
}
}
}
SetArrangeId()
public static void SetArrangeId(int arrangeId, string objTag)
{
if (arrangeId == 0 || objTag == "")
{
//기록하지 않음
return;
}
//추가 하기 위해 하나 많이 SaveData 배열 만들기
SaveData[] newSavedatas = new SaveData[arrangeDataList.saveDatas.Length + 1];
//데이터 복사
for (int i = 0; i < arrangeDataList.saveDatas.Length; i++)
{
newSavedatas[i] = arrangeDataList.saveDatas[i];
}
//SaveData 만들기
SaveData savedata = new SaveData();
savedata.arrangeId = arrangeId; //Id를 기록
savedata.objTag = objTag; //태그 기록
//SaveData 추가
newSavedatas[arrangeDataList.saveDatas.Length] = savedata;
arrangeDataList.saveDatas = newSavedatas;
}
SaveArrangeData()
public static void SaveArrangeData(string stageName)
{
if (arrangeDataList.saveDatas != null && stageName != "")
{
//SaveDataList를 JSON 데이터로 변환
string saveJson = JsonUtility.ToJson(arrangeDataList);
//씬 이름을 키로하여 저장
PlayerPrefs.SetString(stageName, saveJson);
}
}
열린 보물 상자 저장
보물 상자가 열리고아이템이 생성됐을때 호출되는 ItemBox 클래스의 OnCollisionEnter2D 메서드에 보물 상자의 열린 상태를 저장하는 처리를 추가합니다. 인수로 자기 자신(보물 상자)의 arrangeID와 태그를 전달합니다.
ItemBox스크립트를 열어 다음을 추가합니다.
public class ItemBox : MonoBehaviour
{
~ 생략
//접촉 (물리)
private void OnCollisionEnter2D(Collision2D collision) {
if (isClosed && collision.gameObject.tag == "Player") {
//상자가 닫혀 있는 상태에서 플레이어와 접촛
//프리펩으로 아이템 만들기
//배치 Id 기록
SaveDataManager.SetArrangeId(arrangeId, gameObject.tag);
}
}
}
획득한 아이템 저장
아이템을 얻었을때 호출되는 ItemData클래스의 OnCollisionEnter2D()에 획득한 아이템을 저장하는 처리를 추가합니다. 인수로 arrangeID와 태그를 전달합니다.
public class ItemData : MonoBehaviour{
~생략
//접촉 (물리)
private void OnTriggerEnter2D(Collider2D collision) {
if (collision.gameObject.tag == "Player") {
if (type == ItemType.key) { //열쇠 }
else if (type == ItemType.arrow) { //화살 }
else if (type == ItemType.life) { }
//++++ 아이템 획득 연출 ++++
//충돌 판정 비활성
//아이템의 Rigidbody2D가져오기
//중력 젹용
//위로 튀어오르는 연출
//0.5초 뒤에 제거
//배치 Id 기록
SaveDataManager.SetArrangeId(arrangeId, gameObject.tag);
}
}
}
열린 문 저장
문이 열렸을때 호출되는 Door클래스의 OnCollisionEnter2D()에 문의 열린 상태를 저장하는 처리를 추가합니다. 인수로 arrangeID와 태그를 전달합니다.
public class Door : MonoBehaviour
{
~생략
void OnCollisionEnter2D(Collision2D collision) {
if (collision.gameObject.tag == "Player") {
if (ItemKeeper.hasKeys > 0) { //열쇠를 가지고있으면
//열쇠를 하나 감소
//문 열기 (제거하기)
//배치 Id 기록
SaveDataManager.SetArrangeId(arrangeId, gameObject.tag);
}
}
}
}
쓰러트린 적 저장
EmemyController의 OnCollisionEnter2D()에 쓰러트린 적을 저장하는 처리를 추가합니다. 인수로 arrangeID와 태그를 전달합니다.
private void OnCollisionEnter2D(Collision2D collision){
if (collision.gameObject.tag == "Arrow") {
hp--; //데미지
if (hp <= 0) { //사망!
~사망처리
//배치 Id 기록
SaveDataManager.SetArrangeId(arrangeId, gameObject.tag);
}
}
}
스테이지를 이동할 때 데이터 저장
스테이지 이동은 RoomManager클래스의 ChangeScene메서드에서 실행합니다.
public static void ChangeScene(string scnename, int doornum)
{
doorNumber = doornum; //문 번호를 static 변수에 저장
string nowScene = PlayerPrefs.GetString("LastScene");
if (nowScene != "")
{
SaveDataManager.SaveArrangeData(nowScene); // 배치 데이터 저장
}
PlayerPrefs.SetString("LastScene", scnename); // 씬 이름 저장
PlayerPrefs.SetInt("LastDoor", doornum); // 문 번호 저장
ItemKeeper.SaveItem(); // 아이템 저장
SceneManager.LoadScene(scnename); // 씬 이동
}
배치 데이터를 저장하기 위해 씬을 변경하기 전
SaveDataManager클래스의 SaveArrangeData메서드를 호출해 배치 데이터를 저장합니다.
SaveArrangeData메서드에는 PlayerPrefs클래스의 GetString 메서드에 "LastScene"을 키로 전달하면 얻을 수 있는 "현재씬이름"을 사용합니다. 이름이 null이 아니면 SaveDataManager클래스의 SaveArrangeData메서드를 호출해 데이터를 저장합니다.
다음으로 PlayerPrefs클래스의 SetString메서드를 사용해 "LastScene"키로 앞으로 이동할 씬 이름을 저장합니다.
문번호는 PlayerPrefs클래스의 SetStringInt메서드를 사용해 "LastDoor"키로 문 번호를 저장합니다.
씬을 이동할 때 아이템을 저장하는 ItemKeeper클래스의 SaveItem메서드를 호출하면 그 방에서 획득한 아이템을 저장합니다.
게임이어하기 기능 만들기
타이틀 화면의 [CONTINUE]버튼을 누르면 게임을 중간부터 시작할 수 있도록 합니다.
[GAME START]버튼을 누르면 이전 기록을 초기화 하는 처리도 추가합니다. TitleManager 스크립트를 다음과 같이 수정합니다.
변수
public GameObject startButton; //스타트 버튼
public GameObject continueButton; //이어하기 버튼
public string firstSceneName; //게임 시작 씬 이름
Start()
PlayerPrefs "LastScene"키로 가져온 이름이 없다면 [CONTINUE]버튼을 비활성화 합니다. 마지막씬이 있다면 활성화합니다.
public void StartButtonClicked()
{
//저장 데이터를 지움
PlayerPrefs.DeleteAll();
//HP 초기화
PlayerPrefs.SetInt("PlayerHP", 3);
//저장된 스테이지 정보를 지움
PlayerPrefs.SetString("LastScene", firstSceneName); //씬 이름 초기화
RoomManager.doorNumber = 0;
SceneManager.LoadScene(firstSceneName);
}
ContinueButtonClicked()
public void ContinueButtonClicked()
{
string sceneName = PlayerPrefs.GetString("LastScene"); //저장된 씬
RoomManager.doorNumber = PlayerPrefs.GetInt("LastDoor"); //문 번호
SceneManager.LoadScene(sceneName);
}
게임 재시도 처리
UIManager 클래스의 Retry메서드도 UIManager스크립트에서 다음과 같이 수정합니다. Player.Prefs.SetInt로 저장된 플레이어의 HP를 3으로 되돌립니다.
//재시도
public void Retry()
{
//HP 되돌리기
PlayerPrefs.SetInt("PlayerHP", 3);
//게임 중으로 설정
SceneManager.LoadScene(retrySceneName); //씬 이동
}
저장할 수 있는 배치 데이터 만들기
이제 저장할 수 있는 배치 데이터를 만들어 봅시다. 배치할 수 있는 게임 오브젝트는 다음표와 같습니다. 각각 다른 태그가 설정됐으며. 각오브젝트에는 arrangeID라는 Int형 변수를 가지는 스크립트가 어태치됐습니다.
게임오브젝트
태그
arrangeID를 갖는 스크립트
문
Door
Door
아이템
Item
ItemData
보물상자
ItemBox
ItemBox
예를 들어 보물 상자가 두개 배치되었으면 Itembox의 arrangeID에 각각 1이상이고 서로 중복되지 않는 숫자를 설정합니다. 이제 이상태에서 타이틀 화면은 [GAME START]버튼을 클릭해서게임을 시작합니다. 게임중 획득한 아이템이나 열린 문의 정보가 각 씬을 옮겨 다닐 때마다 저장되고 재현됩니다. 타이틀화면으로 돌아가 [CONTINUE] 버튼으로 게임을 시작하면 아이템의 수나 아이템의 배치 상태등 방의 모습이 재현된 상태로 게임이 시작됩니다.
게임 실행하기
실행시 SoundManager관련 에러가 나면 주석처리 해줍니다. SoundManager는 맨 마지막에 만들겁니다.