대장간을 이용한 업그레이드 기능 추가

This commit is contained in:
2026-02-23 16:55:32 +09:00
parent 840ddc1c2c
commit e841438997
48 changed files with 1189 additions and 490 deletions

View File

@@ -0,0 +1,228 @@
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using Northbound.Data;
namespace Northbound
{
/// <summary>
/// 업그레이드 리스트 아이템 UI
/// </summary>
public class UpgradeListItem : MonoBehaviour, IPointerClickHandler
{
[Header("UI References")]
[SerializeField] private TextMeshProUGUI _nameText;
[SerializeField] private TextMeshProUGUI _costText;
[SerializeField] private Transform _effectRowsParent;
[SerializeField] private Transform _reqChipsParent;
[SerializeField] private Button _purchaseButton;
[SerializeField] private GameObject _purchasedOverlay;
[SerializeField] private Image _backgroundImage;
private UpgradeData _upgradeData;
private bool _isOwned;
private bool _canPurchase;
private UpgradeListPopup _parentPopup;
private Color _normalColor = new Color(1f, 1f, 1f, 0.44f); // 기본 배경색
private Color _disabledColor = new Color(0.5f, 0.5f, 0.5f, 0.6f); // 회색
private void Awake()
{
if (_purchaseButton == null)
{
_purchaseButton = GetComponent<Button>();
}
if (_purchaseButton != null)
{
_purchaseButton.onClick.AddListener(OnPurchaseClicked);
}
if (_backgroundImage == null)
{
_backgroundImage = GetComponent<Image>();
}
}
/// <summary>
/// 아이템 설정
/// </summary>
public void Setup(UpgradeData upgrade, bool isOwned, bool canPurchase, UpgradeListPopup parentPopup)
{
_upgradeData = upgrade;
_isOwned = isOwned;
_canPurchase = canPurchase;
_parentPopup = parentPopup;
UpdateUI();
}
private void UpdateUI()
{
if (_upgradeData == null) return;
// 이름
if (_nameText != null)
{
_nameText.text = _upgradeData.memo;
}
// 비용
if (_costText != null)
{
_costText.text = $"Cost: {_upgradeData.mana}";
}
// 구매 가능 여부 확인 (비용 체크 포함)
bool hasEnoughResources = CheckHasEnoughResources();
bool isAvailable = _canPurchase && !_isOwned && hasEnoughResources;
// 구매 불가능한 경우 회색 처리
if (_backgroundImage != null)
{
_backgroundImage.color = isAvailable ? _normalColor : _disabledColor;
}
// 이름 텍스트 색상도 변경
if (_nameText != null)
{
_nameText.color = isAvailable ? Color.white : Color.gray;
}
// 비용 텍스트 색상 (자원 부족 시 빨간색)
if (_costText != null)
{
_costText.color = hasEnoughResources ? Color.white : Color.red;
}
// 구매 버튼 - 항상 클릭 가능하게 설정
if (_purchaseButton != null)
{
_purchaseButton.interactable = true;
}
// 구매 완료 오버레이
if (_purchasedOverlay != null)
{
_purchasedOverlay.SetActive(_isOwned);
}
// 효과 표시
UpdateEffectRows();
// 선행조건 표시
UpdateReqChips();
}
/// <summary>
/// 자원이 충분한지 확인
/// </summary>
private bool CheckHasEnoughResources()
{
var core = CoreResourceManager.Instance?.mainCore;
if (core == null) return false;
return core.TotalResources >= _upgradeData.mana;
}
private void UpdateEffectRows()
{
if (_effectRowsParent == null || _upgradeData == null) return;
// 기존 자식 제거
foreach (Transform child in _effectRowsParent)
{
Destroy(child.gameObject);
}
// 효과 목록 생성
for (int i = 0; i < _upgradeData.effectStatList.Count; i++)
{
if (i >= _upgradeData.effectOpList.Count || i >= _upgradeData.effectValueList.Count)
break;
string statName = FormatStatName(_upgradeData.effectStatList[i]);
string op = _upgradeData.effectOpList[i];
float value = _upgradeData.effectValueList[i];
// 간단한 텍스트로 표시 (EffectRow 프리팹이 없는 경우)
var textObj = new GameObject($"Effect_{i}");
textObj.transform.SetParent(_effectRowsParent);
var text = textObj.AddComponent<TextMeshProUGUI>();
text.text = $"{statName}: {FormatValue(op, value)}";
text.fontSize = 24;
}
}
private void UpdateReqChips()
{
if (_reqChipsParent == null || _upgradeData == null) return;
// 기존 자식 제거
foreach (Transform child in _reqChipsParent)
{
Destroy(child.gameObject);
}
// 선행조건이 없으면 표시하지 않음
if (_upgradeData.requireUpgradeId.Count == 0) return;
foreach (int reqId in _upgradeData.requireUpgradeId)
{
var database = UpgradeDatabase.Instance;
var reqUpgrade = database?.GetUpgradeById(reqId);
if (reqUpgrade == null) continue;
// 간단한 텍스트로 표시 (ReqChip 프리팹이 없는 경우)
var textObj = new GameObject($"Req_{reqId}");
textObj.transform.SetParent(_reqChipsParent);
var text = textObj.AddComponent<TextMeshProUGUI>();
text.text = $"Requires: {reqUpgrade.memo}";
text.fontSize = 20;
text.color = Color.yellow;
}
}
private string FormatStatName(string stat)
{
return stat switch
{
"player_max_hp" => "Max HP",
"player_atk_damage" => "ATK Damage",
"player_capacity" => "Capacity",
"player_manpower" => "Manpower",
"player_move_speed" => "Move Speed",
"player_sight" => "Sight",
"player_atk_range" => "ATK Range",
_ => stat
};
}
private string FormatValue(string op, float value)
{
return op switch
{
"add" => $"+{value}",
"mul" => $"x{value}",
"set" => $"{value}",
_ => $"{value}"
};
}
private void OnPurchaseClicked()
{
if (_upgradeData == null || _parentPopup == null) return;
if (_isOwned || !_canPurchase) return;
_parentPopup.RequestPurchase(_upgradeData.id);
}
// IPointerClickHandler 구현 - 직접 클릭 감지
public void OnPointerClick(PointerEventData eventData)
{
OnPurchaseClicked();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: bb93da116066efb4f95f04229c90a069

View File

@@ -0,0 +1,175 @@
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
using Northbound.Data;
namespace Northbound
{
/// <summary>
/// 업그레이드 목록 팝업 UI 컨트롤러
/// </summary>
public class UpgradeListPopup : MonoBehaviour
{
[Header("References")]
[SerializeField] private Transform _contentParent;
[SerializeField] private GameObject _listItemPrefab;
[SerializeField] private TextMeshProUGUI _manaText;
[SerializeField] private Button _closeButton;
private PlayerUpgradeManager _playerUpgradeManager;
private PlayerStats _playerStats;
private List<UpgradeListItem> _listItems = new List<UpgradeListItem>();
private void Awake()
{
if (_closeButton != null)
{
_closeButton.onClick.AddListener(Close);
}
}
private void Update()
{
// ESC 키로 닫기
if (Keyboard.current != null && Keyboard.current.escapeKey.wasPressedThisFrame)
{
Close();
}
// 마나 텍스트 업데이트
UpdateManaDisplay();
}
/// <summary>
/// 팝업 초기화
/// </summary>
public void Initialize(PlayerUpgradeManager upgradeManager, PlayerStats playerStats)
{
_playerUpgradeManager = upgradeManager;
_playerStats = playerStats;
RefreshList();
UpdateManaDisplay();
gameObject.SetActive(true);
}
/// <summary>
/// 업그레이드 목록 갱신
/// </summary>
public void RefreshList()
{
// 기존 아이템 제거
ClearList();
if (_playerUpgradeManager == null) return;
var database = UpgradeDatabase.Instance;
if (database == null)
{
Debug.LogWarning("[UpgradeListPopup] UpgradeDatabase를 찾을 수 없습니다.");
return;
}
// 개인 업그레이드 목록 가져오기
var allUpgrades = database.GetPersonalUpgrades();
var ownedIds = _playerUpgradeManager.GetOwnedUpgradeIdSet();
foreach (var upgrade in allUpgrades)
{
if (upgrade == null) continue;
bool isOwned = ownedIds.Contains(upgrade.id);
bool prerequisitesMet = database.ArePrerequisitesMet(upgrade.id, ownedIds);
// 이미 구매했거나, 선행조건이 충족된 항목만 표시
if (!isOwned && !prerequisitesMet) continue;
bool canPurchase = !isOwned && prerequisitesMet;
CreateListItem(upgrade, isOwned, canPurchase);
}
}
/// <summary>
/// 리스트 아이템 생성
/// </summary>
private void CreateListItem(UpgradeData upgrade, bool isOwned, bool canPurchase)
{
if (_listItemPrefab == null || _contentParent == null) return;
GameObject itemObj = Instantiate(_listItemPrefab, _contentParent);
var listItem = itemObj.GetComponent<UpgradeListItem>();
if (listItem != null)
{
listItem.Setup(upgrade, isOwned, canPurchase, this);
_listItems.Add(listItem);
}
else
{
// UpgradeListItem 컴포넌트가 없으면 추가
listItem = itemObj.AddComponent<UpgradeListItem>();
listItem.Setup(upgrade, isOwned, canPurchase, this);
_listItems.Add(listItem);
}
}
/// <summary>
/// 리스트 비우기
/// </summary>
private void ClearList()
{
foreach (var item in _listItems)
{
if (item != null && item.gameObject != null)
{
Destroy(item.gameObject);
}
}
_listItems.Clear();
}
/// <summary>
/// 업그레이드 구매 요청
/// </summary>
public void RequestPurchase(int upgradeId)
{
if (_playerUpgradeManager == null) return;
_playerUpgradeManager.RequestPurchaseUpgrade(upgradeId);
// 구매 후 목록 갱신
RefreshList();
UpdateManaDisplay();
}
/// <summary>
/// 마나 표시 업데이트
/// </summary>
private void UpdateManaDisplay()
{
if (_manaText == null) return;
var core = CoreResourceManager.Instance?.mainCore;
if (core != null)
{
_manaText.text = $"MANA: {core.TotalResources}";
}
}
/// <summary>
/// 팝업 닫기
/// </summary>
public void Close()
{
gameObject.SetActive(false);
}
private void OnDestroy()
{
ClearList();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1d9a732b420252f48bfa530b3f90d50b