0. 들어가기 전에
이번에는 월드 판넬을 제작했다. 본격적으로 야생 콘텐츠를 만들기 전에 야생 씬으로 넘어갈 수 있도록 하는 판넬을 만들어야 하기 때문이다.
1. 게임 오브젝트
이번에 새로 만든 게임 오브젝트는 World Panel 이다.
1.1 World Panel
기존 Canvas1 게임 오브젝트에 자식 오브젝트로 World Panel 을 만들었다.
1. 하이어라키 창

2. 게임 화면 속 모습

3. 인스펙터 창 모습
World Panel 게임 오브젝트는 컴포넌트로 Animator 와 World Panel 을 갖는다.

1.2 World Button
기존 만들어 놓았던 게임 오브젝트이다. 수정한 내역은 다음과 같다.
1. 하이어라키 창 모습

2. 인스펙터 창 모습
기존에 부착해놨던 Button Move 스크립트의 Panel 변수로 새로 만든 World Panel 게임 오브젝트를 할당했다.

1.3 Close Button
기존 만들어 놓았던 게임 오브젝트이다. 수정한 내역은 다음과 같다.
1. 하이어라키 창 모습

2. 인스펙터 창 모습
OnClick() 에 직접 추가했다. 새로 추가한 내역은 사진 속 빨간색 네모 칸에 있는 것이다. Close Button 을 누르면 World Button 의 ButtonMove 컴포넌트의 CloseButton 메서드를 호출할 수 있도록 했다.
즉, 야생 버튼의 스프라이트 상태를 원상태로 돌려놓도록 했다.

2. 스크립트
이번에 새로 만든 스크립트는 WorldPanelClayAnim, WorldPanel 이고 ButtonMove 스크립트를 수정했다.
2.1 WorldPanel 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class WorldPanel : MonoBehaviour
{
[Header("World Panel UI")]
public Button[] worldButtons;
public Text[] worldTexts;
[Header("Prices")]
public int[] worldPrices;
private void Start()
{
SetWorldPanel(); // 버튼 설정
}
public void SetWorldPanel()
{
for (int i=0; i<worldButtons.Length; i++)
{
int price = worldPrices[i];
// 버튼 난이도에 맞는 가격 소모 메서드 할당
worldButtons[i].onClick.AddListener(() => GameManager.instance.GetGold(-price));
// 텍스트에 가격 표시..
worldTexts[i].text = worldPrices[i] + "";
}
}
public void ClosePanel()
{
gameObject.SetActive(false); // 활성화 끄기..
}
}
2.2 WorldPanel 스크립트 설명
1. 변수
선언한 변수는 다음과 같다.
worldButtons 는 월드 판넬의 세 버튼을 넣어놓기 위해 선언한 변수이다. worldTexts 도 같은 맥락이다. worldPrices 는 worldButton 에 GameManager 의 GetGold 메서드를 연결할 때 사용하기 위해 선언했다.
[Header("World Panel UI")]
public Button[] worldButtons;
public Text[] worldTexts;
[Header("Prices")]
public int[] worldPrices;
2. Start()
버튼에 GetGold 메서드를 연결하는 메서드를 Start 에서 호출했다.
private void Start()
{
SetWorldPanel(); // 버튼 설정
}
3. SetWorldPanel()
버튼에 GetGold 메서드를 연결하는 메서드이다. 동시에 텍스트에도 가격을 표시하도록 했다.
일단 야생 씬으로 넘어가는 로직은 추가하지 않았다. 이번엔 정말 버튼을 클릭했을 때 골드가 차감되는 기본적인 동작만 하도록 만들었다.
public void SetWorldPanel()
{
for (int i=0; i<worldButtons.Length; i++)
{
int price = worldPrices[i];
// 버튼 난이도에 맞는 가격 소모 메서드 할당
worldButtons[i].onClick.AddListener(() => GameManager.instance.GetGold(-price));
// 텍스트에 가격 표시..
worldTexts[i].text = worldPrices[i] + "";
}
}
4. ClosePanel()
게임 오브젝트 활성화를 끄도록 하는 메서드이다.
public void ClosePanel()
{
gameObject.SetActive(false); // 활성화 끄기..
}
2.3 WorldPanelClayAnim 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
using UnityEngine.EventSystems;
public class WorldPanelClayAnim : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
[Header("Animation")]
public Animator anim; // 점토 이미지에 마우스 가져다 대면 애니메이션 실행될 수 있도록..
private void Awake()
{
anim = GetComponent<Animator>();
}
public void OnPointerEnter(PointerEventData eventData)
{
// 마우스 포인터가 이미지에 도달하면 자동으로 호출되는 메서드
anim.SetBool("isPointerOn", true);
}
public void OnPointerExit(PointerEventData eventData)
{
// 마우스 포인터가 이미지에서 빠져나가면 자동으로 호출되는 메서드
anim.SetBool("isPointerOn", false);
}
}
2.4 WorldPanelClayAnim 스크립트 설명
1. 변수
월드 판넬 속 점토에 마우스를 가져다 대면 점토의 모습이 계속해서 변하는 애니메이션을 수행할 것이다. 이를 위해 Animator 타입의 변수를 선언했다.
[Header("Animation")]
public Animator anim; // 점토 이미지에 마우스 가져다 대면 애니메이션 실행될 수 있도록..
2. Awake()
anim 에 컴포넌트를 할당해주었다.
private void Awake()
{
anim = GetComponent<Animator>();
}
3. OnPointerEnter(PointerEventData eventData)
isPointerOn 값을 true 로 설정해서 애니메이션이 수행되도록 했다.
public void OnPointerEnter(PointerEventData eventData)
{
// 마우스 포인터가 이미지에 도달하면 자동으로 호출되는 메서드
anim.SetBool("isPointerOn", true);
}
4. OnPointerExit(PointerEventData eventData)
애니메이션을 Idle 상태로 다시 옮겨가도록 하기 위해 isPointerOn 값을 false 로 설정해줬다.
public void OnPointerExit(PointerEventData eventData)
{
// 마우스 포인터가 이미지에서 빠져나가면 자동으로 호출되는 메서드
anim.SetBool("isPointerOn", false);
}
2.5 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(); // 판넬 꺼
else if (gameObject.GetComponent<ButtonMove>().panel.GetComponent<UpgradePanel>() != null) // 업그레이트 판넬
gameObject.GetComponent<ButtonMove>().panel.GetComponent<UpgradePanel>().ClosePanel(); // 판넬 꺼
else if (gameObject.GetComponent<ButtonMove>().panel.GetComponent<WorldPanel>() != null) // 월드 판넬
gameObject.GetComponent<ButtonMove>().panel.GetComponent<WorldPanel>().ClosePanel(); // 판넬 꺼
}
}
}
2.6 ButtonMove 스크립트 변경 사항 설명
1. CloseButton()
기존 메서드에서 월드 판넬을 끄는 로직이 추가되었다.
// 자기 자신을 끄는 함수
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(); // 판넬 꺼
else if (gameObject.GetComponent<ButtonMove>().panel.GetComponent<UpgradePanel>() != null) // 업그레이트 판넬
gameObject.GetComponent<ButtonMove>().panel.GetComponent<UpgradePanel>().ClosePanel(); // 판넬 꺼
else if (gameObject.GetComponent<ButtonMove>().panel.GetComponent<WorldPanel>() != null) // 월드 판넬
gameObject.GetComponent<ButtonMove>().panel.GetComponent<WorldPanel>().ClosePanel(); // 판넬 꺼
}
}
3. 애니메이션 & 애니메이터
이번에 새로 만든 애니메이터와 애니메이션은 다음과 같다.
3.1 WorldPanel 애니메이터, WorldPanelShow, WorldPanelNonShow 애니메이션
WorldPanel 애니메이터는 WorldPanel 의 Animator 컴포넌트 속 Controller 에 부착했다.
1. 애니메이터 상태
isOpened 값이 true 면 Show 애니메이션이 수행되도록, flase 면 NonShow 애니메이션이 수행되도록 했다.

2. 애셋
NonShow 에 WorldPanelNonshow 애니메이션, Show 에 WorldPanelShow 애니메이션을 넣어주었다.

3.2 WorldPanelClayImageAnim
월드 판넬 속 점토 이미지에 애니메이션을 적용하기 위해 만들었다.
1. 애셋

2. 애니메이터 상태
easyButton 컨트롤러를 오버라이딩 한 hardButton, normalButton 컨트롤러가 있다. 즉, 세 개의 컨트롤러 속 상태는 동일하고 각 애니메이션 칸에 포함된 애니메이션만 다르다.
isPointerOn 값이 true 가 되면 PointerOn 으로 상태가 넘어가서 점토가 계속해서 모습을 바꾸는 애니메이션이 수행되도록 했다. false 가 되면 Idle 상태로 가도록 했다.

4. 결과물