0. 들어가기 전에
점토 구매 UI 창과 저장 로직을 수정했다. 옵션 판넬에 돌아가기와 나가기 버튼을 만들었다. 돌아가기 버튼과 나가기 버튼에 현재 게임 데이터를 저장하는 메서드를 연결했다.
1. 게임 오브젝트
이번에 추가한 게임 오브젝트는 OptionPanelParent, Save Button, Exit Button 이 있다.
1.1 OptionPanelParent
OptionPanelParent 를 추가한 이유는 다음과 같다.
비활성화된 게임 오브젝트는 Find 메서드로 찾을 수 없기 때문에 활성화된 부모 오브젝트에 OptionPanel 을 넣었다.
Find 로 OptionPanelParent 를 먼저 찾고 이어서 계속 Find 를 쓰면 최종적으로 Option Panel 을 찾을 수 있다.
1.2 Save Button
Save Button 을 추가한 이유는 다음과 같다.
옵션 버튼을 누르면 옵션 판넬이 뜨는데 판넬에는 돌아가기 버튼과 나가기 버튼이 있다.
돌아가기 버튼을 누르면 저장이 되면서 다시 게임 화면으로 돌아갈 수 있도록 했다.
1.3 Exit Button
Exit Button 을 추가한 이유는 다음과 같다.
나가기 버튼을 누르면 게임 데이터를 저장하고 게임을 종료할 수 있도록 하기 위함이다.
2. 스크립트
이번에는 추가한 스크립트는 없고 수정만 했다. 수정한 스크립트는 PoolManager, DataManager, GameManager, ClayPanel, ButtonMove 가 있다.
2.1 PoolManager 스크립트
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PoolManager : MonoBehaviour
{
[Header("Clay Info")]
public GameObject[] clayPrefabs;
[Header("Clay Pool")]
public List<GameObject>[] pools;
[Header("Clay Spawn")]
public GameObject spawnPoint; // 중앙에서 스폰될 것..
[Header("Clay Sell")]
public Clay curClay; // 현재 클릭된 대상 클레이
public bool isSellZone; // 판매 버톤에 들어가있는지 확인용
public bool isPossibleSell; // 이 값이 true 면 팔아!
public delegate void SellClayHandler();
public event SellClayHandler OnSellClay;
private void Awake()
{
pools = new List<GameObject>[clayPrefabs.Length];
for (int index = 0; index < pools.Length; index++)
pools[index] = new List<GameObject>();
}
private void Start()
{
for (int index=0; index<DataManager.instance.data.clayInfos.Count; index++)
{
ClayDatas tmpData = DataManager.instance.data.clayInfos[index];
int idx = tmpData.clayIdx;
int level = tmpData.clayLevel;
int cnt = tmpData.curTouchCnt;
GetGameObject(index).GetComponent<Clay>().ResetInfo(level, cnt); // 점토 정보 설정
}
// 중복 연결 막기 위해서 미리 뺐다가 다시 더하기
// - 는 연결되어 있지 않아도 에러 발생시키지 않음.
DataManager.instance.OnSave -= SetSaveClayData;
DataManager.instance.OnSave += SetSaveClayData;
}
public void TrySellClay()
{
if (isPossibleSell)
{
isPossibleSell = false; // 상태 초기화
OnSellClay?.Invoke(); // 이벤트 호출
}
}
public GameObject GetGameObject(int index)
{
GameObject select = null;
foreach (GameObject gameObj in pools[index])
{
// 풀을 돌면서 놀고 있는 게임 오브젝트 찾기
if (gameObj.activeSelf == false)
{
// 찾으면 반환
select = gameObj;
ActivateClay(select);
break;
}
}
// 놀고 있는 게임 오브젝트가 없다면..
if (!select)
{
// 새로 생성해서 반환..
// 새로 생성한 게임 오브젝트는 풀 매니저 하위에 놓을 것.. 그래서 부모에 transform 넣어줌..
select = Instantiate(clayPrefabs[index], transform);
pools[index].Add(select);
ActivateClay(select);
}
return select;
}
public void ActivateClay(GameObject clay)
{
clay.SetActive(true);
clay.transform.position = spawnPoint.transform.position; // 점토의 위치를 중앙으로..
clay.GetComponent<Clay>().ResetInfo(); // 점토 상태 초기화시키기..
}
public void ReturnToPool(GameObject clay)
{
clay.SetActive(false);
}
// 점토 데이터를 저장할 것(활성돠 된 점토만..)
public void SetSaveClayData()
{
// 프리팹 사이즈만큼 점토 정보 저장할 리스트 만들기
DataManager.instance.data.clayInfos = new List<ClayDatas>();
for (int index = 0; index < pools.Length; index++)
{
foreach (GameObject gameObj in pools[index])
{
// 풀을 돌면서 활성화 되어 있는 애들만 저장
if (gameObject.activeSelf == true)
{
// 저장할 내용 만들기
ClayDatas clayData = new ClayDatas();
Clay tmpClay = gameObj.GetComponent<Clay>();
clayData.clayIdx = tmpClay.clayIdx;
clayData.clayLevel = tmpClay.clayLevel;
clayData.curTouchCnt = tmpClay.curTouchCnt;
DataManager.instance.data.clayInfos.Add(clayData); // 리스트에 추가하기
}
}
}
}
}
2.2 PoolManager 스크립트 변경사항 설명
1. Start()
DataManager 에는 OnSave 라는 델리게이트가 있다. 저장할 데이터 정보를 세팅할 때 이를 이용해서 한 번에 여러 메서드를 호출할 수 있도록 한다.
PoolManager 에서는 OnSave 에 기존에 만들었던 SetSaveClayData 메서드(원래는 이름이 SaveClayData 였다) 를 연결했다.
// 중복 연결 막기 위해서 미리 뺐다가 다시 더하기
// - 는 연결되어 있지 않아도 에러 발생시키지 않음.
DataManager.instance.OnSave -= SetSaveClayData;
DataManager.instance.OnSave += SetSaveClayData;
2. SetSaveClayData()
메서드의 마지막에 원래는 DataManager 의 SaveData 메서드를 직접 호출했는데 그 코드를 제거했다. 왜냐하면 이제 데이터를 저장할 땐 DataManager 의 OnSave 를 이용해서 직접 저장할 것이기 때문이다.
// 점토 데이터를 저장할 것(활성돠 된 점토만..)
public void SetSaveClayData()
{
// 프리팹 사이즈만큼 점토 정보 저장할 리스트 만들기
DataManager.instance.data.clayInfos = new List<ClayDatas>();
for (int index = 0; index < pools.Length; index++)
{
foreach (GameObject gameObj in pools[index])
{
// 풀을 돌면서 활성화 되어 있는 애들만 저장
if (gameObject.activeSelf == true)
{
// 저장할 내용 만들기
ClayDatas clayData = new ClayDatas();
Clay tmpClay = gameObj.GetComponent<Clay>();
clayData.clayIdx = tmpClay.clayIdx;
clayData.clayLevel = tmpClay.clayLevel;
clayData.curTouchCnt = tmpClay.curTouchCnt;
DataManager.instance.data.clayInfos.Add(clayData); // 리스트에 추가하기
}
}
}
}
2.3 DataManager 스크립트
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
public class DataManager : MonoBehaviour
{
[Header("Data Manager")]
public static DataManager instance;
[Header("Save Datas")]
string GameDataFileName = "GameData.json";
public Datas data = new Datas(); // 저장용 클래스 변수
public delegate void SaveDataHandler(); // 데이터 저장 관리
public event SaveDataHandler OnSave;
[Header("Save Button")]
public Button saveButton; // 얘는 게임 시작할 때랑, 다른 씬에서 돌아올 때마다 값 할당해줘야함.
private void Awake()
{
// 싱글톤 이용
if (instance != null && instance != this)
{
// 만약 이미 존재하면 그냥 없애
Destroy(gameObject);
return;
}
instance = this;
DontDestroyOnLoad(gameObject); // 얘는 다른 씬으로 전환되어도 안 없앨 거임
// 일단 맨 처음엔 null 로 설정..
data.unlockClays = null;
data.catchClays = null;
LoadGameData(); // 게임 데이터 가져오기
}
private void Start()
{
saveButton = GameObject.Find("OptionPanelParent").transform.Find("Option Panel").transform.Find("Image").transform.Find("Save Button").GetComponent<Button>(); // 버튼 찾아서 할당
saveButton.onClick.AddListener(SaveGameData); // 데이터 저장 메서드 연결
}
// 불러오기
public void LoadGameData()
{
string filePath = Application.persistentDataPath + "/" + GameDataFileName;
// 저장된 게임이 있다면
if (File.Exists(filePath))
{
// 저장된 파일 읽어오고 Json 을 클래스 형식으로 전환해서 할당
string FromJsonData = File.ReadAllText(filePath);
print(FromJsonData);
data = JsonUtility.FromJson<Datas>(FromJsonData);
print("불러오기 완료");
}
}
// 저장하기
public void SaveGameData()
{
OnSave?.Invoke(); // OnSave 에 연결된 메서드 모두 실행
// 클래스를 Json 형식으로 변환(true: 가독성 좋게 작성)
string ToJsonData = JsonUtility.ToJson(data, true);
Debug.Log(ToJsonData + "저장할건디용");
string filePath = Application.persistentDataPath + "/" + GameDataFileName;
// 이미 저장된 파일이 있다면 덮어쓰고, 없다면 새로 만들어서 저장
File.WriteAllText(filePath, ToJsonData);
// 올바르게 저장됐는지 확인
print("저장완료");
}
}
2.4 DataManager 스크립트 변경사항 설명
1. 변수
다음과 같은 변수가 추가되었다.
일단 여러 메서드를 연결하기 위해 OnSave 라는 이름의 델리게이트를 하나 선언했다. 이는 데이터를 저장할 때 이용할 것이다.
그리고 옵션 판넬에 존재하는 돌아가기 버튼을 할당하기 위한 saveButton 을 선언했다.
public delegate void SaveDataHandler(); // 데이터 저장 관리
public event SaveDataHandler OnSave;
[Header("Save Button")]
public Button saveButton; // 얘는 게임 시작할 때랑, 다른 씬에서 돌아올 때마다 값 할당해줘야함.
2. Awake()
일단 저장된 데이터를 불러오기 전에는 data.unlockClays 와 data.catchClays 의 값을 null 로 설정해줬다.
그 후 LoadGameData() 를 호출해서 data 에 새로 데이터를 할당했다.
// 일단 맨 처음엔 null 로 설정..
data.unlockClays = null;
data.catchClays = null;
LoadGameData(); // 게임 데이터 가져오기
3. Start()
게임 월드에 존재하는 돌아가기 버튼을 찾기 위해 Find 메서드를 이용했다. 비활성화된 게임오브젝트는 직접적으로 Find 메서드를 써서 찾을 수 없고, 활성화된 부모 오브젝트를 먼저 찾은 다음 Find 메서드를 통해 찾기가 가능하다.
그래서 Save Button 까지 차례로 Find 메서드를 이용했다. 찾아서 값을 할당한 다음에는 버튼에 데이터 저장 메서드를 연결했다. 이제 이 버튼을 누르면 게임 데이터가 저장되도록 했다.
private void Start()
{
saveButton = GameObject.Find("OptionPanelParent").transform.Find("Option Panel").transform.Find("Image").transform.Find("Save Button").GetComponent<Button>(); // 버튼 찾아서 할당
saveButton.onClick.AddListener(SaveGameData); // 데이터 저장 메서드 연결
}
4. SaveGameData()
아래와 같은 구문이 추가되었다. OnSave 에 연결된 메서드를 모두 실행하도록 했다. OnSave 에는 저장할 데이터의 정보를 지정하는 메서드들이 연결되어 있다.
OnSave?.Invoke(); // OnSave 에 연결된 메서드 모두 실행
2.5 GameManager 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
[Header("Game Data")]
public float love; // 애정
public float gold; // 골드
public bool[] unLockedClays; // 점토들의 해금 여부
public bool[] catchedClays; // 야생에서 잡아왔는지 확인용
[Header("Game Manager")]
public static GameManager instance; // 싱글톤 이용하기 위함
[Header("GameDataUI")]
public GameDataUIController gameDataUI;
[Header("Pool Manager")]
public PoolManager poolManager;
[Header("Coroutine")]
public Coroutine updateTextUICoroutine;
[Header("Game Exit")]
public Button gameExitButton;
private void Awake()
{
// 싱글톤 패턴
if (instance != null && instance != this)
{
// 이미 존재하면 새로 만든거 없애
Destroy(gameObject);
return;
}
instance = this;
DontDestroyOnLoad(gameObject); // 얘는 다른 씬으로 전환되어도 안 없앨 거임
poolManager = GameObject.Find("PoolManager").GetComponent<PoolManager>(); // 풀매니저 찾아서 할당
}
void Start()
{
gameExitButton = GameObject.Find("OptionPanelParent").transform.Find("Option Panel").transform.Find("Image").transform.Find("Exit Button").GetComponent<Button>();
gameExitButton.onClick.AddListener(DataManager.instance.SaveGameData); // 게임 데이터 저장 메서드 연결
gameExitButton.onClick.AddListener(GameExit); // 게임 종료 메서드 연결
GetLove(0);
GetGold(1000);
// 저장된 게임 데이터가 있는 경우 데이터 가져와서 반영
if (DataManager.instance.data.unlockClays != null)
{
// 저장된 데이터 반영해서 가져오기
for (int i = 0; i < unLockedClays.Length; i++)
{
unLockedClays[i] = DataManager.instance.data.unlockClays[i];
catchedClays[i] = DataManager.instance.data.catchClays[i];
}
}
// 메서드 연결하기
DataManager.instance.OnSave -= SetSaveData; // 중복 방지하기 위해 먼저 빼줌
DataManager.instance.OnSave += SetSaveData;
}
// 재화 얻는 함수
public void GetGold(float capacity)
{
// 이미 코루틴이 종료되지 않은 중에 동일한게 또 들어오면 겹쳐서 반영이 돼서 이상하게 될 수 있으므로 null 인지 판단해야함.
if (updateTextUICoroutine != null)
{
StopCoroutine(updateTextUICoroutine);
}
updateTextUICoroutine = StartCoroutine(gameDataUI.UpdateTextUI("gold", gold + capacity, gold));
gold += capacity;
//PlayerPrefs.SetFloat("Gold", gold); // 데이터 저장
}
public void GetLove(float capacity)
{
// 이미 코루틴이 종료되지 않은 중에 동일한게 또 들어오면 겹쳐서 반영이 돼서 이상하게 될 수 있으므로 null 인지 판단해야함.
if (updateTextUICoroutine != null)
{
StopCoroutine(updateTextUICoroutine);
}
updateTextUICoroutine = StartCoroutine(gameDataUI.UpdateTextUI("love", love + capacity, love));
love += capacity;
//PlayerPrefs.SetFloat("Love", love); // 데이터 저장
}
public void SetSaveData()
{
int size = unLockedClays.Length;
DataManager.instance.data.unlockClays = new List<bool>();
DataManager.instance.data.catchClays = new List<bool>();
for (int i=0; i<size; i++)
{
DataManager.instance.data.unlockClays.Add(unLockedClays[i]); // 해금 여부 저장
DataManager.instance.data.catchClays.Add(catchedClays[i]); // 포획 여부 저장
}
}
public void GameExit()
{
// 게임 종료
Application.Quit();
}
}
2.6 GameManager 스크립트 변경사항 설명
1. 변수
다음과 같이 변수가 추가되었다. catchedClays 는 야생에서 점토를 잡아왔는지 여부를 확인하기 위해 선언했다. 야생에서 점토를 잡아오면 해당 인덱스 값이 true 가 되고, 이 값이 true 가 되면 점토 구매 창에서 해금하기 버튼이 활성화된다.
public bool[] catchedClays; // 야생에서 잡아왔는지 확인용
[Header("Game Exit")]
public Button gameExitButton;
2. Start()
나가기 버튼을 찾고, 나가기 버튼에 게임 데이터 저장 메서드와 게임 종료 메서드를 연결하는 구문을 추가했다.
그리고 DataManager 의 OnSave 델리게이트에 SetSaveData 메서드를 연결했다.
void Start()
{
gameExitButton = GameObject.Find("OptionPanelParent").transform.Find("Option Panel").transform.Find("Image").transform.Find("Exit Button").GetComponent<Button>();
gameExitButton.onClick.AddListener(DataManager.instance.SaveGameData); // 게임 데이터 저장 메서드 연결
gameExitButton.onClick.AddListener(GameExit); // 게임 종료 메서드 연결
GetLove(0);
GetGold(1000);
// 저장된 게임 데이터가 있는 경우 데이터 가져와서 반영
if (DataManager.instance.data.unlockClays != null)
{
// 저장된 데이터 반영해서 가져오기
for (int i = 0; i < unLockedClays.Length; i++)
{
unLockedClays[i] = DataManager.instance.data.unlockClays[i];
catchedClays[i] = DataManager.instance.data.catchClays[i];
}
}
// 메서드 연결하기
DataManager.instance.OnSave -= SetSaveData; // 중복 방지하기 위해 먼저 빼줌
DataManager.instance.OnSave += SetSaveData;
}
3. SetSaveData()
저장할 데이터의 정보를 세팅하는 메서드이다. 해금 여부와 포획 여부 정보를 세팅한다.
public void SetSaveData()
{
int size = unLockedClays.Length;
DataManager.instance.data.unlockClays = new List<bool>();
DataManager.instance.data.catchClays = new List<bool>();
for (int i=0; i<size; i++)
{
DataManager.instance.data.unlockClays.Add(unLockedClays[i]); // 해금 여부 저장
DataManager.instance.data.catchClays.Add(catchedClays[i]); // 포획 여부 저장
}
}
4. GameExit()
게임을 종료하는 메서드이다.
public void GameExit()
{
// 게임 종료
Application.Quit();
}
2.7 ClayPanel 스크립트
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;
public class ClayPanel : MonoBehaviour
{
[Header("UI")]
public Button pageLeftButton; // 페이지 왼쪽 버튼
public Button pageRightButton; // 페이지 오른쪽 버튼
public Button buyClayButton; // 점토 구매 버튼
public Button unlockClayButton; // 점토 해금 버튼
public Image lockedImage; // 잠금된 점토 이미지
public Image clayImage; // 점토 이미지
public Text clayName; // 점토 이름
public Text buyPrice; // 점토 가격
public GameObject lockedPage; // 잠금 페이지
[Header("Control")]
public int pageIdx = 0; // 페이지 인덱스
public int maxIdx;
public int minIdx = 0;
private void Start()
{
maxIdx = GameManager.instance.poolManager.clayPrefabs.Length;
pageLeftButton.onClick.AddListener(DownPageIdx);
pageLeftButton.onClick.AddListener(SetClayPanel);
pageRightButton.onClick.AddListener(UpPageIdx);
pageRightButton.onClick.AddListener(SetClayPanel);
}
private void OnEnable()
{
// 활성화 될 때 호출되는 함수
ResetClayPanel();
}
public void ResetClayPanel()
{
pageIdx = 0;
unlockClayButton.onClick.AddListener(() => Unlock(pageIdx)); // Unlock 메서드 추가
}
public void SetClayPanel()
{
Clay clay = GameManager.instance.poolManager.clayPrefabs[pageIdx].GetComponent<Clay>();
if (GameManager.instance.unLockedClays[pageIdx] == false)
{
lockedPage.SetActive(true); // 해금이 안된 경우엔 잠금 판넬 활성화..
}
else
{
lockedPage.SetActive(false); // 해금된 경우엔 잠금 판넬 비활성화..
}
// 페이지 인덱스에 맞게 설정
lockedImage.sprite = clay.clay; // 점토의 이미지 가져오기
clayImage.sprite = clay.clay;
clayName.text = clay.clayName; // 점토 이름 가져오기
buyPrice.text = clay.buyPrice + ""; // 점토 가격 가져오기
}
public void UpPageIdx()
{
if (pageIdx >= maxIdx - 1) return; // 빠져나가기..
pageIdx++;
SetButtonInfo();
}
public void DownPageIdx()
{
if (pageIdx <= 0) return; // 빠져나가기..
pageIdx--;
SetButtonInfo();
}
private void SetButtonInfo()
{
ColorBlock col = unlockClayButton.colors;
// 만약 야생에서 점토를 잡아왔으면 해금하기 버튼 노란색으로 바꿔주기
if (GameManager.instance.catchedClays[pageIdx])
{
col.normalColor = new Color32(255, 220, 90, 255); // 노란색
col.highlightedColor = new Color32(255, 220, 90, 255); // 노란색
unlockClayButton.colors = col; // 색 만들어 놓은거 할당해주기
}
else
{
col.normalColor = new Color32(255, 255, 255, 255); // 흰색
col.highlightedColor = new Color32(255, 255, 255, 255); // 흰색
unlockClayButton.colors = col; // 색 만들어 놓은거 할당해주기
}
unlockClayButton.onClick.RemoveAllListeners(); // 일단 다 지웡
unlockClayButton.onClick.AddListener(() => Unlock(pageIdx)); // Unlock 메서드 추가
buyClayButton.onClick.RemoveAllListeners(); // 일단 다 지웡
buyClayButton.onClick.AddListener(() => BuyClay(pageIdx)); // BuyClay 메서드 추가
}
public void Unlock(int idx)
{
// 야생에서 아직 안 잡았으면 해금 못하도록..
if (!GameManager.instance.catchedClays[pageIdx])
{
Debug.Log("점토를 야생에서 잡아와야 한다!");
return;
}
GameManager.instance.unLockedClays[idx] = true;
SetClayPanel();
}
public void BuyClay(int idx)
{
int price = GameManager.instance.poolManager.clayPrefabs[idx].GetComponent<Clay>().buyPrice;
// 돈이 충분하면 구매
if (GameManager.instance.gold >= price)
{
GameManager.instance.GetGold(-price);
GameManager.instance.poolManager.GetGameObject(idx); // 동물 get!
}
}
public void ClosePanel()
{
gameObject.SetActive(false); // 활성화 끄기..
}
}
2.8 ClayPanel 스크립트 변경사항 설명
1. SetButtonInfo()
메서드의 내용을 좀 수정했다. 일단 해금하기 버튼이 활성화 되었음을 알리기 위해 해금하기 버튼의 색을 노란색으로 바꿨다.
버튼의 색을 바꾸기 위해서는 ColorBlock 타입의 변수가 필요하다. 해금하기 버튼이 활성화되지 않은 경우에는 흰색, 활성화된 경우에는 노란색으로 설정해줬다.
private void SetButtonInfo()
{
ColorBlock col = unlockClayButton.colors;
// 만약 야생에서 점토를 잡아왔으면 해금하기 버튼 노란색으로 바꿔주기
if (GameManager.instance.catchedClays[pageIdx])
{
col.normalColor = new Color32(255, 220, 90, 255); // 노란색
col.highlightedColor = new Color32(255, 220, 90, 255); // 노란색
unlockClayButton.colors = col; // 색 만들어 놓은거 할당해주기
}
else
{
col.normalColor = new Color32(255, 255, 255, 255); // 흰색
col.highlightedColor = new Color32(255, 255, 255, 255); // 흰색
unlockClayButton.colors = col; // 색 만들어 놓은거 할당해주기
}
unlockClayButton.onClick.RemoveAllListeners(); // 일단 다 지웡
unlockClayButton.onClick.AddListener(() => Unlock(pageIdx)); // Unlock 메서드 추가
buyClayButton.onClick.RemoveAllListeners(); // 일단 다 지웡
buyClayButton.onClick.AddListener(() => BuyClay(pageIdx)); // BuyClay 메서드 추가
}
2. Unlock(int idx)
메서드의 내용을 수정했다. 원래는 해금하기 버튼을 누르면 바로 해금될 수 있도록 했는데 이번에는 야생에서 잡아온 점토만 해금할 수 있도록 했다.
잡아오지 않았는데 해금하기 버튼을 누르면 메서드를 빠져나가도록 했다.
public void Unlock(int idx)
{
// 야생에서 아직 안 잡았으면 해금 못하도록..
if (!GameManager.instance.catchedClays[pageIdx])
{
Debug.Log("점토를 야생에서 잡아와야 한다!");
return;
}
GameManager.instance.unLockedClays[idx] = true;
SetClayPanel();
}
3. ClosePanel()
새로 추가된 메서드이다. 자기 자신의 활성화를 끄는 메서드이다.
public void ClosePanel()
{
gameObject.SetActive(false); // 활성화 끄기..
}
2.9 ButtonMove 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class ButtonMove : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
[Header("Animation")]
Animator anim;
[Header("Sprite")]
public Sprite nonClicked;
public Sprite clicked;
[Header("Button UI")]
public Button uiButton;
public Button[] otherButtons;
[Header("Panel")]
public GameObject panel; // 해당 버튼에 맞는 판넬 게임 오브젝트 할당
[Header("Close Button")]
public Button closeButton;
void Start()
{
anim = GetComponent<Animator>();
uiButton = GetComponent<Button>();
}
public void ButtonMoveStart()
{
// 이미 버튼이 눌려있는 상태에서 마우스를 가져다대면 위아래로 움직이는 모션이 실행되지 않도록..
if (!anim.GetBool("clicked"))
{
anim.SetBool("draged", true); // 값을 true 로 줘서 Draged 애니메이션 실행
}
else
{
// 버튼이 눌린 상태면 버튼으로 마우스 갖다대도 false 로..
anim.SetBool("draged", false);
}
}
public void ButtonMoveEnd()
{
anim.SetBool("draged", false); // 값을 false 로 줘서 Idle 애니메이션 실행
}
public void ButtonClicked()
{
for (int i=0; i<otherButtons.Length; i++)
{
// 자신을 제외한 다른 버튼 모두 끄기
otherButtons[i].GetComponent<ButtonMove>().CloseButton();
if (otherButtons[i].GetComponent<ButtonMove>().panel != null)
{
otherButtons[i].GetComponent<ButtonMove>().panel.GetComponent<Animator>().SetBool("isOpened", false); // 창 닫힘 애니메이션 실행
}
}
uiButton.image.sprite = clicked; // 스프라이트를 click 상태로
if (panel != null)
{
panel.GetComponent<Animator>().SetBool("isOpened", true); // 창 열림 애니메이션 실행
}
anim.SetBool("clicked", true);
anim.SetBool("closed", false);
closeButton.gameObject.SetActive(true); // 클로즈 버튼 활성화
}
// Event Handler 이용
public void OnPointerEnter(PointerEventData eventData)
{
ButtonMoveStart();
}
public void OnPointerExit(PointerEventData eventData)
{
ButtonMoveEnd();
}
public void OnPointerClick(PointerEventData eventData)
{
ButtonClicked();
}
public void ResetButtonSprite()
{
// 버튼 스프라이트를 nonClick 상태로 다시 바꿔주기
uiButton.image.sprite = nonClicked;
anim.SetBool("clicked", false);
anim.SetBool("closed", true);
}
// 자기 자신을 끄는 함수
public void CloseButton()
{
gameObject.GetComponent<ButtonMove>().ResetButtonSprite(); // 버튼 모습 초기화
if (gameObject.GetComponent<ButtonMove>().panel != null)
{
gameObject.GetComponent<ButtonMove>().panel.GetComponent<Animator>().SetBool("isOpened", false); // 창 닫힘 애니메이션 실행
if (gameObject.GetComponent<ButtonMove>().panel.GetComponent<ClayPanel>() != null) // 점토 구매 판넬
gameObject.GetComponent<ButtonMove>().panel.GetComponent<ClayPanel>().ClosePanel(); // 판넬 꺼
}
}
}
2.10 ButtonMove 스크립트 변경사항 설명
1. CloseButton()
메서드를 조금 수정했다. 아래와 같은 코드가 추가되었다. 만약 현재 끄려고 하는 판넬이 점토 구매 판넬이면 ClayPanel 컴포넌트를 찾아서 ClosePanel 메서드를 호출하도록 했다.
if (gameObject.GetComponent<ButtonMove>().panel.GetComponent<ClayPanel>() != null) // 점토 구매 판넬
gameObject.GetComponent<ButtonMove>().panel.GetComponent<ClayPanel>().ClosePanel(); // 판넬 꺼
3. 결과물
4. 참고자료
이번엔 좀 찾아본 개념들이 많아서 다 가져왔다. 계속 보면서 복습하면 될 것 같다.
4.1 버튼 색 바꾸기
4.2 델리게이트, Action
유니티 이벤트(Events)와 액션(Action)으로 코드 정리하기 - 기밀문서
[C#] Action과 Func : 미리 정의 된 Delegate : 네이버 블로그
4.3 델리게이트 연결 메서드 중복 막기
C# eventHandler 중복, Action 중복 방지 하기 :: 3DMP
4.4 비활성화 된 게임 오브젝트 찾기
4.5 게임 종료
[Unity3D] 게임 종료 스크립트 : 네이버 블로그
[유니티] 게임 비활성화, 종료 시 처리 - 와상의 야매 개발 블로그
-> 얘는 모바일 게임 만들 때 사용해야 할 것 같다.