feat: 패시브 트리 프로토타입 구현
- 패시브 트리/노드/프리셋 데이터와 카탈로그 참조 구조를 추가하고 Resources 의존을 Data/Passives 자산 구조로 정리 - 플레이어 런타임, 전투 계수, 프리셋 적용, 멀티플레이 동기화 경로에 패시브 적용 로직 연결 - 프리팹 기반 패시브 트리 UI와 노드 아이콘/프리셋/상세 패널 흐름을 추가하고 HUD에 연동 - 패시브 디버그/부트스트랩 메뉴와 UI 프리팹 재생성 경로를 추가
This commit is contained in:
129
Assets/_Game/Scripts/Passives/PassiveTreeData.cs
Normal file
129
Assets/_Game/Scripts/Passives/PassiveTreeData.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Colosseum.Passives
|
||||
{
|
||||
/// <summary>
|
||||
/// 패시브 트리 전체 데이터를 정의합니다.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "PassiveTree", menuName = "Colosseum/Passives/Passive Tree")]
|
||||
public class PassiveTreeData : ScriptableObject
|
||||
{
|
||||
[Header("기본 정보")]
|
||||
[SerializeField] private string treeId;
|
||||
[SerializeField] private string treeName;
|
||||
[TextArea(2, 4)]
|
||||
[SerializeField] private string description;
|
||||
[Min(0)] [SerializeField] private int initialPoints = 0;
|
||||
|
||||
[Header("노드")]
|
||||
[SerializeField] private List<PassiveNodeData> nodes = new List<PassiveNodeData>();
|
||||
|
||||
public string TreeId => treeId;
|
||||
public string TreeName => treeName;
|
||||
public string Description => description;
|
||||
public int InitialPoints => initialPoints;
|
||||
public IReadOnlyList<PassiveNodeData> Nodes => nodes;
|
||||
|
||||
public PassiveNodeData GetNodeById(string nodeId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(nodeId))
|
||||
return null;
|
||||
|
||||
for (int i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
PassiveNodeData node = nodes[i];
|
||||
if (node != null && string.Equals(node.NodeId, nodeId, System.StringComparison.Ordinal))
|
||||
return node;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 선택된 노드 구성이 유효한지 검사합니다.
|
||||
/// </summary>
|
||||
public bool TryResolveSelection(IReadOnlyList<string> selectedNodeIds, out List<PassiveNodeData> resolvedNodes, out string reason)
|
||||
{
|
||||
resolvedNodes = new List<PassiveNodeData>();
|
||||
reason = string.Empty;
|
||||
|
||||
HashSet<string> uniqueIds = new HashSet<string>();
|
||||
int totalCost = 0;
|
||||
|
||||
if (selectedNodeIds == null)
|
||||
return true;
|
||||
|
||||
for (int i = 0; i < selectedNodeIds.Count; i++)
|
||||
{
|
||||
string nodeId = selectedNodeIds[i];
|
||||
if (string.IsNullOrWhiteSpace(nodeId))
|
||||
continue;
|
||||
|
||||
if (!uniqueIds.Add(nodeId))
|
||||
{
|
||||
reason = $"중복 노드가 포함되어 있습니다: {nodeId}";
|
||||
return false;
|
||||
}
|
||||
|
||||
PassiveNodeData node = GetNodeById(nodeId);
|
||||
if (node == null)
|
||||
{
|
||||
reason = $"트리에 없는 노드입니다: {nodeId}";
|
||||
return false;
|
||||
}
|
||||
|
||||
resolvedNodes.Add(node);
|
||||
totalCost += node.Cost;
|
||||
}
|
||||
|
||||
for (int i = 0; i < resolvedNodes.Count; i++)
|
||||
{
|
||||
PassiveNodeData node = resolvedNodes[i];
|
||||
IReadOnlyList<PassiveNodeData> prerequisiteNodes = node.PrerequisiteNodes;
|
||||
if (prerequisiteNodes == null)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < prerequisiteNodes.Count; j++)
|
||||
{
|
||||
PassiveNodeData prerequisiteNode = prerequisiteNodes[j];
|
||||
if (prerequisiteNode == null)
|
||||
continue;
|
||||
|
||||
if (!uniqueIds.Contains(prerequisiteNode.NodeId))
|
||||
{
|
||||
reason = $"{node.DisplayName} 선택에는 선행 노드 {prerequisiteNode.DisplayName} 이(가) 필요합니다.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (totalCost > initialPoints)
|
||||
{
|
||||
reason = $"선택한 노드 비용이 보유 포인트를 초과합니다. Used={totalCost}, Max={initialPoints}";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int CalculateUsedPoints(IReadOnlyList<PassiveNodeData> selectedNodes)
|
||||
{
|
||||
if (selectedNodes == null)
|
||||
return 0;
|
||||
|
||||
int totalCost = 0;
|
||||
for (int i = 0; i < selectedNodes.Count; i++)
|
||||
{
|
||||
PassiveNodeData node = selectedNodes[i];
|
||||
if (node == null)
|
||||
continue;
|
||||
|
||||
totalCost += Mathf.Max(0, node.Cost);
|
||||
}
|
||||
|
||||
return totalCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user