using System; using System.Collections.Generic; using Animancer; using Logic; using Logic.Action; using Logic.Audio; using Logic.CrashSight; using Logic.Multilingual; using Logic.Skill; using RuntimeData; using TH1_Core.Events; using TH1_Core.Managers; using TH1_Logic.Core; using TH1_Presentation.Sequencer.Task; using TH1_UI.Components; using TH1_UI.HintUI; using TH1Renderer; using TH1Resource; using TMPro; using UI.HintUI; using Unity.VisualScripting; using UnityEngine; using UnityEngine.UI; namespace TH1_UI.View.Info { public class UIInfoGridInfoView : Base.View { public Button closeButton; public ViDelegateAssisstant.Dele OnBtnCloseClick; [Header("Color相关")] public Image BGUnder; public Image BGSurface; public Image BG2Under; public Image BG2Surface; public Image AvatarTitleBG; [Header("GridInfo相关")] public GameObject GridInfoArea; public GameObject GridPreview; public GameObject GridCamera; public TextMeshProUGUI GridInfoTitle; public TextMeshProUGUI GridInfoDesc; public TextMeshProUGUI GridInfoTerrainTxt; public TextMeshProUGUI GridInfoResourceTxt; public TextMeshProUGUI GridInfoBuildingTxt; public HintTrigger GridInfoHint; [Header("CityInfo相关")] public GameObject CityInfoArea; public GameObject CityPreview; public GameObject CityCamera; public GameObject CityInfoDataArea; public TextMeshProUGUI CityInfoTitle; public TextMeshProUGUI CityInfoDesc; public TextMeshProUGUI CityInfoCoinTxt; public TextMeshProUGUI CityInfoTechTxt; public TextMeshProUGUI CityInfoCultureTxt; public TextMeshProUGUI CityInfoDiamondTxt; public TextMeshProUGUI CityInfoPopulationTxt; public TextMeshProUGUI CityInfoConnectTxt; [Header("UnitInfo相关")] public GameObject UnitInfoArea; public Image UnitPreview; public GameObject SkillArea; public TextMeshProUGUI UnitInfoTitle; public TextMeshProUGUI UnitInfoDesc; public TextMeshProUGUI UnitInfoAttackTxt; public TextMeshProUGUI UnitInfoDefendTxt; public TextMeshProUGUI UnitInfoHealthTxt; public TextMeshProUGUI UnitInfoMoveTxt; public TextMeshProUGUI UnitInfoRangeTxt; public TextMeshProUGUI UnitInfoMobilityTxt; public HintTrigger UnitInfoHint; [Header("TaskInfo相关")] public GameObject TaskArea; public TextMeshProUGUI TaskDesc; [Header("CommonInfo相关")] public GameObject AvatarArea; public GameObject AvatarHint; public GameObject Avatar; public GameObject AvatarTitleArea; public TextMeshProUGUI AvatarTitle; public Image AvatarImg; public Button AvatarBtn; public GameObject ActionArea; public TextMeshProUGUI ActionHint; public RectTransform VerticalGroup; public GameObject ActionCirclePrefab; public GameObject SkillCirclePrefab; [Header("ActionPoint相关")] public GameObject APBox; public Transform APContainer; public GameObject ActionPointPrefab; private List ActionCircleMonoList = null; private List SkillCircleMonoList = null; private List ActionPointMonoList = null; private int _actionCount; protected override void OnInit() { base.OnInit(); ActionCircleMonoList = new List(); SkillCircleMonoList = new List(); ActionPointMonoList = new List(); ActionAreaInit(); SkillAreaInit(); APBoxInit(); closeButton.onClick.RemoveAllListeners(); closeButton.onClick.AddListener(() => { OnBtnCloseClick?.Invoke(); }); //CheckPanel.InitStart(RefreshStatus); } //清除所有actioncircle,重新开始生成 private void ActionAreaInit() { if (gameObject == null) return; for (int i = ActionArea.transform.childCount - 1; i >= 0; i--) { Transform child = ActionArea.transform.GetChild(i); // 判断组件是否存在 if (child.GetComponent() != null) { // 正确调用 Destroy 方法,销毁子对象的 GameObject Destroy(child.gameObject); } } ActionCircleMonoList.Clear(); ActionCircleMonoList = new List(); } private void SkillAreaInit() { if (gameObject == null) return; for (int i = SkillArea.transform.childCount - 1; i >= 0; i--) { Transform child = SkillArea.transform.GetChild(i); // 判断组件是否存在 if (child.GetComponent() != null) { // 正确调用 Destroy 方法,销毁子对象的 GameObject Destroy(child.gameObject); } } SkillCircleMonoList.Clear(); SkillCircleMonoList = new List(); } public void SetContent(ShowUIInfoGridInfo evt) { SetContentAvatar(evt); SetContentGrid(evt); SetContentUnit(evt); SetContentCity(evt); SetContentSkill(evt); SetContentAction(evt); SetContentAPBox(evt); SetContentTask(evt); LayoutRebuilder.ForceRebuildLayoutImmediate(VerticalGroup); } private void SetContentAvatar(ShowUIInfoGridInfo evt) { AvatarArea.SetActive(true); PlayerData player = null; switch (evt.type) { case UIGridInfoType.grid: // City is on a grid, so its ID is a GID Main.MapData.GetPlayerDataByTerritoryGridId(evt.id, out player); break; case UIGridInfoType.unit: Main.MapData.GetPlayerDataByUnitId(evt.id, out player); break; } if (player == null || !Table.Instance.PlayerDataAssets.GetPlayerInfo(player, out var info)) { AvatarTitleArea.SetActive(false); AvatarHint.SetActive(false); Avatar.SetActive(false); //设置中立领土颜色 SetColor(Table.Instance.PlayerDataAssets.CommonColor); return; } AvatarTitleArea.SetActive(true); AvatarHint.SetActive(true); Avatar.SetActive(true); Table.Instance.PlayerDataAssets.GetPlayerInfo(player, out var playerInfo); SetColor(playerInfo?.Color ?? Color.black); if(!Main.MapData.PlayerMap.SelfPlayerData.MeetPlayers.Contains(player.Id)) { AvatarBtn.onClick.RemoveAllListeners(); AvatarImg.sprite = Table.Instance.PlayerDataAssets.CommonPlayerAvatar; AvatarTitle.text = "???"; LayoutRebuilder.ForceRebuildLayoutImmediate(AvatarTitleArea.GetComponent()); return; } AvatarImg.sprite = info.LeaderAvatar; MultilingualManager.Instance.SetUIText(AvatarTitle,info.ForceName); LayoutRebuilder.ForceRebuildLayoutImmediate(AvatarTitleArea.GetComponent()); AvatarBtn.onClick.RemoveAllListeners(); AvatarBtn.onClick.AddListener(() => { EventManager.Publish(new ShowUIInfoDiplomacy() { Pid = player.Id }); //因为gridinfo和diplomacyinfo 同属infoUI,打开diploInfo会自动关闭gridinfo,这里如果再主动关闭自身,会重复关闭导致错误 //OnBtnCloseClick?.Invoke(); }); } private void SetColor(Color color) { var colorUnder = color; colorUnder.a = 0.4f; BGUnder.color = colorUnder; BGSurface.color = color; BG2Under.color = colorUnder; BG2Surface.color = color; AvatarTitleBG.color = color; } private void SetContentGrid(ShowUIInfoGridInfo evt) { if (evt.type != UIGridInfoType.grid || !Main.MapData.GridMap.GetGridDataByGid(evt.id, out var grid) || Main.MapData.GetCityDataByGid(evt.id, out var _)) { GridInfoArea.SetActive(false); return; } GridInfoArea.SetActive(true); //Step #1 GridPreview GameObject clone = Instantiate(MapRenderer.Instance.ROGridMap[evt.id].GetROGrid() as GameObject); for (int i = GridPreview.transform.childCount - 1; i >= 0; i--) Destroy(GridPreview.transform.GetChild(i).gameObject); clone.transform.SetParent(GridPreview.transform); clone.transform.localPosition = new Vector3(0,15,0); clone.transform.Find("SelectHighlight").gameObject.SetActive(false); SetLayerRecursively(clone, LayerMask.NameToLayer("Preview")); GridCamera.SetActive(true); Timer.Instance.TimerRegister(GridCamera, () => { GridCamera.SetActive(false); }, 0.001f,"HideCamera"); //Step #2 Title & Desc //title 逻辑 -> building > resource > forest > mountain > plain string title_DECODE = ""; string desc_DECODE = ""; Empire empire = new Empire(grid.CivEnum,grid.Player(Main.MapData)?.ForceEnum??ForceEnum.Common); var spType = grid.GetTopGridSpType(); //如果是奇观 if (grid.Resource == ResourceType.Wonder) { if (Table.Instance.GridAndResourceDataAssets.GetWonderInfo(grid.Wonder, out var info)) { title_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(info.Name); desc_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(info.Desc); } } //如果显示建筑或者资源 else if (grid.Resource != ResourceType.None && Main.MapData.PlayerMap.SelfPlayerData.CanShowResource(grid.Resource)) { title_DECODE = Table.Instance.GridAndResourceDataAssets.GetResourceNameWithLevel_DECODE(grid,empire,spType); //var spr = Table.Instance.GridAndResourceDataAssets.GetResourceSprite(grid.Resource, grid.Player(Main.MapData), grid); Table.Instance.GridAndResourceDataAssets.GetResourceInfo(grid.Resource, out var resourceInfo); desc_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(resourceInfo.GetResourceDesc(empire,spType)); } //如果显示树木 else if(grid.Vegetation == Vegetation.Trees) { Table.Instance.GridAndResourceDataAssets.GetVegetationInfo(out var vegetationInfo); title_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(vegetationInfo.GetResourceName(empire,spType)); desc_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(vegetationInfo.GetResourceDesc(empire,spType)); } //如果显示山脉 else if(grid.Feature == TerrainFeature.Mountain) { Table.Instance.GridAndResourceDataAssets.GetMountainInfo(out var mountainInfo); title_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(mountainInfo.ResourceName); desc_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(mountainInfo.ResourceDesc); } //如果显示地形 else { Table.Instance.GridAndResourceDataAssets.GetTerrainInfo(grid.Terrain, out var terrainInfo); title_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(terrainInfo.ResourceName); desc_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(terrainInfo.ResourceDesc); } GridInfoTitle.text = title_DECODE; GridInfoDesc.text = desc_DECODE; //Step #3 设置详细info //resource / building if (grid.Resource != ResourceType.None && Table.Instance.GridAndResourceDataAssets.GetResourceInfo(grid.Resource, out var resourceInfo2)) { if (resourceInfo2.ResourceSubType == ResourceSubType.Building) { GridInfoBuildingTxt.text = Table.Instance.GridAndResourceDataAssets.GetResourceNameWithLevel_DECODE(grid,empire,spType); //处理盖在建筑下面的资源 if (grid.ResourceUnderBuilding != ResourceType.None && Table.Instance.GridAndResourceDataAssets.GetResourceInfo(grid.ResourceUnderBuilding, out var resourceInfo3) && resourceInfo3.ResourceSubType == ResourceSubType.Resource) MultilingualManager.Instance.SetUIText(GridInfoResourceTxt, Table.Instance.GridAndResourceDataAssets.GetResourceName(grid.ResourceUnderBuilding,empire,spType)); else GridInfoResourceTxt.text = "-"; } else { GridInfoBuildingTxt.text = "-"; if(Main.MapData.PlayerMap.SelfPlayerData.CanShowResource(grid.Resource)) MultilingualManager.Instance.SetUIText(GridInfoResourceTxt, Table.Instance.GridAndResourceDataAssets.GetResourceName(grid.Resource,empire,spType)); else GridInfoResourceTxt.text = "-"; } } else { GridInfoBuildingTxt.text = "-"; GridInfoResourceTxt.text = "-"; } //terrain if (grid.Feature == TerrainFeature.Mountain) { Table.Instance.GridAndResourceDataAssets.GetMountainInfo(out var mountainInfo); MultilingualManager.Instance.SetUIText(GridInfoTerrainTxt, mountainInfo.ResourceName); } else if (grid.Vegetation == Vegetation.Trees) { Table.Instance.GridAndResourceDataAssets.GetVegetationInfo(out var vegetationInfo); MultilingualManager.Instance.SetUIText(GridInfoTerrainTxt, vegetationInfo.ResourceName); } else { Table.Instance.GridAndResourceDataAssets.GetTerrainInfo(grid.Terrain,out var terrainInfo); MultilingualManager.Instance.SetUIText(GridInfoTerrainTxt, terrainInfo.ResourceName); } //处理GeoHintInfo //TODO 不能在这里修改mapData,这是错误的, 必须要调用action 来修改mapData grid.UpdateGeoInfo(Main.MapData); if (grid.GeoIdList?.Count > 0) { GridInfoHint.gameObject.SetActive(true); GridInfoHint.DataProvider.HintDataType = HintDataType.GeoData; GridInfoHint.DataProvider.GeoIdList = grid.GetRealTimeGeoIdList(); } else { GridInfoHint.gameObject.SetActive(false); } } private void SetContentUnit(ShowUIInfoGridInfo evt) { if (evt.type != UIGridInfoType.unit || !Main.MapData.UnitMap.GetUnitDataByUnitId(evt.id, out var unitData)) { UnitInfoArea.SetActive(false); return; } UnitInfoArea.SetActive(true); // 获取关联数据 Main.MapData.GetPlayerDataByUnitId(unitData.Id, out var playerData); Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(unitData.UnitFullType, out var unitTypeInfo); // Step #1: Unit Preview if (Table.Instance.UnitTypeDataAssets.GetUnitSprite(Main.MapData, unitData, out var spr)) UnitPreview.sprite = spr; // Step #2: Title & Description // 逻辑参考 BottomInfoUI.cs -> UpdateInfoUnit string title = MultilingualManager.Instance.GetMultilingualTextSafe(unitTypeInfo.Name); //处理Officer的情况 if (unitData.IsOfficer()) title += "("+ MultilingualManager.Instance.GetMultilingualText(Table.Instance.TextDataAssets.UnitOfficerName)+")"; // 示例 else if (unitData.IsPrepareOfficer()) title += $"({unitData.GetKillCount()}/3)"; UnitInfoTitle.text = title; MultilingualManager.Instance.SetUIText(UnitInfoDesc, unitTypeInfo.Desc); // Step #3: Core Stats UnitInfoHealthTxt.text = $"{unitData.Health}/{unitData.GetMaxHealth()}"; UnitInfoAttackTxt.text = unitData.GetAttackShowString(Main.MapData); UnitInfoDefendTxt.text = unitData.GetDefenseShowString(Main.MapData); UnitInfoMoveTxt.text = unitData.GetMoveRangeShowString(Main.MapData); UnitInfoRangeTxt.text = unitData.GetAttackRangeShowString(Main.MapData); UnitInfoMobilityTxt.text = Table.Instance.MobilityDataAssets.GetLandTypeText_DECODE(unitTypeInfo.LandType); //Step #4 处理Giant Hint bool isgiant = unitData.UnitFullType.UnitType is UnitType.Giant or UnitType.GiantJuggernaut; UnitInfoHint.gameObject.SetActive(isgiant); if (isgiant) { UnitInfoHint.DataProvider.HintDataType = HintDataType.TextDataGiantUpgrate; UnitInfoHint.DataProvider.UnitFullType = unitData.UnitFullType; } } private void SetContentCity(ShowUIInfoGridInfo evt) { if (evt.type != UIGridInfoType.grid || !Main.MapData.GetCityDataByGid(evt.id,out var city) || !Main.MapData.GetPlayerDataByCityId(city.Id, out var player)) { CityInfoArea.SetActive(false); return; } //TODO 这里临时去现实city的border foreach (var gid in city.Territory.TerritoryArea) if(Main.MapData.GridMap.GetGridDataByGid(gid,out var gridData)) gridData.CityBorderRenderMark = true; CityInfoArea.SetActive(true); // Step 1: Preview (Placeholder) GameObject clone = Instantiate(MapRenderer.Instance.ROGridMap[evt.id].GetROGrid() as GameObject); for (int i = CityPreview.transform.childCount - 1; i >= 0; i--) Destroy(CityPreview.transform.GetChild(i).gameObject); clone.transform.SetParent(CityPreview.transform); clone.transform.localPosition = new Vector3(0,15,0); clone.transform.Find("SelectHighlight").gameObject.SetActive(false); SetLayerRecursively(clone, LayerMask.NameToLayer("Preview")); CityCamera.SetActive(true); Timer.Instance.TimerRegister(CityCamera, () => { CityCamera.SetActive(false); }, 0.001f,"HideCamera"); // Step 2: Title & Description Table.Instance.CivDataAssets.GetCityInfo(city.Name, out var cityInfo); CityInfoTitle.text = MultilingualManager.Instance.GetMultilingualTextSafe(cityInfo.CityName) + " Lv." + city.Level; MultilingualManager.Instance.SetUIText(CityInfoDesc, cityInfo.CityDescription); // Step 3: Detailed Info (differs for self vs. others) if (player.Id == Main.MapData.PlayerMap.SelfPlayerData.Id) { CityInfoDataArea.SetActive(true); var tb = Table.Instance.TextDataAssets; CityInfoCoinTxt.text = "+" + Main.CityLogic.GetCityCoinPerTurn(Main.MapData, city)+ MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_PerTurn); CityInfoTechTxt.text = "+" + Main.CityLogic.GetCityTechPointPerTurn(Main.MapData, city) + MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_PerTurn); //var culturePerTurn = Main.CityLogic.GetCityCulturePointPerTurn(Main.MapData, city); //CityInfoCultureTxt.text = "+" + culturePerTurn + MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_PerTurn); //CityInfoCultureTxt.gameObject.SetActive(culturePerTurn > 0); CityInfoPopulationTxt.text = MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_Population) + Main.MapData.GetUnitCount(city.Id) + "/" + city.Level; CityInfoDiamondTxt.text = city.ParkCount + MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_Diamond); CityInfoConnectTxt.text = city.IsCapital ? MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_Capital) : (city.IsConnectedCapital ? MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_Connected) : MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_Unconnected)); } else CityInfoDataArea.SetActive(false); } private void SetContentSkill(ShowUIInfoGridInfo evt) { if (evt.type != UIGridInfoType.unit) { SkillArea.SetActive(false); return; } if (!Main.MapData.UnitMap.GetUnitDataByUnitId(evt.id, out var unit)) return; var skillList = new List(); foreach (var skill in unit.Skills) { if(!Table.Instance.SkillDataAssets.GetSkillInfo(skill.GetSkillType(), out var info) || info.NotShow)continue; skillList.Add(skill); } if (skillList.Count == 0) { SkillArea.SetActive(false); return; } SkillArea.SetActive(true); //Step #2 确定格位够不够 while (SkillCircleMonoList.Count < skillList.Count) { GameObject actionCircle = Instantiate(SkillCirclePrefab, SkillArea.transform, true); actionCircle.GetComponent().localScale = Vector3.one; actionCircle.GetComponent().localPosition = Vector3.zero; SkillCircleMonoList.Add(actionCircle.GetComponent()); } //Step #3 skill分类sort序列 var skillSort = new List(); var skillViewType = new List(); foreach (var t in skillList) { Table.Instance.SkillDataAssets.GetSkillInfo(t.GetSkillType(), out var info); var viewType = info?.SkillViewType ?? SkillViewType.Normal; if (t.HasTimeLimit && viewType != SkillViewType.Positive && viewType != SkillViewType.Negative) viewType = SkillViewType.Positive; skillViewType.Add(viewType); } for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Normal)skillSort.Add(i); for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Special)skillSort.Add(i); for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Unique)skillSort.Add(i); for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Positive)skillSort.Add(i); for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Negative)skillSort.Add(i); //Step #3 设置每一个action //bool unitIsBanned = unit.IsFrozen(); for (int i = 0; i < SkillCircleMonoList.Count; i++) if (i < skillSort.Count && skillSort[i] < skillList.Count) { var skill = skillList[skillSort[i]]; bool isBanned = skill.IsFrozen(unit); SkillCircleMonoList[i].gameObject.SetActive(true); SkillCircleMonoList[i].SetContent(skill,unit.UnitFullType,isBanned); } else SkillCircleMonoList[i].gameObject.SetActive(false); } private void SetContentAction(ShowUIInfoGridInfo evt) { //观战模式:非自己回合时不显示Action区域 if (Main.MapData.CurPlayer != Main.MapData.PlayerMap.SelfPlayerData) { ActionArea.SetActive(false); _actionCount = 0; return; } //Step #1 获取actionList //ResourceCache.Instance.SpriteCache.ActionBGAvailable var actionList = new List(); var cantTypeList = new List(); bool showAction = false; var subType = evt.type; CommonActionParams param = null; if (subType == UIGridInfoType.unit && Main.MapData.UnitMap.GetUnitDataByUnitId(evt.id,out var unit)) { param = new CommonActionParams(mapData:Main.MapData,playerData:Main.MapData.PlayerMap.SelfPlayerData,unitData:unit,mainObjectType:MainObjectType.Unit); showAction = ActionLogicFactory.MainObjectCanShowAction(param, out actionList,out cantTypeList); MultilingualManager.Instance.SetUIText(ActionHint,Table.Instance.TextDataAssets.GridInfoText_UnitInfoHint); } else if (subType == UIGridInfoType.grid && Main.MapData.GetCityDataByGid(evt.id,out var city)) { param = new CommonActionParams(mapData:Main.MapData,playerData:Main.MapData.PlayerMap.SelfPlayerData,cityData:city,mainObjectType:MainObjectType.City); showAction = ActionLogicFactory.MainObjectCanShowAction(param,out actionList,out cantTypeList); MultilingualManager.Instance.SetUIText(ActionHint,Table.Instance.TextDataAssets.GridInfoText_CityInfoHint); } else if (subType == UIGridInfoType.grid && Main.MapData.GridMap.GetGridDataByGid(evt.id,out var grid)) { param = new CommonActionParams(mapData:Main.MapData,Main.MapData.PlayerMap.SelfPlayerData,gridData:grid,mainObjectType:MainObjectType.Grid); showAction = ActionLogicFactory.MainObjectCanShowAction(param,out actionList,out cantTypeList); if(grid.Resource is ResourceType.Military or ResourceType.RemiliaMilitary) MultilingualManager.Instance.SetUIText(ActionHint,Table.Instance.TextDataAssets.GridInfoText_CityInfoHint); MultilingualManager.Instance.SetUIText(ActionHint,Table.Instance.TextDataAssets.GridInfoText_GridInfoHint); } if (!showAction) { // 我方Unit即使没有Action也保留ActionArea(用于显示APBox),但隐藏标题 bool isSelfUnit = subType == UIGridInfoType.unit && Main.MapData.UnitMap.GetUnitDataByUnitId(evt.id, out var selfCheckUnit) && Main.MapData.GetPlayerDataByUnitId(evt.id, out var selfCheckPlayer) && selfCheckPlayer.Id == Main.MapData.PlayerMap.SelfPlayerData.Id; if (isSelfUnit) { ActionArea.SetActive(true); ActionHint.gameObject.SetActive(false); // 隐藏所有ActionCircle for (int i = 0; i < ActionCircleMonoList.Count; i++) ActionCircleMonoList[i].gameObject.SetActive(false); _actionCount = 0; return; } ActionArea.SetActive(false); //_actionCount必须设置为0,因为其他地方会用到 _actionCount = 0; return; } ActionArea.SetActive(true); ActionHint.gameObject.SetActive(true); _actionCount = actionList.Count; //Step #2 确定格位够不够 while (ActionCircleMonoList.Count < actionList.Count) { GameObject actionCircle = Instantiate(ActionCirclePrefab, ActionArea.transform, true); actionCircle.GetComponent().localScale = Vector3.one; actionCircle.GetComponent().localPosition = Vector3.zero; ActionCircleMonoList.Add(actionCircle.GetComponent()); } //Step #3 设置每一个action for (int i = 0; i < ActionCircleMonoList.Count; i++) { ActionCircleMonoList[i].gameObject.SetActive(i < actionList.Count); if (i >= actionList.Count) continue; ActionCircleMonoList[i].SetContent(actionList[i].ActionId,cantTypeList[i],param,OnActionCircleClicked); } } public void ExecuteAction(ExecuteUIInfoGridInfo evt) { if(evt.idx >= ActionCircleMonoList.Count || evt.idx >= _actionCount) return; ActionCircleMonoList[(int)evt.idx].ClickButton.onClick.Invoke(); } private void OnActionCircleClicked(CommonActionId actionId, CommonActionParams param) { var action = ActionLogicFactory.GetActionLogic(actionId); if (action.CheckCan(param) && action.CompleteExecute(param)) { // Action执行成功后立即刷新APBox,确保关闭/重开面板时显示最新状态 if (param.UnitData != null) RefreshActionPoints(param.UnitData); OnBtnCloseClick?.Invoke(); //这里特殊处理 点击了action但是不关闭gridInfo而是让单位继续行动的情况。后续需要将这个属性归化 if(action.ActionId.UnitActionType == UnitActionType.AYAMOVEAGAIN) PresentationManager.EnqueueTask(new InputSequencerTask(MapRenderer.Instance.SelectUnitData.Grid(Main.MapData))); } } //清除所有ActionPoint,重新开始 private void APBoxInit() { if (APContainer == null) return; for (int i = APContainer.childCount - 1; i >= 0; i--) { Transform child = APContainer.GetChild(i); if (child.GetComponent() != null) Destroy(child.gameObject); } ActionPointMonoList.Clear(); } /// /// 根据当前GridInfo展示的类型,决定APBox是否显示,以及填充ActionPoint列表。 /// 仅在展示Unit的ActionArea时才显示APBox。 /// private void SetContentAPBox(ShowUIInfoGridInfo evt) { // 只有当展示的是Unit,并且ActionArea可见时,才显示APBox if (evt.type != UIGridInfoType.unit || !Main.MapData.UnitMap.GetUnitDataByUnitId(evt.id, out var unitData) || !ActionArea.activeSelf) { if (APBox != null) APBox.SetActive(false); return; } if (APBox != null) APBox.SetActive(true); RefreshActionPoints(unitData); } /// /// 刷新APContainer下ActionPoint的数量和显示内容。 /// 根据unitData里的行动点信息,动态生成/复用/隐藏ActionPoint对象。 /// public void RefreshActionPoints(RuntimeData.UnitData unitData) { if (APContainer == null || ActionPointPrefab == null || unitData == null) return; // 将ActionPoint字典展开为一个平铺列表,每个点一个条目 var flatList = new List(); if (unitData.ActionPoint != null) { foreach (var kv in unitData.ActionPoint) { for (int j = 0; j < kv.Value; j++) flatList.Add(kv.Key); } } // 如果总量为0,仍然显示一个Empty int needCount = flatList.Count > 0 ? flatList.Count : 1; // 确保池中有足够的ActionPoint实例 while (ActionPointMonoList.Count < needCount) { GameObject go = Instantiate(ActionPointPrefab, APContainer, false); go.GetComponent().localScale = Vector3.one; var mono = go.GetComponent(); if (mono == null) mono = go.AddComponent(); ActionPointMonoList.Add(mono); } // 设置每个ActionPoint的显示/隐藏和内容 for (int i = 0; i < ActionPointMonoList.Count; i++) { if (i < needCount) { ActionPointMonoList[i].gameObject.SetActive(true); if (flatList.Count == 0) ActionPointMonoList[i].SetEmpty(); else ActionPointMonoList[i].SetContent(flatList[i]); } else { ActionPointMonoList[i].gameObject.SetActive(false); ActionPointMonoList[i].ResetContent(); } } } private void SetLayerRecursively(GameObject obj, int newLayer) { obj.layer = newLayer; foreach (Transform child in obj.transform) { SetLayerRecursively(child.gameObject, newLayer); } } private void SetContentTask(ShowUIInfoGridInfo evt) { // Step #1 判断是否有task需要显示 if (evt.type != UIGridInfoType.unit || !Main.MapData.UnitMap.GetUnitDataByUnitId(evt.id, out var unit) || !Main.MapData.GetPlayerDataByUnitId(evt.id, out var player) ) { TaskArea.SetActive(false); return; } bool shouldShowTask = (unit.UnitFullType.UnitType is UnitType.Giant or UnitType.GiantJuggernaut)&& unit.UnitFullType.UnitLevel < 4 && player.Id == Main.MapData.PlayerMap.SelfPlayerId; if (!shouldShowTask) { TaskArea.SetActive(false); return; } //Step #2 设置具体内容 TaskArea.SetActive(true); if (!Table.Instance.HeroDataAssets.GetHeroInfo(unit.GiantType, out var heroInfo) || heroInfo.TaskList.Count <= unit.UnitLevel - 1 || !Main.MapData.PlayerMap.SelfPlayerData.PlayerHeroData.GetHeroTask(unit.GiantType, out var task)) { TaskArea.SetActive(false); return; } if (task.IsForceFinished) { MultilingualManager.Instance.SetUIText(TaskDesc, Table.Instance.TextDataAssets.HeroTaskFinishedDesc); } else { var param1 = task.LevelShowString(); var param2 = task.TargetLevelShowString(); var param3 = ""; if (task.SkillType != SkillType.NONE && Table.Instance.SkillDataAssets.GetSkillInfo(task.SkillType, out var skillInfo)) { param3 = MultilingualManager.Instance.GetMultilingualTextSafe(skillInfo.SkillName); } var taskDesc = heroInfo.TaskList[(int)(unit.UnitLevel - 1)].Desc; MultilingualManager.Instance.SetUIText(TaskDesc, taskDesc, new List { param1, param2, param3 }); } } public void CloseView() { // 不停止音乐,只恢复轮播(如果正在播放的不是轮播音乐,会继续播放) Logic.Audio.AudioManager.Instance.ResumeBgmRotationIfEnabled(); } protected override void OnShowAnimFinished() { base.OnShowAnimFinished(); // 延迟一帧执行布局刷新,确保 RectTransform 尺寸已正确计算 StartCoroutine(RefreshLayoutNextFrame()); } private System.Collections.IEnumerator RefreshLayoutNextFrame() { yield return null; // 等待一帧 if (VerticalGroup != null) { LayoutRebuilder.ForceRebuildLayoutImmediate(VerticalGroup); } } } }