TH1/Unity/Assets/Scripts/UI/TechTreeUI.cs
2025-07-23 02:15:25 +08:00

457 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;
using TMPro;
using Animancer;
using Logic;
using Logic.Action;
using Logic.Audio;
using RuntimeData;
using Unity.VisualScripting;
using Logic.Multilingual;
using Logic.Skill;
using TH1Renderer;
using TH1Resource;
public class TechTreeUI
{
public GameObject ROTechTreeUI;
public GameObject ROTechCheckPanel;
//-------- UI表现层RenderData --------//
public bool TechTreeUIStatus = false;
public bool ShowHideAnimMark = false;
public bool TechTreeUIDataRenderMark = false;
public bool TechCheckPanelStatus = false;
public bool TechCheckPanelShowHideAnimMark = false;
public TechType TechCheckTechType;
//------- 动画数据 ---------//
private bool _isAnimating = false;
private float _fadeTime = 0f;
private bool _isShow = false;
private float _fadeDuration = 0.2f;
private TechType _techTypeChoose;
private int _techNoChooseCost = 0;
public TechTreeUI()
{
ROTechTreeUI = UIManager.Instance.ROUIManager.transform.Find("TechTreePanel").gameObject;
ROTechCheckPanel = ROTechTreeUI.transform.Find("TechCheckPanel").gameObject;
//绑定关闭按钮点击事件
ROTechTreeUI.transform.Find("CloseButton").GetComponent<Button>().onClick.AddListener(()=>PlayAnimTechTreeHide());
HideTechCheckPanel();//隐藏TechCheckPanel
Button techCheckPanelCloseButton = ROTechCheckPanel.transform.Find("ButtonGroup").transform.Find("ButtonCancel").GetComponent<Button>();
Button techCheckPanelReserchButton = ROTechCheckPanel.transform.Find("ButtonGroup").transform.Find("ButtonResearch").GetComponent<Button>();
techCheckPanelCloseButton.onClick.AddListener(HideTechCheckPanel);
techCheckPanelReserchButton.onClick.AddListener(ResearchTech);
InitTechTreeData();
}
private void UpdateTechTreeLine()
{
var lines = ROTechTreeUI.transform.Find("Lines");
var sublines = lines.Find("FatherControl");
var techSet = new HashSet<TechType>();
//先处理三级科技
foreach (Transform line in lines)
{
var tech = line.GetComponent<TechTypeMono>();;
if (tech == null) continue;
bool can = Main.MapData.PlayerMap.SelfPlayerData.TechTree.CheckIfHasTech(tech.TechType) || Main.MapData.PlayerMap.SelfPlayerData.TechTree.CheckIfTechCanLearn(tech.TechType);
line.gameObject.SetActive(can);
var techInfo = Table.Instance.TechDataAssets.GetTechInfo(tech.TechType);
if (techInfo == null)
{
Debug.LogWarning("TechType's TechInfo Not Found!");
continue;
}
//将父科技加入set便于处理复杂的一级科技连接线
if(can)
techSet.Add(techInfo.FatherTechType);
}
//处理一级科技连出来的那根线
foreach (Transform subline in sublines)
{
subline.gameObject.SetActive(false);
var tech2 = subline.GetComponent<TechTypeMono>();
if (tech2 == null) continue;
if (techSet.Contains(tech2.TechType))
subline.gameObject.SetActive(true);
}
}
private void InitTechTreeData()
{
Transform techTree = ROTechTreeUI.transform.Find("TechTree");
//设置每个科技圈圈内显示的图标是什么
foreach (Transform techNode in techTree)
{
TechType techType = techNode.GetComponent<TechTypeMono>().TechType;
var techInfo = Table.Instance.TechDataAssets.GetTechInfo(techType);
//设置英雄圈圈的背景和内容 TODO 暂时不用做内容,之后要改内容
if (techInfo.GiantTech)
{
continue;
}
TextMeshProUGUI txt = techNode.Find("Text").GetComponent<TextMeshProUGUI>();
int rk = 0;
foreach(var techItem in techInfo.techActions)
{
rk++;
Image img = techNode.Find("ImageGroup").transform.Find($"Circle{rk.ToString()}/Image").GetComponent<Image>();
MultilingualManager.Instance.SetUIText(txt, techInfo.TechName);
if (!Table.Instance.ActionDataAssets.GetActionInfo(techItem, out var actionInfo))
continue;
RectTransform rectTransform = img.rectTransform;
rectTransform.pivot = new Vector2(0.5f, 0.5f);
rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
rectTransform.anchoredPosition = Vector2.zero;
rectTransform.anchoredPosition = new Vector2(0, 20);
//img.sprite = actionInfo.GetIcon(Main.MapData.PlayerMap.SelfPlayerData.PlayerCivId, Main.MapData.PlayerMap.SelfPlayerData.PlayerForceId);
if (actionInfo.VarientIcon)
img.sprite = actionInfo.GetIcon(Main.MapData.PlayerMap.SelfPlayerData.PlayerCivId, Main.MapData.PlayerMap.SelfPlayerData.PlayerForceId);
else
img.sprite = actionInfo.Icon;
//处理偏移和尺寸
if(actionInfo.SpriteSize != Vector2.zero)
rectTransform.sizeDelta = actionInfo.SpriteSize;
if(actionInfo.SpritePos != Vector2.zero)
rectTransform.anchoredPosition = actionInfo.SpritePos;
//如果是防御类图标手动将防御小icon贴上去
if (actionInfo.ActionId.SkillType == SkillType.OCEANDEFENSE ||
actionInfo.ActionId.SkillType == SkillType.WATERDEFENSE ||
actionInfo.ActionId.SkillType == SkillType.FORESTDEFENSE ||
actionInfo.ActionId.SkillType == SkillType.MOUNTAINDEFENSE)
{
var t = techNode.Find($"ImageGroup/Circle{rk.ToString()}");
GameObject def = new GameObject("DefenseImg");
def.transform.SetParent(t, false);
var image = def.AddComponent<Image>();
image.sprite = ResourceCache.Instance.SpriteCache.TH1Icon_ActionDefense;
image.preserveAspect = true;
RectTransform rt = image.GetComponent<RectTransform>();
rt.sizeDelta = new Vector2(50, 50);
rt.anchoredPosition = new Vector2(15, -10);
}
}
for (int j = techInfo.techActions.Count + 1; j <= 3; j++)
techNode.Find("ImageGroup").transform.Find($"Circle{j.ToString()}").gameObject.SetActive(false);
}
UpdateTechTreeLine();
ROTechTreeUI.SetActive(false);
}
//当需要更新渲染科技树的时候调用
private void RenderUpdateTechTreeData()
{
Transform techTree = ROTechTreeUI.transform.Find("TechTree");
//techCheckPanel = techTreeUI.transform.Find("TechCheckPanel").gameObject;
foreach (Transform techNode in techTree)
{
TechType techType = techNode.GetComponent<TechTypeMono>().TechType;
var techInfo = Table.Instance.TechDataAssets.GetTechInfo(techType);
Button btn = techNode.GetComponent<Button>();
TextMeshProUGUI txt = techNode.Find("Text").GetComponent<TextMeshProUGUI>();
//TechType techType = Table.Instance.LegacyTechListToTechType(techNo);
btn.onClick.AddListener(() => SetTechCheckPanelShowHide(true,techType));
//Debug.Log(techType);
//如果该科技已经学习
if (Main.MapData.PlayerMap.SelfPlayerData.TechTree.CheckIfHasTech(techType))
{
Image img = techNode.transform.Find("Background").GetComponent<Image>();
img.sprite = ResourceCache.Instance.SpriteCache.TechCompleteBackground;
techNode.Find("costNumber").gameObject.SetActive(false);
techNode.Find("star").gameObject.SetActive(false);
//如果不是giant科技就把下面3个circle对象的背景都变成绿的已完成
if(!techInfo.GiantTech)
for (int i = 1; i <= techInfo.techActions.Count; i++)
{
techNode.transform.Find($"ImageGroup/Circle{i}")?.GetComponent<Image>().gameObject.SetActive(true);
if (techNode.transform.Find($"ImageGroup/Circle{i}") != null)
techNode.transform.Find($"ImageGroup/Circle{i}").GetComponent<Image>().sprite = ResourceCache.Instance.SpriteCache.TechCompleteBackground;
}
}
else
//如果该科技未解锁
if (Main.MapData.PlayerMap.SelfPlayerData.TechTree.CheckIfTechUnsee(techType))
{
Image img = techNode.Find("Background").GetComponent<Image>();
img.sprite = ResourceCache.Instance.SpriteCache.TechLockedBackground;
techNode.Find("costNumber").gameObject.SetActive(false);
techNode.Find("star").gameObject.SetActive(false);
for (int i = 1; i <= techInfo.techActions.Count; i++)
techNode.transform.Find($"ImageGroup/Circle{i}")?.GetComponent<Image>().gameObject.SetActive(false);
}
else //if(Main.MapData.PlayerMap.SelfPlayerData.TechTree.CheckIfTechCanLearn(techType))
//如果该科技可以学习
{
TextMeshProUGUI costTxt = techNode.Find("costNumber").GetComponent<TextMeshProUGUI>();
//计算目前该tech的学习成本=科技基础cost * 城市数 + 4
var img = techNode.Find("Background").GetComponent<Image>();
img.sprite = ResourceCache.Instance.SpriteCache.TechAvailableBackground;
int tmpCost = (Main.MapData.GetCityCount(Main.MapData.PlayerMap.SelfPlayerData.Id)
* techInfo.CostLevel + 4);
costTxt.text = tmpCost.ToString();
if (tmpCost > Main.MapData.PlayerMap.SelfPlayerData.PlayerWealth)
costTxt.color = Color.red;
else costTxt.color = Color.white;
costTxt.gameObject.SetActive(true);
techNode.Find("star").gameObject.SetActive(true);
for (int i = 1; i <= techInfo.techActions.Count; i++)
{
techNode.transform.Find($"ImageGroup/Circle{i}")?.GetComponent<Image>().gameObject.SetActive(true);
if (techNode.transform.Find($"ImageGroup/Circle{i}") != null)
techNode.transform.Find($"ImageGroup/Circle{i}").GetComponent<Image>().sprite = ResourceCache.Instance.SpriteCache.TechAvailableBackground;
}
}
}
UpdateTechTreeLine();
}
public void Update(MapData mapData)
{
//如果则当前不需要显示直接return
if (!ROTechTreeUI.activeSelf && !TechTreeUIStatus)
return;
//先更新data
if (TechTreeUIDataRenderMark)
{
RenderUpdateTechTreeData();
TechTreeUIDataRenderMark = false;
}
//处理动画播放or关闭动画
if (ROTechTreeUI.activeSelf != TechTreeUIStatus && ShowHideAnimMark)
{
ShowHideAnimMark = false;
if(TechTreeUIStatus)
PlayAnimTechTreeShow();
else PlayAnimTechTreeHide();
}
//处理techcheckpanel的fade动画
if (TechCheckPanelStatus != ROTechCheckPanel.activeSelf && TechCheckPanelShowHideAnimMark)
{
TechCheckPanelShowHideAnimMark = false;
if (TechCheckPanelStatus)
ShowTechCheckPanel(mapData, TechCheckTechType);
else
HideTechCheckPanel();
}
}
private void RenderUpdateTechCheckPanel(MapData mapData)
{
TechInfo techInfo = Table.Instance.TechDataAssets.GetTechInfo(_techTypeChoose);
PlayerData selfPlayer = Main.MapData.PlayerMap.SelfPlayerData;
ROTechCheckPanel.SetActive(true);
//记录一下目前点击的techNo和费用以供点击Research时判断使用
_techNoChooseCost = (Main.MapData.GetCityCount(selfPlayer.Id) * techInfo.CostLevel + 4);
TextMeshProUGUI title = ROTechCheckPanel.transform.Find("Title").GetComponent<TextMeshProUGUI>();
TextMeshProUGUI cost = ROTechCheckPanel.transform.Find("Title").transform.Find("costNumber").GetComponent<TextMeshProUGUI>();
cost.text = _techNoChooseCost.ToString();
MultilingualManager.Instance.SetUIText(title, techInfo.TechName);
//title.text = techInfo.TechName;
//设置研发按钮的表现
ROTechCheckPanel.transform.Find("ButtonGroup").transform.Find("ButtonResearch").gameObject.SetActive(true);
int itemsCount = techInfo.techActions.Count;
Transform items = ROTechCheckPanel.transform.Find("UnlockItems");
int rk = 0;
foreach(var techItem in techInfo.techActions)
{
if (!Table.Instance.ActionDataAssets.GetActionInfo(techItem, out var actionInfo)) continue;
++rk;
Transform child = items.GetChild(rk - 1);
child.gameObject.SetActive(true);
var img = child.Find("Image").GetComponent<Image>();
var rect = child.Find("Image").GetComponent<RectTransform>();
var actionMono = child.GetComponent<ActionIdMono>();
actionMono.ActionId = actionInfo.ActionId;
if (actionInfo.VarientIcon)
img.sprite = actionInfo.GetIcon(mapData.PlayerMap.SelfPlayerData.PlayerCivId,mapData.PlayerMap.SelfPlayerData.PlayerForceId);
else
img.sprite = actionInfo.Icon;
if (actionInfo.SpritePos != Vector2.zero)
rect.anchoredPosition = actionInfo.SpritePos;
if (actionInfo.SpriteSize != Vector2.zero)
rect.sizeDelta = actionInfo.SpriteSize;
TextMeshProUGUI txt = child.Find("Text").GetComponent<TextMeshProUGUI>();
MultilingualManager.Instance.SetUIText(txt, actionInfo.ActionName);
//处理defend
var t = child.Find("Defend")?.gameObject;
bool showDefend = (techItem.SkillType == SkillType.OCEANDEFENSE
|| techItem.SkillType == SkillType.WATERDEFENSE
|| techItem.SkillType == SkillType.FORESTDEFENSE
|| techItem.SkillType == SkillType.MOUNTAINDEFENSE);
if(t !=null)
t.SetActive(showDefend);
}
for(int i = itemsCount; i< 3; i++)
{
Transform child = items.GetChild(i);
child.gameObject.SetActive(false);
}
//如果已经研发完成
if (selfPlayer.TechTree.CheckIfHasTech(_techTypeChoose))
{
title.text += "(已完成)";
ROTechCheckPanel.transform.Find("ButtonGroup").transform.Find("ButtonResearch").gameObject.SetActive(false);
ROTechCheckPanel.transform.Find("Title").transform.Find("costNumber").gameObject.SetActive(false);
ROTechCheckPanel.transform.Find("Title").transform.Find("star").gameObject.SetActive(false);
}
else
//如果还没解锁
if (selfPlayer.TechTree.CheckIfTechUnsee(_techTypeChoose))
{
if (techInfo.GiantTech)
title.text = "研发该区任意3科技后解锁";
else
title.text += "(需完成前置科技)";
ROTechCheckPanel.transform.Find("ButtonGroup").transform.Find("ButtonResearch").gameObject.SetActive(false);
ROTechCheckPanel.transform.Find("Title").transform.Find("costNumber").gameObject.SetActive(true);
ROTechCheckPanel.transform.Find("Title").transform.Find("star").gameObject.SetActive(true);
}
else
//如果可以研发但是买不起则cost显示红色按钮disable
if (selfPlayer.PlayerWealth < _techNoChooseCost)
{
title.text += "(费用不足)";
cost.color = Color.red;
ROTechCheckPanel.transform.Find("ButtonGroup").transform.Find("ButtonResearch").GetComponent<Button>().interactable = false;
ROTechCheckPanel.transform.Find("Title").transform.Find("costNumber").gameObject.SetActive(true);
ROTechCheckPanel.transform.Find("Title").transform.Find("star").gameObject.SetActive(true);
}
//其他情况,那只能是可以研发了这一种情况了
else
{
cost.color = Color.white;
ROTechCheckPanel.transform.Find("ButtonGroup").transform.Find("ButtonResearch").GetComponent<Button>().interactable = true;
ROTechCheckPanel.transform.Find("Title").transform.Find("costNumber").gameObject.SetActive(true);
ROTechCheckPanel.transform.Find("Title").transform.Find("star").gameObject.SetActive(true);
}
}
//点击某个科技树后显示科技树状态
private void ShowTechCheckPanel(MapData mapData, TechType techType)//techNo是0开始的顺序编号techId是不连续的,11,121,这种代号
{
_techTypeChoose = techType;
RenderUpdateTechCheckPanel(mapData);
//播放fadeIn动画
AnimancerComponent animancer = ROTechCheckPanel.GetComponent<AnimancerComponent>();
AnimationClip animationB = Resources.Load<AnimationClip>("Animations/UI/TechButton/TechCheckPanelFadeIn");
animancer.Play(animationB);
}
private void HideTechCheckPanel()
{
AnimancerComponent animancer = ROTechCheckPanel.GetComponent<AnimancerComponent>();
AnimationClip animationB = Resources.Load<AnimationClip>("Animations/UI/TechButton/TechCheckPanelFadeOut"); // 需要播放的动画片段
animancer.Play(animationB); // 直接播放动画B
Timer.Instance.TimerRegister(ROTechTreeUI, OnTechCheckPanelFadeOutComplete, 0.2f);
}
private void SetTechCheckPanelShowHide(bool status,TechType techType = TechType.None)
{
TechCheckPanelStatus = status;
TechCheckPanelShowHideAnimMark = true;
TechCheckTechType = techType;
}
private void ResearchTech()
{
//钱不够就不能研发。这种情况理应不会发生
if (Main.MapData.PlayerMap.SelfPlayerData.PlayerWealth < _techNoChooseCost)
return;
Main.PlayerLogic.ResearchTech(Main.MapData,Main.MapData.PlayerMap.SelfPlayerData,_techTypeChoose,_techNoChooseCost);
SetTechCheckPanelShowHide(false);
RenderUpdateTechTreeData();
UIManager.Instance.TopBarUI.RenderMark = true;
}
private void PlayAnimTechTreeShow()
{
ROTechTreeUI.SetActive(true);
AnimancerComponent animancer = ROTechTreeUI.GetComponent<AnimancerComponent>();
AnimationClip animationB = Resources.Load<AnimationClip>("Animations/UI/TechTreePanelFadeIn"); // 需要播放的动画片段
animancer.Play(animationB); // 直接播放动画B
//播放音乐
AudioManager.Instance.PlayMusic("RemiliaEgyptian", 1f, 0.3f, true);
}
private void PlayAnimTechTreeHide()
{
AnimancerComponent animancer = ROTechTreeUI.GetComponent<AnimancerComponent>();
AnimationClip animationB = Resources.Load<AnimationClip>("Animations/UI/TechTreePanelFadeOut"); ; // 需要播放的动画片段
animancer.Play(animationB); // 直接播放动画B
UIManager.Instance.BottomBarUI.SetBottomBarShowHide(true);
Timer.Instance.TimerRegister(ROTechTreeUI, OnFadeOutComplete,0.2f);
//停止播放音乐
AudioManager.Instance.StopMusic();
}
//对外方法设置techtree为show或者hide
public void SetTechTreeShowHide(bool status)
{
ShowHideAnimMark = true;
TechTreeUIStatus = status;
if (status)
TechTreeUIDataRenderMark = true;
}
private void OnFadeOutComplete()
{
ROTechTreeUI.SetActive(false);
}
private void OnTechCheckPanelFadeOutComplete()
{
ROTechCheckPanel.SetActive(false);
}
}