티스토리 뷰
* UIShop 상점 시스템 중 아이템을 구입하는 기능을 구현했다.
먼저 유저가 상점을 이용하려면 어떤 데이터가 있어야하는지 먼저 고민 해야했다.
유저의 현재 골드 보유량, 아이템 마다 정해진 가격(등급에 따라 가격을 나눈 후 데이터 테이블을 만들어놨다)이
먼저 필요했다.
그 후 상점에서 아이템을 구매하였다면 "유저의 현재 보유 금액 - 아이템의 가격" 을 다시 유저의 현재 보유 금액에 저장해야했다. 인포를 관리하기 위해 "PossessionAmount_info" 데이터 테이블을 만들었다. 유저가 보유할 수 있는 재화의 종류는 2가지 뿐임으로 (int)Gold, (int)Ether 만 정의해 놓았다.
아이템에 가격에 대한 Data는 테이블은 현재 레벨 기획 단계에서 좀 더 수정 할 부분이 있어서
미리 만들어 놓은 EquipmentFactory에서 아이템의 가격을 직접 정해주고 만들어주었다.
info들을 관리하기 위하여 InfoManager를 싱글톤으로 만들고 어디서든 info에 접근 가능하게 만들었다
상점이용에서 InfoManager가 해줘야 하는 역할은 "유저의 보유 금액 - 구매하려는 아이템의 가격"을
저장하고(직렬화) 상점 스크립트에서 값을 받아 구매 가능여부를 체크했다
UIShopGrid에서는 InfoManager에서 받은 유저의 현재 재화 info 로 유저가 클릭한 아이템의 가격과
비교(현재 금액 > 아이템 가격)하여 거래 가능 여부를 체크했다.
가능 하다면 구매 버튼 활성, 버튼 알파값 1f, // 불가능 하다면 구매 버튼 비활성, 버튼 알파값 0.5f
구매 한 후 해당 아이템을 중복 구매 불가능하게끔 Cell의 컴포넌트 버튼을 비활성화 하고
아이콘과 프레임 알파값을 0.5f 로 바꿔줬다.
*UIShopGrid
using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class UIShopGrid : MonoBehaviour
{
public enum eShopType //성소, 던전
{
Sanctuary=9, //Cell 9 food O
Dungeon=5 //Cell 5 food X
}
public UIShopPopup uIShopPopup;
public Transform equipmentContent;
public Transform foodContent;
private ShopFactory shopFactory;
private bool isGoldEnough;
public EquipmentCell clickedCell;
public List<EquipmentCell> SanctuaryEquipmentCells;
//SanctuaryAction
//public System.Action onCreatSanctuaryShop;
//public System.Action onCreatDungeonShop;
//public System.Action onCreatFoodShop;
public void Init()
{
this.SanctuaryEquipmentCells= new List<EquipmentCell>();
this.isGoldEnough = true;
this.shopFactory = this.GetComponent<ShopFactory>();
//this.ClickedCellOn();
this.uIShopPopup.Init();
this.shopFactory.onUIPopupActive = () => {
this.uIShopPopup.gameObject.SetActive(true);
this.PopupDetail();
this.PopupDetailFrameColor();
this.PopupDetailIcon();
this.CheckCurrentGold();
};
this.uIShopPopup.onBuyItem = () => {
if (this.isGoldEnough) AcceptBuyItem();
};
}
public void SanctuaryShopCell()
{
this.shopFactory.CreatShopSword("Wood", this.equipmentContent);
this.shopFactory.CreatShopAxe("Iron", this.equipmentContent);
this.shopFactory.CreatShopArrow("Gold", this.equipmentContent);
this.shopFactory.CreatShopWand("Diamond", this.equipmentContent);
this.shopFactory.CreatShopSword("Wood", this.equipmentContent);
this.shopFactory.CreatShopArrow("Diamond", this.equipmentContent);
this.shopFactory.CreatShopWand("Gold", this.equipmentContent);
this.shopFactory.CreatShopAxe("Iron", this.equipmentContent);
this.shopFactory.CreatShopSword("Wood", this.equipmentContent);
}
public void DungeonShopCell()
{
this.shopFactory.CreatShopSword("Wood", this.equipmentContent);
this.shopFactory.CreatShopArrow("Diamond", this.equipmentContent);
this.shopFactory.CreatShopAxe("Iron", this.equipmentContent);
this.shopFactory.CreatShopWand("Gold", this.equipmentContent);
this.shopFactory.CreatShopAxe("Wood", this.equipmentContent);
}
public void FoodCell()
{
//Test
this.shopFactory.CreatShopFood("Iron", this.foodContent);
this.shopFactory.CreatShopFood("Gold", this.foodContent);
}
private void PopupDetail()
{
this.clickedCell = EventSystem.current.currentSelectedGameObject.GetComponent<EquipmentCell>(); //click된 오브잭트의 인스턴스 정보를 가져옴
this.uIShopPopup.txtNameDetail.text = clickedCell.equipmentCellname;
this.uIShopPopup.txtPowerStatDetail.text = $"공격력 : {clickedCell.powerStat}";
this.uIShopPopup.txtCriticalHitAmountDetail.text = $"치명타공격력 : {clickedCell.criticalHitAmount.ToString()}";
this.uIShopPopup.txtCriticalHitChanceDetail.text = $"치명타확률 : {clickedCell.criticalHitChance.ToString()}";
this.uIShopPopup.txtFireRateStatDetail.text = $"공격속도 : {clickedCell.fireRateStat.ToString()}";
this.uIShopPopup.txtRecoveryAmount.text = $"체력 : {clickedCell.recoveryAmount.ToString()}개 회복"; // C# 문자열 보간
this.uIShopPopup.txtPriceDetail.text = $"{clickedCell.itemPrice.ToString()+"/"+ InfoManager.instance.possessionAmountInfo.goldAmount}";
}
private void PopupDetailFrameColor()
{
this.clickedCell = EventSystem.current.currentSelectedGameObject.GetComponent<EquipmentCell>();
var color = clickedCell.transform.GetChild(0).GetComponent<Image>().color;
this.uIShopPopup.frame.color = color;
}
private void PopupDetailIcon()
{
this.clickedCell = EventSystem.current.currentSelectedGameObject.GetComponent<EquipmentCell>();
var sprite = clickedCell.transform.GetChild(1).GetComponent<Image>().sprite;
this.uIShopPopup.imgItem.sprite = sprite;
}
/// <summary>
/// 유저의 현재 금액과 클릭한 아이템의 가격 비교
/// 구매 버튼 활성/비활성
/// 버튼 알파값 0.5/1
/// </summary>
private void CheckCurrentGold()
{
if(InfoManager.instance.possessionAmountInfo.goldAmount > this.clickedCell.itemPrice)
{
Debug.Log("거래가능");
this.uIShopPopup.btnSelect.enabled = true;
this.isGoldEnough = true;
this.ButtonAlphaUp();
}
else
{
Debug.Log("거래불가");
this.uIShopPopup.btnSelect.enabled = false;
this.isGoldEnough = false;
this.ButtonAlphaDown();
}
}
/// <summary>
/// 거래 수락, InfoManager에서 유저의 금액 차감하고 save
/// </summary>
private void AcceptBuyItem()
{
Debug.Log("<Color=green>AcceptBuy</Color>");
InfoManager.instance.DecreasePossessionGoods(this.clickedCell.itemPrice);
this.ClickedCellOff();
}
private void ButtonAlphaUp()
{
var img = this.uIShopPopup.btnSelect.transform.GetChild(0).GetComponent<Image>();
Color color = img.color;
color.a = 1f;
img.color = color;
}
private void ButtonAlphaDown()
{
var img = this.uIShopPopup.btnSelect.transform.GetChild(0).GetComponent<Image>();
Color color = img.color;
color.a = 0.5f;
img.color = color;
}
/// <summary>
/// 중복 구입 방지
/// 구매 했다면(AcceptBuyItem) Cell 활성화
/// 프레임, 아이콘 알파값 1
/// Init에서 초기화 필수
/// </summary>
private void CellActive()
{
this.clickedCell.gameObject.GetComponent<Button>().enabled = true;
var frame = this.clickedCell.gameObject.transform.GetChild(0).GetComponent<Image>();
var icon = this.clickedCell.gameObject.transform.GetChild(1).GetComponent<Image>();
Color colorFrame = frame.color;
Color colorIcon = icon.color;
colorFrame.a = 1f;
colorIcon.a = 1f;
frame.color = colorFrame;
icon.color = colorIcon;
}
private void ClickedCellOff()
{
this.clickedCell.gameObject.GetComponent<Button>().enabled = false;
var frame = this.clickedCell.gameObject.transform.GetChild(0).GetComponent<Image>();
var icon = this.clickedCell.gameObject.transform.GetChild(1).GetComponent<Image>();
Color colorFrame = frame.color;
Color colorIcon = icon.color;
colorFrame.a = 0.5f;
colorIcon.a = 0.5f;
frame.color = colorFrame;
icon.color = colorIcon;
}
}
# 단순한 기능 구현이 아닌 팀 프로잭트임으로 생각할게 아주 많았다. 상점 UI 를 맡고 하다 보니 인벤토리UI와
직접적으로 연관이 있는게 많았다. 유저의 저장시점이 언제인지 , 어떤 데이터를 저장해야하고 어떤 데이터를 저장하지 말아야할지(장르가 로그라이크 이다 보니 던전 안에서 재화정보, 구매 아이템은 저장하지 않는다)도 고민할 부분이 아주 많았다. 아직 좀더 추가해야하는 기능들과 수정할 부분들이 많다.
'게임클라이언트 프로그래밍 > Guns N Rachel's' 카테고리의 다른 글
UIShop 테스트, 버그 수정 (0) | 2023.04.30 |
---|---|
UIShop 완성 (0) | 2023.04.29 |
UIShop 인벤토리 용량 증가 기능 추가 (0) | 2023.04.26 |
UIShop 팩토리 패턴 추가 수정 (0) | 2023.04.25 |
1 Stage Boss Attack Pattern3, 4 / 1,2,3Phase (0) | 2023.04.24 |