오늘은 어제에 이어서 Gallery 해금시스템을 만들었다.
저번시간에는 골드메탈님 강의를 옮겨서 만든 초안을 바탕으로 코드를 작성했다.
2023.10.31 - [TIL] - 2023/10/31 TIL
2023/10/31 TIL
먼저 어제 하지 못했던 팀원들 사진을 깔끔하게 정리했다. 팀원들 사진의 사이즈가 재각각이였기 때문에 먼저 이미지 편집 사이트를 이용해 사진을 1대 1 비율로 다 잘라주었다. https://www.iloveimg.
seaweed0201.tistory.com
팀원분중 한분이 갤러리 팝업창 시스템을 구현하셨다.
그 기준에 맞춰서 코드 변형을 진행했다. (chatGPT의 도움을 받아 ㅎ;)
1차 코드 수정
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
using static GalleryBtn;
public class GalleryManager : MonoBehaviour
{
public GameObject[] lockCharacter;
//잠금 되어있는 인물창
public GameObject[] unlockCharacter;
//잠금해제 되어있는 인물창
// 수집여부는 카드 두장 맞는지확인하는거에서 카드가 맞았을때 수집되지않은 카드라면 이펙트뜨고 수집한 카드면 그냥 들어감?
enum Achive { UnlockWoman, UnlockMan }
//일단 실험으로 2가지 인물만 잠금해제 할 수 있도록 함
Achive[] achives;
void Init()
{
PlayerPrefs.SetInt("MyData", 1);
foreach (Achive achive in achives)
{
PlayerPrefs.SetInt(achive.ToString(), 1);
/* 잠금해제하고 싶은 경우 윗줄에서 0을 1로 바꾼 뒤
* edit에서 Clear all PlayerPref를 눌러 초기화한 후 게임을 실행하면 잠금해제
*/
}
}
// 수집여부는 카드 두장 맞는지확인하는거에서 카드가 맞았을때 수집되지않은 카드라면 이펙트뜨고 수집한 카드면 그냥 들어감?
// AudioSource audioSource;
// Animator anim; // 게임매니저 애니메이터
public GameObject popupObj;
GalleryPopup[] galleryPopups; // 팝업창 애니메이터들
/*
* CG 종류만큼 갤러리 버튼 프리팹과 팝업창 프리팹을 컨트롤D로 늘리고 팝업창 내용을 수정해준다.
*
* 팝업창과 버튼 ENUM에도 CG 이름 추가해야함. 나중에 CG 해금여부 읽을때도 필요
*/
void Awake()
{
achives = (Achive[])Enum.GetValues(typeof(Achive));
if (!PlayerPrefs.HasKey("MyData"))
{
Init();
}
// anim = GetComponent<Animator>();
// audioSource = GetComponent<AudioSource>();
}
void Start()
{
UnlockCharacter();
galleryPopups = new GalleryPopup[popupObj.transform.childCount];
for (int i = 0; i < popupObj.transform.childCount; i++)
{
galleryPopups[i] = popupObj.transform.GetChild(i).gameObject.GetComponent<GalleryPopup>();
}
}
void UnlockCharacter()
{
for (int index = 0; index < lockCharacter.Length; index++)
{
string achiveName = achives[index].ToString();
bool isUnlock = PlayerPrefs.GetInt(achiveName, 0) == 1;
// isUnlock = 1 :true
lockCharacter[index].SetActive(!isUnlock);
unlockCharacter[index].SetActive(isUnlock);
}
}
public void PopupOpen(WhoIs name)
// 팝업창열기. 자기 넘버 넣어서 실행. 넘버에맞는 팝업창 오픈.
{
for (int i = 0; i < galleryPopups.Length; i++)
{
if ((int)galleryPopups[i].whoIs == (int)name)
{
galleryPopups[i].Open();
}
}
}
}
중간중간 Gpt의 도움을 받아 작성했기 때문에 어느순간 코드가 너무 복잡해지기도 했고, 스스로 알아보기도 힘들었다.
제일 중요한건, 작동하지 않았다는 것이다.
팀원들의 피드백을 들어보니 gameManager에서 매칭된 카드를 받아오는 함수를 만들면 작동할 수 있을것 같다고 했다.
string myResourceName = gameObject.transform.Find("unlocked").GetComponent<Image>().sprite.name;
Debug.Log(myResourceName);
Debug.Log(PlayerPrefs.HasKey(myResourceName));
팀원중 한분이 참고하라고 주신 코드이다.
myResourceName과 gameManager에서 받아올 코드가 일치하게 되면 디버그창에 그 이름과 Key를 가지고 있는지 나오게 될 것이였다.
2차 코드 수정
using System;
using Unity.Burst.CompilerServices;
using UnityEngine;
using UnityEngine.UI;
using static GalleryManager;
public class GalleryBtn : MonoBehaviour
{
public enum WhoIs
{
팀원1,
팀원2,
팀원3,
팀원4,
팀원5,
냥이
}
WhoIs[] whoIs;
AudioSource audioSource;
GalleryManager galleryManager;
public GameObject LockCard; // Lock 이미지
public GameObject UnLockCard; // UnLock 이미지
Button btn; // 버튼 컴포넌트
void Awake()
{
btn = GetComponent<Button>();
galleryManager = FindObjectOfType<GalleryManager>();
}
whoIs = (WhoIs[])Enum.GetValues(typeof(WhoIs));
if (!PlayerPrefs.HasKey("MyData"))
Init();
}
void Init()
{
PlayerPrefs.SetInt("MyData", 1);
foreach (WhoIs card in whoIs)
{
PlayerPrefs.SetInt(card.ToString() + "IsGet", 0);
}
}
private void OnEnable()
{
int isCardGet = PlayerPrefs.GetInt(gameObject.name + "IsGet", 0);
if (isCardGet != 0)
{
btn.interactable = true; // 버튼을 상호 작용 가능하게 설정
LockCard.SetActive(false); // Lock 이미지를 비활성화
UnLockCard.SetActive(true); // UnLock 이미지를 활성화
}
else
{
btn.interactable = false; // 버튼을 상호 작용 불가능하게 설정
LockCard.SetActive(true); // Lock 이미지를 활성화
UnLockCard.SetActive(false); // UnLock 이미지를 비활성화
}
}
public void Click()
{
if (audioSource != null)
audioSource.Play();
int whoIsIndex = Array.IndexOf(whoIs, (WhoIs)Enum.Parse(typeof(WhoIs), gameObject.name));
galleryManager.PopupOpen(whoIsIndex);
PlayerPrefs.SetInt(gameObject.name + "IsGet", 1);
PlayerPrefs.Save();
}
}
2차 코딩 수정본이다. 일단 gallerymanager에서 galleryBtn으로 넘어가서 버튼을 누를때 판단이 일어나도록 했다.
판단하는 김에, 이미지 버튼 상호작용도 연관시켜서 버튼 클릭 가능여부와 이미지 활성화를 동시에 시켰다.
여전히 gameManager에서 이미지 이름을 받아오지는 못하는 모습이다.
그 후 enum을 통해 모든 인물의 조건을 만들었다.
enum Achive { UnlockFirst, UnlockSecond, UnlockThird, UnlockFourth, UnlockFifth, UnlockSixth }
Achive[] achives;
이 조건을 각각 이룰 수 있는 함수 역시 만들었다.
3차 코드 수정본(일부)
void LateUpdate()
{
foreach (Achive achive in achives)
{
CheckAchive(achive);
}
}
void CheckAchive(Achive achive)
{
bool isAchive = false;
GameObject[] LockCardImage;
FirstCardImage = PlayerPrefs.GetString("Canvas/Scroll view/Viewpoint/Content/Gallery");
LockCardImage = GameObject.FindGameObjectsWithTag("GalleryBtn");
switch (achive)
{
case Achive.UnlockFirst:
isAchive = false; // 초기화
foreach (GameObject cardImage in LockCardImage)
{
if (cardImage.name == FirstCardImage)
{
isAchive = true;
break;
}
}
break;
case Achive.UnlockSecond:
isAchive = false; // 초기화
foreach (GameObject cardImage in LockCardImage)
{
if (cardImage.name == SecondCardImage)
{
isAchive = true;
break;
}
}
break;
case Achive.UnlockThird:
isAchive = false; // 초기화
foreach (GameObject cardImage in LockCardImage)
{
if (cardImage.name == ThirdCardImage)
{
isAchive = true;
break;
}
}
break;
case Achive.UnlockFourth:
isAchive = false; // 초기화
foreach (GameObject cardImage in LockCardImage)
{
if (cardImage.name == FourthCardImage)
{
isAchive = true;
break;
}
}
break;
case Achive.UnlockFifth:
isAchive = false; // 초기화
foreach (GameObject cardImage in LockCardImage)
{
if (cardImage.name == FifthCardImage)
{
isAchive = true;
break;
}
}
break;
case Achive.UnlockSixth:
isAchive = false; // 초기화
foreach (GameObject cardImage in LockCardImage)
{
if (cardImage.name == SixthCardImage)
{
isAchive = true;
break;
}
}
break;
}
if (isAchive && PlayerPrefs.GetInt(achive.ToString()) == 0)
{
PlayerPrefs.SetInt(achive.ToString(), 1);
}
}
enum과 PlayerPrefs에 고통받고 있던 와중 팀원중 한분이 코드를 완벽하게 수정해주었다.
GalleryManager 코드(일부)
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GalleryManager : MonoBehaviour
{
public enum WhoIs
{
팀원1,
팀원2,
팀원3,
팀원4,
팀원5,
냥이
}
public Sprite[] firstKey;
public Sprite[] secondKey;
public Sprite[] thirdKey;
public Sprite[] fourthKey;
public Sprite[] fifthKey;
public Sprite[] sixthKey;
public Sprite[] faces; // enum의 순서대로 프사를 넣어주세요.
public string[] tmis; // enum의 순서대로 설명을 적어주세요.
void Awake()
{
profile = new Dictionary<int, ProfileSetting>();
for (int i = 0; i < Enum.GetValues(typeof(WhoIs)).Length; i++)
{
profile.Add(i, new ProfileSetting(((WhoIs)(i)).ToString(), faces[i], tmis[i]));
}
}
}
GalleryBtn 스크립트 코드
using System;
using UnityEngine;
using UnityEngine.UI;
public class GalleryBtn : MonoBehaviour
{
GalleryManager.WhoIs whoIs;
public enum Achives
{
UnlockFirst,
UnlockSecond,
UnlockThird,
UnlockFourth,
UnlockFifth,
UnlockSixth
}
public Achives achive; //업적이름 인스펙터에서 선택해주세요
Sprite[] myKey;
AudioSource audioSource;
GalleryManager galleryManager;
public GameObject lockCard; // Lock 이미지
Button btn; // 버튼 컴포넌트
void Awake()
{
btn = GetComponent<Button>();
}
void Start()
{
galleryManager = FindObjectOfType<GalleryManager>();
lockCard.SetActive(true);
btn.interactable = false;
Init();
Set(achive);
}
void Init()
{
switch (achive)
{
case Achives.UnlockFirst:
//myKey = new Sprite[galleryManager.firstKey.Length];
myKey = galleryManager.firstKey;
break;
case Achives.UnlockSecond:
// myKey = new Sprite[galleryManager.secondKey.Length];
myKey = galleryManager.secondKey;
break;
case Achives.UnlockThird:
// myKey = new Sprite[galleryManager.thirdKey.Length];
myKey = galleryManager.thirdKey;
break;
case Achives.UnlockFourth:
// myKey = new Sprite[galleryManager.fourthKey.Length];
myKey = galleryManager.fourthKey;
break;
case Achives.UnlockFifth:
// myKey = new Sprite[galleryManager.fifthKey.Length];
myKey = galleryManager.fifthKey;
break;
case Achives.UnlockSixth:
//myKey = new Sprite[galleryManager.sixthKey.Length];
myKey = galleryManager.sixthKey;
break;
default:
Debug.Log("버그입니다!");
break;
}
}
void Set(Achives ach)
{
for (int i = 0; i < myKey.Length; i++)
{
if (!PlayerPrefs.HasKey(myKey[i].name)) // 플레이어프리프에 하나라도 안본 내사진이있다면 버튼 안열림
{
return;
}
}
lockCard.SetActive(false);
btn.interactable = true;
}
public void Click()
{
if (audioSource != null)
audioSource.Play();
galleryManager.PopupOpen((int)achive);
}
}
일단 오늘로써는 어떻게 이루어지는건지 이해하기엔 힘들 것 같다. 다음에 관련 함수들을 더 공부해보고 와야 할듯 하다.
팀원의 아이디어로 게임속의 게임을 만들어 보았다.
원래 우리가 만들던 게임은 카드 뒤집기 게임인데
비어있는 시작화면을 꾸미다가 일이 커졌다.
이게 더 재밌는건 비밀
게임이 시작하면 화살이 쏟아지는데
화살을 맞고 죽어도 죽는 모션이 없어서 심심해 보였다. 그래서 애니메이션으로 죽는 모션을 만들어주었다.
애니메이션을 새로 만들어주고 더블클릭하면 이런 화면이 뜬다.
애니메이션을 집어넣을 GameObject를 선택해주면 Animation창에 preview옆에 녹화버튼에 불이 들어온다.
녹화버튼을 누르고 원하는 시간에 색을 붉게 바꿔주고 Rotation을 90도로 설정해주면 애니메이션이 완성된다.
그 다음 Animator창에서 Parameters를 누르고 +버튼을 눌러서 bool값을 추가해준다. 이름은 isDie로 한다.
그 다음 animator에 생성된 die라는 state에 우클릭을 해 transition을 하나 만들어준다.
만들어진 transition(화살표)를 클릭하면 inspector 창이 하나 뜨는데
Has Exit Time은 체크 해제를 한다.( 그래야 딜레이가 없다.)
+를 눌러 Conditions를 하나 추가하고 Die, true를 선택한다.
Script를 하나 만든 후 원하는 GameObject에 넣어준다.
Script에는 다음 코드들을 넣어준다.
public Animator anim;
void start()
{
anim = GetComponent<Animator>();
}
public void Dead()
{
anim.SetBool("isDie", true);
Invoke("timeStop", 0.5f);
}
void timeStop()
{
Time.timeScale = 0.0f;
}
Dead() 라는 함수가 발동되면 isDie가 true로 변하고 애니메이션이 재생된다.
애니메이션이 재생될 수 있도록 Invoke를 이용해 0.5초 뒤에 시간을 멈춘다.
Dead함수는 if문을 써서 완성하면 끝!
그러면 이렇게 죽는 모션이 나온다. 색만 대충 바꾼거여서 좀 어색해보이긴 한다.
오늘 하루 대부분을 GalleryBtn을 수정하는데 쏟느라 뭔가 성취한 느낌이 들지 않는다.
이제 이 코드들을 이해하기 시작하면 게임개발자로써도 한발자국 나아갈 수 있을 것 같다.
'TIL' 카테고리의 다른 글
2023/11/06 TIL (0) | 2023.11.06 |
---|---|
2023/11/03 TIL (1) | 2023.11.03 |
2023/11/02 TIL (1) | 2023.11.02 |
2023/10/31 TIL (0) | 2023.10.31 |
2023/10/30 TIL (0) | 2023.10.30 |