0. 들어가기 전에
이번에는 점토 도감을 만들었다.
1. 게임 오브젝트
이번에 새로 만든 게임 오브젝트는 BookCanvas 와 Book Button 이다. BookCanvas 는 자식 오브젝트로 Close Button, Book 을 갖는다.
1.1 Book Button
기존에 만들어두었던 Canvas1 에 자식 오브젝트로 만들었다. 북 버튼을 누르면 북 판넬이 활성화된다.
1. 게임 화면 속 모습
2. 인스펙터 창 모습
Book Button 의 OnClick() 에 연결된 목록은 다음 사진과 같다.
북 버튼을 누르면 BookPanel 과 두 개의 Close Button 이 활성화되도록 했다.
Close Button 중 하나는 책 판넬이 아닌 부분을 클릭하면 판넬이 꺼지도록, 하나는 책 판넬의 닫기 버튼을 클릭하면 판넬이 꺼지도록 하기 위한 게임 오브젝트이다.
1.2 BookCanvas 의 CloseButton
이 게임 오브젝트는 책이 아닌 부분을 클릭했을 때 책 판넬을 끌 수 있도록 하기 위해 만들었다.
1. OnClick()
OnClick() 에 연결된 목록은 다음과 같다. Close Button 을 누르면 Close Button 을 비활성화 하도록 했고, BookController 의 ClosePanel 메서드를 호출하도록 했다.
즉, 책 판넬이 꺼짐과 동시에 Close Button 도 꺼지도록 하는 것이다.
Close Button 은 평상시에 비활성화 되어 있는 상태이고, Book 버튼을 누르면 활성화된다.
1.3 BookCanvas 의 Book
Book 은 자식 오브젝트로 Close Button 과 BookPanel 을 갖는다.
1.4 Book 의 Close Button
1. 게임 화면 속 모습
사진 속 빨간 버튼이 Close Button 이다.
2. 인스펙터 창
OnClick() 에 BookPanel 의 ClosePanel 메서드를 연결했다. 즉, CloseButton 을 클릭하면 BookPanel 이 비활성화 되도록 했다.
1.5 Book 의 BookPanel
BookPanel 은 자식 오브젝트로 ClayGroup 과 InfoGroup 을 갖는다.
1. 인스펙터 창
BookPanel 은 BookController 스크립트를 컴포넌트로 갖는다.
도감의 UI 를 관리하기 위해 스크립트를 부착했다.
2. ClayGroup
Book 의 자식 게임 오브젝트이다. 현재 페이지 인덱스에 맞는 점토의 모습과, 이름을 띄우도록 하기 위해 필요하다. 빨간색 네모 박스 안에 있는 UI 들을 자식 오브젝트로 가지고 있다.
3. InfoGroup
BookPanel 의 자식 게임 오브젝트이다. 현재 페이지 인덱스에 맞는 점토의 정보를 띄우는 역할을 한다. 빨간색 네모 박스 안에 있는 UI 들을 자식 오브젝트로 가지고 있다.
자식 오브젝트들은 비활성화 되어 있는 상태이고, 게임 플레이 중에 스크립트로 활성화 여부를 결정해서 사용할 것이다.
2. 스크립트
이번에 새로 만든 스크립트는 없고 Clay, BookController 스크립트를 수정했다.
2.1 Clay 스크립트
using System.Collections;
using System.Collections.Generic;
using TreeEditor;
using UnityEngine;
public class Clay : MonoBehaviour
{
[Header("Clay Data")]
public float[] loves; // 점토를 클릭했을 때 얻는 애정 수치(1~5 레벨)
public int[] touchCnts; // 해당 요소만큼 클릭되면 레벨업
public int clayLevel = 1; // 1레벨에서 시작(5레벨까지 있음)
public int curTouchCnt = 0;
public int clayIdx; // 점토 소환할 때 필요한 인덱스
public int buyPrice; // 구매 가격
public int sellPrice; // 판매 가격
public string clayName; // 점토 이름
public string clayInfo; // 점토 설명
public int effectIdx = 0;
[Header("Animation")]
Animator anim; // 점토가 터치될 때 애니메이션 실행하기 위함
public RuntimeAnimatorController[] animators;
public float[] claySizes;
[Header("Sprites")]
public Sprite clay; // 점토 모습
public Sprite animal; // 다 자란 동물 모습
public GameObject shadow; // 이거 가구 애니메이션 중일 때는 끄도록..
[Header("Drag Clay")]
public float targetTime = 1; // 드래그 시작할 수 있는 시간
public float curTime; // 현재 시간
public Vector3 prevPos; // 점토를 드래그 하기 전 위치
public bool isDragging; // 드래그 중인지 확인
[Header("Pool Manager")]
public PoolManager poolManager;
[Header("ToyAnimation")]
public bool isUsed; // 이미 사용되고 있는 중이면 클릭 버튼이 안 먹히도록 하는데 이용할 것..
[Header("Light")]
public GameObject clayLight; // 점토 불빛
int cnt = 0;
private void Awake()
{
anim = GetComponent<Animator>();
shadow = transform.GetChild(0).gameObject;
}
private void Start()
{
poolManager = GameObject.Find("PoolManager").GetComponent<PoolManager>();
SetClay(); // 점토 정보 반영 세팅(애니메이션, scale)
}
// 점토가 터치되면 저절로 호출됨
private void OnMouseDown()
{
// toy 애니메이션이 수행되고 있는 중이면 빠져나가도록..
if (isUsed) return;
prevPos = transform.position; // 드래그 하기 전 위치 저장
poolManager.curClay = gameObject.GetComponent<Clay>(); // 현재 선택된 클레이 지정
Debug.Log("터치됨!");
anim.SetTrigger("doTouch");
GameManager.instance.GetLove(loves[clayLevel - 1] * GameManager.instance.clayClickLevel); // 레벨에 맞는 수치를 함수로 넘겨주기
curTouchCnt++;
LevelUpClay();
}
private void LevelUpClay()
{
// 이미 점토의 레벨이 최고 레벨에 도달했으면 밑으로 진입 안 하도록..
if (clayLevel != 5)
{
if (curTouchCnt == touchCnts[clayLevel - 1])
{
clayLevel++; // 레벨 1 증가
curTouchCnt = 0; // 초기화
SetClay(); // 점토 정보 반영 세팅(애니메이션, scale)
PlayEffect(effectIdx);
if (clayLevel == 5)
gameObject.GetComponent<SpriteRenderer>().sprite = animal;
}
}
}
private void PlayEffect(int idx)
{
if (GameManager.instance.effects[idx].gameObject.activeSelf == false)
GameManager.instance.effects[idx].gameObject.SetActive(true); // 활성화하기
GameManager.instance.effects[idx].transform.position = transform.position; // 이펙트 위치를 점토 위치로 바꿔주기
GameManager.instance.effects[idx].Play(); // 실행시키깅
}
// 점토 드래그할 때 호출되는 함수
private void OnMouseDrag()
{
// toy 애니메이션이 수행되고 있는 중이면 빠져나가도록..
if (isUsed) return;
curTime += Time.deltaTime;
isDragging = true;
// 만약 현재 시간이 targetTime 보다 크거나 같다면 점토가 마우스를 따라오도록 하기..
if (curTime >= targetTime)
{
// 불 켜는 건 한번만 수행할 수 있도록..
if (cnt == 0)
{
cnt++;
SetLight(); // 점토의 빛 켜주기.. UI 꺼주기, local light 켜주기
}
// 마우스 위치를 가져온 후 Z 축을 카메라와의 거리로 설정한다
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = Camera.main.WorldToScreenPoint(transform.position).z;
// 스크린 좌표를 월드 좌표로 변환
Vector3 worldPosition = Camera.main.ScreenToWorldPoint(mousePosition);
// 오브젝트의 위치를 마우스의 월드 좌표로 이동
transform.position = worldPosition;
// 이 경우에는 UI 보다도 앞에 갈 수 있도록..
gameObject.GetComponent<SpriteRenderer>().sortingOrder = 10;
}
}
// 점토 내려놓을 때 호출되는 함수
private void OnMouseUp()
{
// toy 애니메이션이 수행되고 있는 중이면 빠져나가도록..
if (isUsed) return;
cnt = 0; // 다시 0으로 돌려놓기..
curTime = 0;
isDragging = false;
SetLight(); // 점토의 빛 꺼주기.. UI 켜주기, local Light 꺼주기..
if (transform.position.x < -6.5 || transform.position.x > 6.5 || transform.position.y < -3 || transform.position.y > 0.6)
transform.position = prevPos;
// 다시 UI 보다 아래로 가도록..
gameObject.GetComponent<SpriteRenderer>().sortingOrder = -1;
if (poolManager.isSellZone == true)
{
poolManager.isPossibleSell = true; // 판매 신호 주기
poolManager.TrySellClay(); // 이벤트 호출
}
if (GameManager.instance.curToyIdx != -1)
StartToyAnim(GameManager.instance.curToyIdx); // 가구 애니메이션 수행
}
public void ResetInfo(int level, int cnt)
{
if (level == 5)
gameObject.GetComponent<SpriteRenderer>().sprite = animal; // 동물 모습으로 바꿔주기..
// 점토 정보 설정
clayLevel = level;
curTouchCnt = cnt;
SetClay();
}
public void ResetInfo()
{
// 점토 정보 초기화
clayLevel = 1;
curTouchCnt = 0;
gameObject.GetComponent<SpriteRenderer>().sprite = clay; // 점토 모습으로 바꿔주기..
SetClay();
}
private void SetClay()
{
anim.runtimeAnimatorController = animators[clayLevel - 1]; // 레벨에 맞는 애니메이터로 바꿔주기..
gameObject.transform.localScale = new Vector3(claySizes[clayLevel - 1], claySizes[clayLevel - 1], 0); // 레벨에 맞게 사이즈 설정
// 끄고 다시 켜서 애니메이터에 반영
anim.gameObject.SetActive(false);
anim.gameObject.SetActive(true);
}
public void StartToyAnim(int idx)
{
shadow.SetActive(false); // 그림자 활성화 끄기
Debug.Log("가구 애니메이션 시작했어여!!");
isUsed = true; // 메서드 빠져나갈 때 false 로 다시 설정해주기..
GetComponent<ClayMove>().isToyActioning = true;
// 애니메이션 시작
anim.runtimeAnimatorController = GameManager.instance.clayToyAnimators[idx];
// 코루틴 시작
StartCoroutine(PerformAnimation());
}
private IEnumerator PerformAnimation()
{
float duration = 3f;
yield return new WaitForSeconds(duration);
// 애니메이터 원상태로 돌려놓기
SetClay();
isUsed = false;
GetComponent<ClayMove>().isToyActioning = false;
transform.position = prevPos; // 이전 위치로 돌아가도록..
shadow.SetActive(true); // 그림자 활성화 켜기
Debug.Log("애니메이션 완료!");
}
public void SetLight()
{
// 점토를 들 때 점토의 빛이 켜져야 하므로 isDragging 값을 넘겨줄 것..
clayLight.SetActive(isDragging);
// 점토를 들면 화면 상의 UI 와 local light 이 켜져야 하므로 isDragging 값 넘겾귀
// 점토를 내려놓아도 마찬가지..
GameManager.instance.SetLightAndUI(isDragging);
}
}
2.2 Clay 스크립트 변경 사항 설명
1. 변수
clayInfo 변수를 추가했다. 점토의 정보를 Book Panel 에 띄우기 위해 필요하다.
public string clayInfo; // 점토 설명
2.3 BookController 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class BookController : MonoBehaviour
{
[Header("UI")]
public Button pageLeftButton; // 페이지 왼쪽 버튼
public Button pageRightButton; // 페이지 오른쪽 버튼
public Button closeButton;
public Button subCloseButton;
public Image clayImage; // 점토 이미지
public Text clayName; // 점토 이름
public GameObject infoText; // 점토 설명
public GameObject lockedImage; // 잠금 텍스트 이미지
public GameObject[] otherUIs; // 책 판넬 켜지면 다른 UI 들 다 끄도록..
[Header("Control")]
public int pageIdx;
public int maxIdx;
public int minIdx = 0;
private void Start()
{
maxIdx = GameManager.instance.poolManager.clayPrefabs.Length;
// 버튼에 메세드 연결
pageLeftButton.onClick.AddListener(DownPageIdx);
pageRightButton.onClick.AddListener(UpPageIdx);
}
private void OnEnable()
{
// 활성화 될 때 호출되는 함수
ResetPanel();
for (int i=0; i<otherUIs.Length; i++)
{
otherUIs[i].SetActive(false); // 다른 UI 다 비활성화하기..
}
}
public void SetBookPanel()
{
Clay clay = GameManager.instance.poolManager.clayPrefabs[pageIdx].GetComponent<Clay>();
clayImage.sprite = clay.clay; // 점토의 모습으로 바꿔주기
clayName.text = clay.clayName; // 점토의 이름으로 바꿔주기
infoText.GetComponent<Text>().text = clay.clayInfo; // 점토의 정보로 설정해주기..
// 만약 야생에서 잡아온 점토면 책에 정보가 보이도록..
if (GameManager.instance.catchedClays[pageIdx])
{
Debug.Log("잡혔는디");
clayImage.color = new Color32(255, 255, 255, 255); // 이미지를 잘 보이도록..
infoText.SetActive(true);
lockedImage.SetActive(false);
}
// 안 잡아왔으면 정보 안보이도록..
else
{
Debug.Log("안 잡혔는디");
clayImage.color = new Color32(0, 0, 0, 255); // 이미지를 검정색으로..
clayName.text = "???";
infoText.SetActive(false);
lockedImage.SetActive(true);
}
}
public void UpPageIdx()
{
if (pageIdx >= maxIdx - 1)
{
GameManager.instance.StartInfoPanel("마지막 페이지입니다.");
return; // 빠져나가기..
}
pageIdx++;
SetBookPanel();
}
public void DownPageIdx()
{
if (pageIdx <= 0)
{
GameManager.instance.StartInfoPanel("처음 페이지입니다.");
return; // 빠져나가기..
}
pageIdx--;
SetBookPanel();
}
public void ResetPanel()
{
pageIdx = 0;
SetBookPanel(); // 데이터 반영해서 UI 변경
}
public void ClosePanel()
{
// 활성화 끄기..
gameObject.SetActive(false);
closeButton.gameObject.SetActive(false);
subCloseButton.gameObject.SetActive(false);
for (int i = 0; i < otherUIs.Length; i++)
{
otherUIs[i].SetActive(true); // 다른 UI 다시 다 활성화하기..
}
}
}
2.4 BookController 스크립트 설명
1. 변수
Book Panel 의 UI 를 관리하기 위한 변수들을 선언했다.
[Header("UI")]
public Button pageLeftButton; // 페이지 왼쪽 버튼
public Button pageRightButton; // 페이지 오른쪽 버튼
public Button closeButton;
public Button subCloseButton;
public Image clayImage; // 점토 이미지
public Text clayName; // 점토 이름
public GameObject infoText; // 점토 설명
public GameObject lockedImage; // 잠금 텍스트 이미지
public GameObject[] otherUIs; // 책 판넬 켜지면 다른 UI 들 다 끄도록..
[Header("Control")]
public int pageIdx;
public int maxIdx;
public int minIdx = 0;
2. Start()
maxIdx 값을 설정해주고, 왼쪽, 오른쪽 버튼에 각각 메서드를 연결해주었다.
private void Start()
{
maxIdx = GameManager.instance.poolManager.clayPrefabs.Length;
// 버튼에 메세드 연결
pageLeftButton.onClick.AddListener(DownPageIdx);
pageRightButton.onClick.AddListener(UpPageIdx);
}
3. OnEnable()
게임 오브젝트가 활성화될 때 자동으로 호출되는 메서드이다.
여기서 ResetPanel 메서드를 호출해서 Book Panel 의 상태를 초기화해주고, 도감을 제외한 다른 UI 를 모두 비활성화 하도록 했다.
private void OnEnable()
{
// 활성화 될 때 호출되는 함수
ResetPanel();
for (int i=0; i<otherUIs.Length; i++)
{
otherUIs[i].SetActive(false); // 다른 UI 다 비활성화하기..
}
}
4. SetBookPanel()
Book Panel 의 UI 를 업데이트 하는 메서드이다. 현재 도감의 idx 에 맞게 UI 를 업데이트 하도록 했다.
public void SetBookPanel()
{
Clay clay = GameManager.instance.poolManager.clayPrefabs[pageIdx].GetComponent<Clay>();
clayImage.sprite = clay.clay; // 점토의 모습으로 바꿔주기
clayName.text = clay.clayName; // 점토의 이름으로 바꿔주기
infoText.GetComponent<Text>().text = clay.clayInfo; // 점토의 정보로 설정해주기..
// 만약 야생에서 잡아온 점토면 책에 정보가 보이도록..
if (GameManager.instance.catchedClays[pageIdx])
{
Debug.Log("잡혔는디");
clayImage.color = new Color32(255, 255, 255, 255); // 이미지를 잘 보이도록..
infoText.SetActive(true);
lockedImage.SetActive(false);
}
// 안 잡아왔으면 정보 안보이도록..
else
{
Debug.Log("안 잡혔는디");
clayImage.color = new Color32(0, 0, 0, 255); // 이미지를 검정색으로..
clayName.text = "???";
infoText.SetActive(false);
lockedImage.SetActive(true);
}
}
5. UpPageIdx(), DownPageIdx()
Book Panel 의 왼쪽 버튼, 오른쪽 버튼을 누르면 호출되는 메서드이다.
public void UpPageIdx()
{
if (pageIdx >= maxIdx - 1)
{
GameManager.instance.StartInfoPanel("마지막 페이지입니다.");
return; // 빠져나가기..
}
pageIdx++;
SetBookPanel();
}
public void DownPageIdx()
{
if (pageIdx <= 0)
{
GameManager.instance.StartInfoPanel("처음 페이지입니다.");
return; // 빠져나가기..
}
pageIdx--;
SetBookPanel();
}
6. ResetPanel()
북 판넬을 초기화 하는 메서드이다.
public void ResetPanel()
{
pageIdx = 0;
SetBookPanel(); // 데이터 반영해서 UI 변경
}
7. ClosePanel()
북 판넬을 비활성화 하는 메서드이다.
북 판넬을 켤 때 다른 UI 들을 다 비활성화 했으므로 다시 활성화했다.
public void ClosePanel()
{
// 활성화 끄기..
gameObject.SetActive(false);
closeButton.gameObject.SetActive(false);
subCloseButton.gameObject.SetActive(false);
for (int i = 0; i < otherUIs.Length; i++)
{
otherUIs[i].SetActive(true); // 다른 UI 다시 다 활성화하기..
}
}
3. 결과물