TH1/Unity/Assets/Scripts/TH1_Renderer/InGameBubbleManager.cs
2026-04-28 21:07:09 +08:00

391 lines
15 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.

// BubbleData.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Logic;
using Logic.Action;
using RuntimeData;
using TH1_Core.Events;
using TH1_Core.Managers;
using TH1_Logic.Core;
using TH1Renderer;
using UnityEngine;
using UnityEngine.Tilemaps;
using Object = UnityEngine.Object;
using Random = System.Random;
namespace TH1_Renderer
{
public enum BubbleType
{
None,
Gather,
Capture,
HeroUpgrade,
Upgrade,
Examine,
HeroSelect
}
//TODO 做BubbleData序列化相关的工作
[Serializable]
public struct BubbleData
{
public GridData Grid;
public UnitData Unit;
//public HintType HintType;
public BubbleType BubbleType;
// 用于显示自定义图标(如英雄头像)
public Sprite CustomSprite;
public BubbleData(GridData grid , BubbleType bubbleType, Sprite customSprite = null)
{
Grid = grid;
grid.MainSelfPlayerVisibleUnit(out Unit);
BubbleType = bubbleType;
CustomSprite = customSprite;
}
}
[Serializable]
public class InGameBubbleManager
{
//public HashSet<BubbleData> HintSet = new();
//private Dictionary<uint, BubbleData> _idToHintDict = new();
private uint _bubbleRendererIdCounter;
private GameObject _prefabROHint;
private Transform _selfTransform;
//private Dictionary<uint,BubbleRenderer> _ROHintRendererDict = new();
//存储可用的bubbleRendererId
private HashSet<uint> _availableRenderer;
private Dictionary<uint, BubbleRenderer> _dict;
//gid -> rendererid
private Dictionary<uint,uint> _gridHasBubble;
//每次开启一局游戏前,都要初始化的模块
public void Init(Transform selfTransform)
{
_bubbleRendererIdCounter = 0;
_prefabROHint = Resources.Load<GameObject>("Prefab/bubblePrefab");
_selfTransform = selfTransform;
_availableRenderer = new HashSet<uint>();
_dict = new Dictionary<uint, BubbleRenderer>();
_gridHasBubble = new Dictionary<uint,uint>();
}
//每局游戏开始前都要更新的
public void OnGameStart()
{
_bubbleRendererIdCounter = 0;
_availableRenderer = new HashSet<uint>();
_dict = new Dictionary<uint, BubbleRenderer>();
_gridHasBubble = new Dictionary<uint,uint>();
foreach (Transform child in _selfTransform.transform)
{
// 对每个子对象调用Destroy
Object.Destroy(child.gameObject);
}
}
public void OnGameClosed()
{
CloseAllBubble();
ClearAllRenderer();
}
public void ClearAllRenderer()
{
foreach (var t in _dict)
t.Value.Destroy();
_dict.Clear();
}
public uint BubbleDataIdGenerator()
{
return _bubbleRendererIdCounter++;
}
//每帧调用所有hintRenderer的update并且将已经结束的Renderer回收
public void Update()
{
if (Main.MapData == null) return;
if (!Main.MapData.CurPlayer?.IsSelfPlayer() ?? true) return;
//遍历所有unit查看哪些单位需要更新bubble显示
foreach (var unit in Main.MapData.UnitMap.UnitList)
{
//如果不是本机玩家
if (!unit.Player(Main.MapData, out var player)||!player.IsSelfPlayer()) continue;
if(!unit.Grid(Main.MapData,out var grid)) continue;
//准备升级行为的参数
var upgradeAction = ActionLogicFactory.GetActionLogic(new CommonActionId()
{ ActionType = CommonActionType.UnitAction, UnitActionType = UnitActionType.Upgrade });
var heroUpgradeAction = ActionLogicFactory.GetActionLogic(new CommonActionId()
{ ActionType = CommonActionType.UnitAction, UnitActionType = UnitActionType.HeroUpgrade });
var captureAction = ActionLogicFactory.GetActionLogic(new CommonActionId()
{ ActionType = CommonActionType.UnitAction, UnitActionType = UnitActionType.Capture });
var starfishAction = ActionLogicFactory.GetActionLogic(new CommonActionId()
{ ActionType = CommonActionType.UnitAction, UnitActionType = UnitActionType.Gather });
var treasureAction = ActionLogicFactory.GetActionLogic(new CommonActionId()
{ ActionType = CommonActionType.UnitAction, UnitActionType = UnitActionType.Examine });
var actionParam = new CommonActionParams(mapData: Main.MapData,
playerData: Main.MapData.PlayerMap.SelfPlayerData, unitData: unit,
gridData: unit.Grid(Main.MapData));
//先判断是否已经有按钮,如果有
bool upgrade = upgradeAction.CheckCan(actionParam);
bool heroUpgrade = heroUpgradeAction.CheckCan(actionParam);
bool capture = captureAction.CheckCan(actionParam);
bool treasure = treasureAction.CheckCan(actionParam);
bool starfish = starfishAction.CheckCan(actionParam);
bool showBubble = upgrade || heroUpgrade || capture || treasure || starfish;
BubbleType bubbleType = BubbleType.Upgrade;
if(heroUpgrade)bubbleType = BubbleType.HeroUpgrade;
if(capture)bubbleType = BubbleType.Capture;
if(treasure)bubbleType = BubbleType.Examine;
if(starfish)bubbleType = BubbleType.Gather;
//判断是否能执行升级行为可以的话播放bubble
if (showBubble)
{
if (_gridHasBubble.ContainsKey(grid.Id)) continue;
if(ShowBubble(new BubbleData(grid,bubbleType),out var rendererId))
_gridHasBubble.Add(grid.Id,rendererId);
}
//如果不应该播放bubble但是有个bubble关掉他
//注HeroSelect类型的气泡不依赖单位Action需要单独检查
if(!showBubble)
{
if (_gridHasBubble.ContainsKey(grid.Id))
{
// 获取现有气泡类型跳过HeroSelect类型
if (_dict.TryGetValue(_gridHasBubble[grid.Id], out var existingRenderer))
{
var existingBubbleData = existingRenderer.GetBubbleData();
if (existingBubbleData.BubbleType == BubbleType.HeroSelect)
continue; // HeroSelect气泡不由单位Action控制
existingRenderer.ForceClose();
}
RecycleBubble(_gridHasBubble[grid.Id],grid.Id);
}
}
}
//遍历现在所有存在bubble的格子如果格子上没有unit让这个bubble自动关闭
//注HeroSelect类型的气泡不依赖单位跳过检查
var deleteList = new List<uint>();
foreach (var t in _gridHasBubble)
{
if (!Main.MapData.GridMap.GetGridDataByGid(t.Key, out var grid)) continue;
// 获取bubble类型
BubbleType bubbleType = BubbleType.None;
if (_dict.TryGetValue(t.Value, out var renderer))
{
bubbleType = renderer.GetBubbleData().BubbleType;
}
if (bubbleType == BubbleType.HeroSelect)
{
var selfPlayer = Main.MapData.PlayerMap?.SelfPlayerData;
var canShowHeroSelectBubble = ShouldShowHeroSelectBubble(Main.MapData, selfPlayer);
if (!canShowHeroSelectBubble)
{
renderer.ForceClose();
deleteList.Add(t.Key);
}
continue;
}
if (!grid.MainSelfPlayerVisibleUnit( out var _))
{
renderer.ForceClose();
deleteList.Add(t.Key);
}
}
//回收这些bubble
foreach (var t in deleteList)
if(_gridHasBubble.TryGetValue(t,out var v))
RecycleBubble(v,t);
}
public bool ShowBubble(BubbleData data,out uint rendererId)
{
//Step #1 获取一个可用的renderer
var id = GetAvailableRenderer();
_availableRenderer.Remove(id);
if (!_dict.TryGetValue(id, out var renderer))
{
Debug.Log($"Fatal error Showbubble can't find dict key id = {id}");
rendererId = 0;
return false;
}
rendererId = renderer.Id;
//Step #2 设置对应的renderer
return renderer.SetInfo(data,onClick:ClickBubble);
}
public uint GetAvailableRenderer()
{
//如果池子里没有可用对象,新创建一个
if (_availableRenderer.Count == 0)
{
var renderer = new BubbleRenderer(BubbleDataIdGenerator(),_prefabROHint,_selfTransform);
_availableRenderer.Add(renderer.Id);
_dict[renderer.Id] = renderer;
return renderer.Id;
}
//否则随便给一个可以用的
return _availableRenderer.First();
}
public void CloseAllBubble()
{
//遍历所有renderer查询是否有不在available set里的有的话就强制关闭
foreach (var t in _dict)
if (!_availableRenderer.Contains(t.Key))
{
t.Value.ForceClose();
_availableRenderer.Add(t.Key);
}
_gridHasBubble.Clear();
}
//被动由逻辑触发
public void RecycleBubble(uint rendererId,uint gid)
{
_availableRenderer.Add(rendererId);
_gridHasBubble.Remove(gid);
}
//由玩家主动触发
public void ClickBubble(uint rendererId,uint gid)
{
// 获取气泡类型
var isHeroSelectBubble = false;
if (_dict.TryGetValue(rendererId, out var renderer))
{
isHeroSelectBubble = renderer.GetBubbleData().BubbleType == BubbleType.HeroSelect;
}
RecycleBubble(rendererId,gid);
//UI收回
Main.Instance.MapInteractionLogic.CancelAllHighlight();
// HeroSelect气泡不发送HideAllUIInfo因为会关闭刚打开的Hero界面
if (!isHeroSelectBubble)
{
EventManager.Publish(new HideAllUIInfo(){});
}
}
// HeroSelect 气泡的显示条件:有待选英雄,或者可以购买 SecondHero/ThirdHero 文化卡(且尚未拥有)
private static bool ShouldShowHeroSelectBubble(MapData mapData, PlayerData playerData)
{
if (mapData == null || playerData == null) return false;
if (playerData.PlayerHeroData?.GetHeroButtonHint() == true) return true;
var cultureInfo = playerData.PlayerCultureInfo;
if (cultureInfo == null) return false;
if (CanBuyHeroCultureCard(mapData, playerData, cultureInfo, CultureCardType.SecondHero)) return true;
if (CanBuyHeroCultureCard(mapData, playerData, cultureInfo, CultureCardType.ThirdHero)) return true;
return false;
}
private static bool CanBuyHeroCultureCard(MapData mapData, PlayerData playerData, PlayerCultureInfo cultureInfo, CultureCardType cardType)
{
// 已经拥有则不需要再买
if (cultureInfo.CultureCardList != null && cultureInfo.CultureCardList.Contains(cardType)) return false;
return cultureInfo.CheckCanBuyCultureCard(mapData, playerData, cardType);
}
public void TurnStartSetBubble(MapData mapData, PlayerData playerData)
{
//Debug.Log($"[Bubble] TurnStartSetBubble called for player {playerData.Id}, IsSelfPlayer={playerData.IsSelfPlayer()}");
// 只处理本机玩家
if (!playerData.IsSelfPlayer())
{
//Debug.Log("[Bubble] Not self player, returning");
return;
}
// 检查是否有待选择的英雄
var heroData = playerData.PlayerHeroData;
//Debug.Log($"[Bubble] PlayerHeroData is null: {heroData == null}");
//if (heroData != null)
//{
// Debug.Log($"[Bubble] HeroCount={heroData.HeroCount}, MaxHeroCount={heroData.MaxHeroCount}, GetHeroButtonHint={heroData.GetHeroButtonHint()}");
//}
if (!ShouldShowHeroSelectBubble(mapData, playerData))
{
//Debug.Log("[Bubble] No hero to select and no hero culture card buyable, returning");
return;
}
// 获取玩家首都位置
if (!mapData.GetCapitalCityDataByPlayerId(playerData.Id, out var capitalCity))
{
//Debug.Log("[Bubble] No capital city found, returning");
return;
}
//Debug.Log($"[Bubble] Found capital city: {capitalCity?.Id}");
var capitalGrid = capitalCity.Grid(mapData);
if (capitalGrid == null)
{
//Debug.Log("[Bubble] Capital grid is null, returning");
return;
}
//Debug.Log($"[Bubble] Capital grid: {capitalGrid.Id}");
// 获取英雄按钮的sprite
var heroSprite = playerData.PlayerHeroData.GetHeroButtonSprite();
//Debug.Log($"[Bubble] Hero sprite is null: {heroSprite == null}");
// 创建BubbleData并显示
var bubbleData = new BubbleData(capitalGrid, BubbleType.HeroSelect, heroSprite);
//Debug.Log($"[Bubble] Created BubbleData for HeroSelect at grid {capitalGrid.Id}");
// 如果该位置已有bubble先关闭它
if (_gridHasBubble.ContainsKey(capitalGrid.Id))
{
//Debug.Log($"[Bubble] Grid {capitalGrid.Id} already has bubble, recycling");
if (_dict.TryGetValue(_gridHasBubble[capitalGrid.Id], out var existingRenderer))
existingRenderer.ForceClose();
RecycleBubble(_gridHasBubble[capitalGrid.Id], capitalGrid.Id);
}
// 显示新bubble
//Debug.Log("[Bubble] Calling ShowBubble...");
if (ShowBubble(bubbleData, out var rendererId))
{
_gridHasBubble.Add(capitalGrid.Id, rendererId);
//Debug.Log($"[Bubble] Successfully showed bubble with rendererId {rendererId}");
}
else
{
//Debug.Log("[Bubble] ShowBubble returned false!");
}
}
}
}