using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using RuntimeData; using Logic; using Logic.CrashSight; using TH1_Logic.Core; using TH1_Renderer; using TH1Resource; using UnityEngine.UI; namespace TH1Renderer { public class MapRenderer { private Main _main; private MapData _mapData; private Transform _unitRenderMap; private Transform _gridRenderMap; public Transform HintRenderMap; //HintManager public HintManager HintManager; Transform _cityInfoRenderMap; public CameraController CameraController; public EffectManager EffectManager; //特效管理器,管理目前所有特效 public ProjectileManager ProjectileManager; private Transform _projectileRenderMap; //存储map对应的主要GameObject public GameObject ROMap; private GameObject _unitPrefab; //承载单位图像的prefab private GameObject _gridPrefab; //承载grid的prefab private GameObject _cityInfoPrefab; //承载城市图形信息、人口条的prefab public Dictionary ROGridMap; public Dictionary ROCityInfoMap; public Dictionary ROUnitMap; bool aniFlagExplorer = false; //用于探险家动画的标识bool GameObject explorerUnit; //用于存储探险家图像 Vector2Int explorerNowPos; //用于存储探险家Data当前的位置 // 临时探索者游戏对象 private GameObject _temporaryExplorer = null; private Vector3 _temporaryExplorerStartPos; private float _temporaryExplorerTime = 0f; private bool _temporaryExplorerActive = false; //-------- 表现层数据map交互部分 --------// //移动和攻击的高亮RenderData,set中存放了所有需要更新的对象 public HashSet HighlightGridIdSet = new HashSet(); public bool HighlightGridIdSetRenderMark = false; public HashSet HighlightUnitIdSet = new HashSet(); public bool HighlightUnitIdSetRenderMark = false; public UnitData SelectUnitData; // 添加移动相关的成员变量 private Vector3 _explorerMoveStartPos; private Vector3 _explorerMoveTargetPos; private float _explorerMoveTime; private float _explorerMoveDuration; private bool _explorerIsMoving; // 添加成员变量来记录上一个位置 private Vector2Int _explorerPreviousPosition = new Vector2Int(-1, -1); // 初始化为无效位置 // 添加成员变量来跟踪移动次数和存储当前目标格子 private int _explorerMoveCount = 0; private int _explorerMaxMoves = 10; private GridData _currentTargetGridData; private static MapRenderer _instance; public static MapRenderer Instance { get { if (_instance == null) { Debug.LogError("MapRenderer not initialized. Call Initialize(main, mapData) first."); } return _instance; } } public static void Initialize(Main main, MapData mapData) { if (_instance != null) { Debug.LogWarning("MapRenderer already initialized. Reinitializing..."); } _instance = new MapRenderer(main, mapData); } public static void Dispose() { _instance = null; } public static void TryUpdate() { if (_instance != null) { _instance.Update(); } } private MapRenderer(Main main, MapData mapData) { //EventManager.Instance.EventEnter = new ViewEventEnter(); _main = main; _mapData = mapData; ROMap = main.ROMapRenderer; //初始化Data->Renderer的dict ROGridMap = new Dictionary(); ROCityInfoMap = new Dictionary(); ROUnitMap = new Dictionary(); // 初始化主要的渲染模块(grid city unit projectileManager) InitGridCityUnitObject(); //初始化相机模块 InitCameraObject(); //初始化HintManager HintManager = new HintManager(); HintManager.Init(main, mapData); } private void ClearAllChildren(Transform parent) { if (parent == null) return; for (int i = parent.childCount - 1; i >= 0; i--) { GameObject.Destroy(parent.GetChild(i).gameObject); } } public bool InitGridCityUnitObject() { //重新建立新的关联 if (ROMap == null) return false; _unitRenderMap = ROMap.transform.Find("UnitMap"); _gridRenderMap = ROMap.transform.Find("GridMap"); HintRenderMap = ROMap.transform.Find("HintMap"); _cityInfoRenderMap = ROMap.transform.Find("CityInfoMap")?.GetComponent(); //清理战场,把上一局Grid里面留下的东西清理干净 ClearAllChildren(_unitRenderMap); ClearAllChildren(_gridRenderMap); ClearAllChildren(_cityInfoRenderMap); ClearAllChildren(HintRenderMap); ClearAllChildren(ROMap.transform.Find("ProjectileMap")); _unitPrefab = Resources.Load($"Prefab/unitPrefab"); _gridPrefab = Resources.Load($"Prefab/tilePrefab"); _cityInfoPrefab = Resources.Load($"Prefab/cityInfoMapPrefab"); //建立子模块的manager,目前仅有projectile //TODO 这里要改成ProjectManager依赖注入,然后要上面ClearALL要把Projectilemanager算进去 ProjectileManager = new ProjectileManager(); ProjectileManager.Init(ROMap.transform.Find("ProjectileMap")); return true; } public bool InitCameraObject() { var cameraObject = GameObject.Find("Main Camera"); if (cameraObject == null) return false; CameraController = cameraObject.GetComponent(); return true; } public void Update() { //处理所有飞行道具。这个不会被暂停 ProjectileManager.Update(); //HintManager HintManager.Update(); // 处理临时探索者的浮动动画 if (_temporaryExplorerActive && _temporaryExplorer != null) { _temporaryExplorerTime += Time.deltaTime; float yOffset = 0.2f * Mathf.Sin(2f * _temporaryExplorerTime); // 0.2f是浮动幅度,2f是浮动频率 // 如果正在移动,则不应用浮动效果 if (!_explorerIsMoving) { _temporaryExplorer.transform.position = new Vector3( _temporaryExplorerStartPos.x, _temporaryExplorerStartPos.y + yOffset, _temporaryExplorerStartPos.z ); } } // 处理探索者移动 if (_explorerIsMoving && _temporaryExplorer != null) { _explorerMoveTime += Time.deltaTime; float t = Mathf.Clamp01(_explorerMoveTime / _explorerMoveDuration); _temporaryExplorer.transform.position = Vector3.Lerp(_explorerMoveStartPos, _explorerMoveTargetPos, t); // 移动完成 if (t >= 1.0f) { _explorerIsMoving = false; _temporaryExplorerStartPos = _explorerMoveTargetPos; // 更新浮动动画的起始位置 // 更新视野 if (_currentTargetGridData != null) // 调用UpdateSightByRadius更新视野 Main.PlayerLogic.UpdateSightByRadius(Main.MapData, Main.MapData.PlayerMap.SelfPlayerData, _currentTargetGridData, _currentTargetGridData.Feature == TerrainFeature.Mountain? 2 : 1); // 检查是否需要继续移动 if (_explorerMoveCount < _explorerMaxMoves && _temporaryExplorer != null) { // 获取动画延迟时间 float delayTime = 0.5f; // 默认值 if (Table.Instance.AnimDataAssets != null) { // 从AnimDataAssets获取延迟时间 delayTime = Table.Instance.AnimDataAssets.ExplorerMoveDelay; // 如果没有专门的ExplorerMoveDelay参数,可以使用其他相关参数 if (delayTime <= 0) { delayTime = Table.Instance.AnimDataAssets.MoveAnimTime + 0.2f; // 移动时间加一点额外延迟 } } // 应用动画速度调整 delayTime /= DebugCenter.Instance.AnimationSpeed; // 延迟一小段时间后继续移动 Timer.Instance.TimerRegister(this, () => { MoveExplorerToLeastVisibleDirection(_currentTargetGridData, Main.MapData.PlayerMap.SelfPlayerData); }, delayTime,"MapRenderer_Update"); } else if (_explorerMoveCount >= _explorerMaxMoves && _temporaryExplorer != null) { // 已完成所有移动,销毁探索者 RemoveTemporaryExplorer(); // 确保解锁输入 _main.InputLogic.UnlockInput(); } } } //-------- 处理UI数据 ---------// //处理高亮 if (HighlightGridIdSetRenderMark) { HighlightGridIdSetRenderMark = false; foreach (var gid in HighlightGridIdSet) ROGridMap[gid].RenderUpdataHighlight(); HighlightGridIdSet.Clear(); } if (HighlightUnitIdSetRenderMark) { HighlightUnitIdSetRenderMark = false; foreach (var uid in HighlightUnitIdSet) ROUnitMap[uid].RenderUpdataHighlight(); HighlightUnitIdSet.Clear(); } //处理CityMap或者UnitMap新增/删除的city和unit if (_mapData.CityMap.CityMapRenderMark) { _mapData.CityMap.CityMapRenderMark = false; RenderUpdateCityMap(); } if (_mapData.UnitMap.UnitMapRenderMark) { _mapData.UnitMap.UnitMapRenderMark = false; //检查有无单位销毁 //var t = ROUnitMap; List toRemove = new List(); foreach (var roUnitId in ROUnitMap.Keys) { if (!Main.MapData.UnitMap.GetUnitDataByUnitId(roUnitId, out var unitData)) toRemove.Add(roUnitId); } foreach (var roUnitId in toRemove) { ROUnitMap[roUnitId].Die(); ROUnitMap.Remove(roUnitId); } //更新新增单位 RenderUpdateUnitMap(); } //-------- 处理子节点的Update -------// foreach (var roUnit in ROUnitMap.Values) { roUnit.Update(); } foreach (var roGrid in ROGridMap.Values) roGrid.Update(); foreach (var roCityInfo in ROCityInfoMap.Values) roCityInfo.Update(); } //当gridMap出现新的对象时,新建对象 public void RenderUpdateGridMap() { foreach (var gridData in Main.MapData.GridMap.GridList) { ROGridMap[gridData.Id] = new GridRenderer(_gridPrefab, _gridRenderMap, gridData.Id, Main.MapData, _main); } } //当cityMap出现新的对象时,新建对象 public void RenderUpdateCityMap() { foreach (var cityData in Main.MapData.CityMap.CityList) if(!ROCityInfoMap.ContainsKey(cityData.Id)) { //生成城镇图像 RenderUpdateCityBuildings(cityData.Id); //生成城镇名称和人口条 ROCityInfoMap[cityData.Id] = new CityInfoRenderer(_cityInfoPrefab,_cityInfoRenderMap,cityData.Id,Main.MapData,_main); cityData.CityInfoRenderMark = true; } } //当unitMap出现新的对象时,新建对象 public void RenderUpdateUnitMap() { foreach (var unitData in Main.MapData.UnitMap.UnitList) if(!ROUnitMap.ContainsKey(unitData.Id)) { //生成单位图像 ROUnitMap[unitData.Id] = new UnitRenderer(_unitPrefab,_unitRenderMap,unitData.Id,Main.MapData,_main); } } //当projectileMap出现新的对象时,新建对象 public void RenderUpdateProjectileMap() { } // 初次渲染地图 public void FirstRenderMap() { //初次渲染grid RenderUpdateGridMap(); //初次渲染city RenderUpdateCityMap(); //初次渲染所有unit RenderUpdateUnitMap(); } public void RenderUpdateBorders() //更新全地图的所有边界 { foreach (var gridData in Main.MapData.GridMap.GridList) ROGridMap[gridData.Id].UpdateBorder(); } private void RenderUpdateCityBuildings(uint cityId) //更新主城建筑的渲染 { Main.MapData.GetGridIdByCityId(cityId, out var gridId); ROGridMap[gridId].RenderUpdateCityBuilding(cityId); } public bool SetUnitAllMoveAttackTargetHighlight(uint uid) //渲染所有可移动位置的高亮,其中可以攻击的位置要标红,如果是自己人或者敌人在移动范围内但是不在攻击范围内,则不能高亮 { bool ret = false; Main.UnitLogic.CalcUnitMoveInfo(Main.MapData, uid); Main.MapData.UnitMap.GetUnitDataByUnitId(uid, out var unitData); Main.MapData.GetGridDataByUnitId(uid, out var gridData); Main.MapData.GetPlayerDataByUnitId(uid, out var playerData); //unitLogic.DebugOutputMoveInfo(); int r = Mathf.Max((Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(unitData.UnitType,unitData.GiantType,unitData.UnitLevel,out var info)?info.MoveRange:0) * 2, Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(unitData.UnitType,unitData.GiantType,unitData.UnitLevel,out var info2)?info2.AttackRange:0); //如果有citytransport或者是allytransport,要把r设置为全图大小 if (unitData.UnitType == UnitType.Giant) { bool transport = false; foreach(var skill in unitData.Skills) if (skill.GetSkillType() == SkillType.ALLYTRANSPORT || skill.GetSkillType() == SkillType.CITYTRANSPORT) { transport = true; break; } if(transport) r = (int)(_mapData.MapConfig.Width > _mapData.MapConfig.Height ? _mapData.MapConfig.Width : _mapData.MapConfig.Height); } var targetGridDataList = Main.MapData.GridMap.GetAroundGridDataSet(r,r,gridData); foreach(var targetGridData in targetGridDataList) { //如果不在视野 跳过 if (!playerData.Sight.CheckIsInSight(targetGridData.Id)) continue; var sig = Main.UnitLogic.CheckUnitCanMoveOrAttack(Main.MapData, unitData, targetGridData); //如果是移动目标,且unit的MP>0 if ((sig == MoveAttackType.Move || sig == MoveAttackType.MoveToPort || sig == MoveAttackType.MoveAshore) && unitData.MP > 0) { ret = true; ROGridMap[targetGridData.Id].SetMoveHighlight(true); } //如果是攻击目标,且unit的AP>0 if (sig == MoveAttackType.Attack && unitData.AP > 0 && !unitData.IsLimitSelfAttack(Main.MapData)) { ret = true; if (!Main.MapData.GetUnitDataByGid(targetGridData.Id, out var unitDataB)) continue; //如果可以杀死,做一个提示 if (Table.Instance.CalcDamage(Main.MapData, unitData, unitDataB) >= unitDataB.Health) { targetGridData.VFXRenderMarkDieHintStart = true; //0代表这是杀死提示 targetGridData.VFXRenderMarkDieHintStartParam = 0; } else if(Main.UnitLogic.CanCounter(Main.MapData, unitData, unitDataB) && Table.Instance.CalcDamage(Main.MapData, unitData, unitDataB,true) >= unitData.Health) { targetGridData.VFXRenderMarkDieHintStart = true; //1代表这是被杀死提示 targetGridData.VFXRenderMarkDieHintStartParam = 1; } ROUnitMap[unitDataB.Id].SetAttackHighlight(true); } } return ret; } //返回一个Unit是否存在移动或者攻击目标 public bool CheckUnitHasMoveAttackTarget(uint uid) { Main.UnitLogic.CalcUnitMoveInfo(Main.MapData, uid); Main.MapData.UnitMap.GetUnitDataByUnitId(uid, out var unitData); Main.MapData.GetGridDataByUnitId(uid, out var gridData); Main.MapData.GetPlayerDataByUnitId(uid, out var playerData); if (unitData.AP <= 0 && unitData.MP <= 0) return false; //unitLogic.DebugOutputMoveInfo(); int r = Mathf.Max((Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(unitData.UnitType,unitData.GiantType,unitData.UnitLevel,out var info)?info.MoveRange:0) * 2, Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(unitData.UnitType,unitData.GiantType,unitData.UnitLevel,out var info2)?info2.AttackRange:0); var targetGridDataList = Main.MapData.GridMap.GetAroundGridDataSet(r,r,gridData); foreach(var targetGridData in targetGridDataList) { //如果不在视野 跳过 if (!playerData.Sight.CheckIsInSight(targetGridData.Id)) continue; var sig = Main.UnitLogic.CheckUnitCanMoveOrAttack(Main.MapData, unitData, targetGridData); //如果是移动目标,且unit的MP>0 if ((sig == MoveAttackType.Move || sig == MoveAttackType.MoveToPort || sig == MoveAttackType.MoveAshore) && unitData.MP > 0) return true; //如果是攻击目标,且unit的AP>0 if (sig == MoveAttackType.Attack && unitData.AP > 0 && !unitData.IsLimitSelfAttack(Main.MapData)) return true; } return false; } //返回一个Unit是否当前可以占领遗迹/城市/收集starfish public bool CheckUnitHasSpecialUnitActionTarget(uint uid) { if (!_mapData.UnitMap.GetUnitDataByUnitId(uid, out var unit)) return false; if (!_mapData.GetGridDataByUnitId(uid, out var grid)) return false; if (!_mapData.GetPlayerDataByUnitId(uid, out var player)) return false; if (unit.CP <= 0) return false; //宝藏 if (grid.Resource == ResourceType.Treasure) return true; //海星 if (grid.Resource == ResourceType.Starfish && player.TechTree.CheckIfHasTech(TechType.Navigation)) return true; //城市 if (grid.Resource == ResourceType.CityCenter) { _mapData.GetPlayerDataByTerritoryGridId(grid.Id, out var gridPlayer); //村庄或者他国城市 if (gridPlayer == null) return true; if (gridPlayer.Id != player.Id) return true; } return false; } // 创建临时探索者并向视野最少的方向移动 public void CreateTemporaryExplorer(GridData gridData, float maxDuration) { // 获取玩家数据 - 使用领土所属关系获取 if (!Main.MapData.GetPlayerDataByTerritoryGridId(gridData.Id, out var playerData)) { Debug.LogWarning("无法获取玩家数据,无法创建探索者"); return; } // 检查是否是自己的玩家 bool isSelfPlayer = playerData.Id == Main.MapData.PlayerMap.SelfPlayerData.Id; // 如果不是自己的玩家,直接计算10步探索并更新视野,不进行渲染 if (!isSelfPlayer) { //Debug.Log("非自己玩家的探索者,直接计算探索路径"); // 重置移动计数和当前目标格子 _explorerMoveCount = 0; _currentTargetGridData = gridData; _explorerPreviousPosition = new Vector2Int(-1, -1); // 直接计算10步探索 for (int i = 0; i < _explorerMaxMoves; i++) { // 如果当前目标格子为空,结束探索 if (_currentTargetGridData == null) break; // 计算下一步移动 Vector2Int currentPos = new Vector2Int(_currentTargetGridData.Pos.X, _currentTargetGridData.Pos.Y); // 更新视野 Main.PlayerLogic.UpdateSightByRadius(Main.MapData, playerData, _currentTargetGridData, 1); // 保存当前位置作为上一个位置 Vector2Int prevPos = currentPos; _explorerPreviousPosition = prevPos; // 计算下一步移动方向(不渲染,只计算) CalculateNextExplorerMove(_currentTargetGridData, playerData, out var nextGridData); // 如果无法移动,结束探索 if (nextGridData == null) break; // 更新当前目标格子 _currentTargetGridData = nextGridData; _explorerMoveCount++; } // 完成探索后解锁输入 ,只有是玩家才需要解锁输入 if(playerData.Id == Main.MapData.PlayerMap.SelfPlayerId) _main.InputLogic.UnlockInput(); return; } // 以下是原有的渲染逻辑,只有自己的玩家才会执行 // 如果已经有临时探索者,先销毁 if (_temporaryExplorer != null) { GameObject.Destroy(_temporaryExplorer); _temporaryExplorer = null; } // 重置移动计数 _explorerMoveCount = 0; _currentTargetGridData = gridData; // 重置上一个位置为无效位置 _explorerPreviousPosition = new Vector2Int(-1, -1); // 获取城市位置的世界坐标 Vector3 worldPos = Table.Instance.GridToWorld(gridData, "isUnit"); // 创建一个简单的游戏对象作为临时探索者 _temporaryExplorer = new GameObject("TemporaryExplorer"); _temporaryExplorer.transform.position = worldPos; _temporaryExplorer.transform.SetParent(_unitRenderMap, false); // 创建一个子对象来持有SpriteRenderer GameObject spriteObject = new GameObject("UnitSprite"); spriteObject.transform.SetParent(_temporaryExplorer.transform, false); // 添加精灵渲染器到子对象 SpriteRenderer spriteRenderer = spriteObject.AddComponent(); // 获取UnitTypeInfo UnitType explorerUnitType = UnitType.Warrior; // 使用战士单位类型 if (Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(explorerUnitType, GiantType.None,0, out var unitTypeInfo)) { // 使用GetUnitSpriteByInfo方法获取精灵 if (Table.Instance.UnitTypeDataAssets.GetUnitSpriteByInfo(Main.MapData, unitTypeInfo, playerData, out var sprite)) { spriteRenderer.sprite = sprite; // 确保精灵渲染器设置正确 spriteRenderer.sortingLayerName = "Units"; spriteRenderer.sortingOrder = 10; // 确保显示在其他单位之上 Debug.Log($"临时探索者创建成功,使用精灵: {sprite.name}"); // 计算八个方向的视野情况并选择视野最少的方向移动 MoveExplorerToLeastVisibleDirection(gridData, playerData); } else { Debug.LogWarning("GetUnitSpriteByInfo方法获取精灵失败"); } } else { Debug.LogWarning("获取UnitTypeInfo失败"); } // 设置浮动动画参数 _temporaryExplorerStartPos = worldPos; _temporaryExplorerTime = 0f; _temporaryExplorerActive = true; } // 计算八个方向的视野情况并选择视野最少的方向移动 private void MoveExplorerToLeastVisibleDirection(GridData startGridData, PlayerData playerData) { // 当前位置 Vector2Int currentPos = new Vector2Int(startGridData.Pos.X, startGridData.Pos.Y); // 地图尺寸 int mapWidth = (int)Main.MapData.MapConfig.Width; int mapHeight = (int)Main.MapData.MapConfig.Height; // 存储每个方向的最近未探索格子距离 float[] directionMinDistance = new float[8]; for (int i = 0; i < 8; i++) { directionMinDistance[i] = float.MaxValue; // 初始化为最大值 } // 搜索半径 - 可以调整以提高性能 int searchRadius = 10; // 在搜索半径内查找未探索的格子 for (int x = Mathf.Max(0, currentPos.x - searchRadius); x < Mathf.Min(mapWidth, currentPos.x + searchRadius); x++) { for (int y = Mathf.Max(0, currentPos.y - searchRadius); y < Mathf.Min(mapHeight, currentPos.y + searchRadius); y++) { // 跳过当前位置 if (x == currentPos.x && y == currentPos.y) continue; // 获取格子数据 if (Main.MapData.GridMap.GetGridDataByPos(x, y, out var gridData)) { // 检查是否在视野中 if (!playerData.Sight.CheckIsInSight(gridData.Id)) { // 检查该格子是否可达 if (!IsGridReachable(startGridData, gridData, playerData, 20)) continue; // 计算相对位置 int dx = x - currentPos.x; int dy = y - currentPos.y; // 计算距离 float distance = Mathf.Sqrt(dx * dx + dy * dy); // 确定方向区块 int dirIndex = GetDirectionIndex(dx, dy); // 更新该方向的最小距离 if (distance < directionMinDistance[dirIndex]) { directionMinDistance[dirIndex] = distance; } } } } } // 找出未探索格子最近的方向,排除会导致回到上一个位置的方向 float minDistance = float.MaxValue; List bestDirections = new List(); for (int i = 0; i < 8; i++) { // 如果该方向没有未探索格子,跳过 if (directionMinDistance[i] == float.MaxValue) continue; // 计算该方向的下一个位置 Vector2Int dirVector = GetMoveDirectionFromIndex(i); Vector2Int nextPos = currentPos + dirVector; // 检查该位置是否在地图范围内 if (nextPos.x < 0 || nextPos.x >= mapWidth || nextPos.y < 0 || nextPos.y >= mapHeight) continue; // 检查该位置是否是上一个位置 if (_explorerPreviousPosition.x == nextPos.x && _explorerPreviousPosition.y == nextPos.y) continue; // 检查该位置是否可通行 if (!Main.MapData.GridMap.GetGridDataByPos(nextPos.x, nextPos.y, out var nextGridData)) continue; // 检查地形是否可通行 if (!IsTerrainPassable(nextGridData, playerData)) continue; if (directionMinDistance[i] < minDistance) { minDistance = directionMinDistance[i]; bestDirections.Clear(); bestDirections.Add(i); } else if (directionMinDistance[i] == minDistance) { bestDirections.Add(i); } } // 如果没有找到最佳方向,尝试任何可行方向(除了上一个位置) if (bestDirections.Count == 0) { for (int i = 0; i < 8; i++) { // 计算该方向的下一个位置 Vector2Int dirVector2 = GetMoveDirectionFromIndex(i); Vector2Int nextPos = currentPos + dirVector2; // 检查该位置是否在地图范围内 if (nextPos.x < 0 || nextPos.x >= mapWidth || nextPos.y < 0 || nextPos.y >= mapHeight) continue; // 检查该位置是否是上一个位置 if (_explorerPreviousPosition.x == nextPos.x && _explorerPreviousPosition.y == nextPos.y) continue; // 检查该位置是否可通行 if (!Main.MapData.GridMap.GetGridDataByPos(nextPos.x, nextPos.y, out var nextGridData)) continue; // 检查地形是否可通行 if (!IsTerrainPassable(nextGridData, playerData)) continue; bestDirections.Add(i); } } // 如果仍然没有找到可行方向,结束探索 if (bestDirections.Count == 0) { RemoveTemporaryExplorer(); Debug.LogWarning("YIWAI 3 UNLOCK!!!!!"); _main.InputLogic.UnlockInput(); return; } // 随机选择一个最佳方向 int selectedDirIndex = bestDirections[UnityEngine.Random.Range(0, bestDirections.Count)]; // 根据选择的方向确定移动的目标位置 Vector2Int finalMoveDir = GetMoveDirectionFromIndex(selectedDirIndex); Vector2Int targetPos = currentPos + finalMoveDir; // 获取目标格子数据 if (Main.MapData.GridMap.GetGridDataByPos(targetPos.x, targetPos.y, out var targetGridData)) { // 保存上一个位置 _explorerPreviousPosition = currentPos; // 更新视野 Main.PlayerLogic.UpdateSightByRadius(Main.MapData, playerData, targetGridData, 1); // 获取移动动画时间 float moveTime = 0.5f; if (Table.Instance.AnimDataAssets != null) { moveTime = Table.Instance.AnimDataAssets.MoveAnimTime; } // 应用动画速度调整 moveTime /= DebugCenter.Instance.AnimationSpeed; if(!_temporaryExplorer) { LogSystem.LogError($"_temporaryExplorer is null, cannot move explorer."); return; } // 设置移动参数 Vector3 targetWorldPos = Table.Instance.GridToWorld(targetGridData, "isUnit"); _explorerMoveStartPos = _temporaryExplorer.transform.position; _explorerMoveTargetPos = targetWorldPos; _explorerMoveTime = 0f; _explorerMoveDuration = moveTime; _explorerIsMoving = true; // 增加移动计数 _explorerMoveCount++; // 存储当前目标格子,用于移动完成后更新视野 _currentTargetGridData = targetGridData; } } // 修复GetDirectionIndex方法中的错误 private int GetDirectionIndex(int dx, int dy) { // 将dx和dy归一化为-1, 0, 1 int nx = dx == 0 ? 0 : (dx > 0 ? 1 : -1); int ny = dy == 0 ? 0 : (dy > 0 ? 1 : -1); // 根据归一化后的方向确定索引 switch (nx) { case 1: switch (ny) { case 1: return 1; // 右上 case 0: return 0; // 右 case -1: return 7; // 右下 } break; case 0: switch (ny) { case 1: return 2; // 上 case -1: return 6; // 下 } break; case -1: switch (ny) { case 1: return 3; // 左上 case 0: return 4; // 左 case -1: return 5; // 左下 } break; } // 默认返回右方向 return 0; } // 根据方向索引获取移动方向 private Vector2Int GetMoveDirectionFromIndex(int dirIndex) { switch (dirIndex) { case 0: return new Vector2Int(1, 0); // 右 case 1: return new Vector2Int(1, 1); // 右上 case 2: return new Vector2Int(0, 1); // 上 case 3: return new Vector2Int(-1, 1); // 左上 case 4: return new Vector2Int(-1, 0); // 左 case 5: return new Vector2Int(-1, -1); // 左下 case 6: return new Vector2Int(0, -1); // 下 case 7: return new Vector2Int(1, -1); // 右下 default: return new Vector2Int(0, 0); // 默认不移动 } } // 移除临时探索者 public void RemoveTemporaryExplorer() { if (_temporaryExplorer != null) { GameObject.Destroy(_temporaryExplorer); _temporaryExplorer = null; Debug.Log("临时探索者已移除"); } _temporaryExplorerActive = false; } // 新增辅助方法:计算下一步移动但不执行渲染 private bool CalculateNextExplorerMove(GridData startGridData, PlayerData playerData, out GridData nextGridData) { nextGridData = null; // 当前位置 Vector2Int currentPos = new Vector2Int(startGridData.Pos.X, startGridData.Pos.Y); // 地图尺寸 int mapWidth = (int)Main.MapData.MapConfig.Width; int mapHeight = (int)Main.MapData.MapConfig.Height; // 存储每个方向的最近未探索格子距离 float[] directionMinDistance = new float[8]; for (int i = 0; i < 8; i++) { directionMinDistance[i] = float.MaxValue; // 初始化为最大值 } // 搜索半径 int searchRadius = 10; // 在搜索半径内查找未探索的格子 for (int x = Mathf.Max(0, currentPos.x - searchRadius); x < Mathf.Min(mapWidth, currentPos.x + searchRadius); x++) { for (int y = Mathf.Max(0, currentPos.y - searchRadius); y < Mathf.Min(mapHeight, currentPos.y + searchRadius); y++) { // 跳过当前位置 if (x == currentPos.x && y == currentPos.y) continue; // 获取格子数据 if (Main.MapData.GridMap.GetGridDataByPos(x, y, out var gridData)) { // 检查是否在视野中 if (!playerData.Sight.CheckIsInSight(gridData.Id)) { // 检查该格子是否可达 if (!IsGridReachable(startGridData, gridData, playerData, 20)) continue; // 计算相对位置 int dx = x - currentPos.x; int dy = y - currentPos.y; // 计算距离 float distance = Mathf.Sqrt(dx * dx + dy * dy); // 确定方向区块 int dirIndex = GetDirectionIndex(dx, dy); // 更新该方向的最小距离 if (distance < directionMinDistance[dirIndex]) { directionMinDistance[dirIndex] = distance; } } } } } // 找出未探索格子最近的方向 float minDistance = float.MaxValue; List bestDirections = new List(); for (int i = 0; i < 8; i++) { // 如果该方向没有未探索格子,跳过 if (directionMinDistance[i] == float.MaxValue) continue; // 计算该方向的下一个位置 Vector2Int dirVector = GetMoveDirectionFromIndex(i); Vector2Int nextPos = currentPos + dirVector; // 检查该位置是否在地图范围内 if (nextPos.x < 0 || nextPos.x >= mapWidth || nextPos.y < 0 || nextPos.y >= mapHeight) continue; // 检查该位置是否是上一个位置 if (_explorerPreviousPosition.x == nextPos.x && _explorerPreviousPosition.y == nextPos.y) continue; // 检查该位置是否可通行 GridData tempNextGridData; if (!Main.MapData.GridMap.GetGridDataByPos(nextPos.x, nextPos.y, out tempNextGridData)) continue; // 检查地形是否可通行 if (!IsTerrainPassable(tempNextGridData, playerData)) continue; if (directionMinDistance[i] < minDistance) { minDistance = directionMinDistance[i]; bestDirections.Clear(); bestDirections.Add(i); } else if (directionMinDistance[i] == minDistance) { bestDirections.Add(i); } } // 如果没有找到最佳方向,尝试任何可行方向(除了上一个位置) if (bestDirections.Count == 0) { for (int i = 0; i < 8; i++) { // 计算该方向的下一个位置 Vector2Int dirVector2 = GetMoveDirectionFromIndex(i); Vector2Int nextPos = currentPos + dirVector2; // 检查该位置是否在地图范围内 if (nextPos.x < 0 || nextPos.x >= mapWidth || nextPos.y < 0 || nextPos.y >= mapHeight) continue; // 检查该位置是否是上一个位置 if (_explorerPreviousPosition.x == nextPos.x && _explorerPreviousPosition.y == nextPos.y) continue; // 检查该位置是否可通行 GridData tempNextGridData; if (!Main.MapData.GridMap.GetGridDataByPos(nextPos.x, nextPos.y, out tempNextGridData)) continue; // 检查地形是否可通行 if (!IsTerrainPassable(tempNextGridData, playerData)) continue; bestDirections.Add(i); } } // 如果仍然没有找到可行方向,返回失败 if (bestDirections.Count == 0) { return false; } // 随机选择一个最佳方向 int selectedDirIndex = bestDirections[UnityEngine.Random.Range(0, bestDirections.Count)]; // 根据选择的方向确定移动的目标位置 Vector2Int finalMoveDir = GetMoveDirectionFromIndex(selectedDirIndex); Vector2Int targetPos = currentPos + finalMoveDir; // 获取目标格子数据 return Main.MapData.GridMap.GetGridDataByPos(targetPos.x, targetPos.y, out nextGridData); } // 新增方法:检查地形是否可通行 private bool IsTerrainPassable(GridData gridData, PlayerData playerData) { // 检查地形是否可通行 if (gridData.Terrain == TerrainType.DeepSea && !playerData.TechTree.CheckIfHasTech(TechType.Sailing)) return false; if (gridData.Terrain == TerrainType.ShallowSea && !playerData.TechTree.CheckIfHasTech(TechType.Fishing)) return false; if (gridData.Feature == TerrainFeature.Mountain && !playerData.TechTree.CheckIfHasTech(TechType.Climbing)) return false; return true; } // 新增方法:使用BFS检查格子是否可达 private bool IsGridReachable(GridData startGrid, GridData targetGrid, PlayerData playerData, int maxSteps) { // 如果起点和终点相同,直接返回true if (startGrid.Id == targetGrid.Id) return true; // 如果目标格子地形不可通行,直接返回false if (!IsTerrainPassable(targetGrid, playerData)) return false; // 使用BFS搜索 Queue queue = new Queue(); HashSet visited = new HashSet(); Dictionary steps = new Dictionary(); queue.Enqueue(startGrid); visited.Add(startGrid.Id); steps[startGrid.Id] = 0; while (queue.Count > 0) { GridData current = queue.Dequeue(); int currentSteps = steps[current.Id]; // 如果已经超过最大步数,跳过 if (currentSteps >= maxSteps) continue; // 获取当前格子的八个方向的相邻格子 Vector2Int currentPos = new Vector2Int(current.Pos.X, current.Pos.Y); for (int i = 0; i < 8; i++) { Vector2Int dirVector = GetMoveDirectionFromIndex(i); Vector2Int nextPos = currentPos + dirVector; // 检查位置是否在地图范围内 if (nextPos.x < 0 || nextPos.x >= Main.MapData.MapConfig.Width || nextPos.y < 0 || nextPos.y >= Main.MapData.MapConfig.Height) continue; // 获取相邻格子数据 if (!Main.MapData.GridMap.GetGridDataByPos(nextPos.x, nextPos.y, out var nextGrid)) continue; // 如果已经访问过,跳过 if (visited.Contains(nextGrid.Id)) continue; // 检查地形是否可通行 if (!IsTerrainPassable(nextGrid, playerData)) continue; // 如果找到目标格子,返回true if (nextGrid.Id == targetGrid.Id) return true; // 将相邻格子加入队列 queue.Enqueue(nextGrid); visited.Add(nextGrid.Id); steps[nextGrid.Id] = currentSteps + 1; } } // 搜索完毕仍未找到目标格子,返回false return false; } public bool UpdateAroundAfterUnitDie(MapData mapData, GridData grid) { //如果不是真map,不操作 if (mapData != Main.MapData) return false; var set = mapData.GridMap.GetAroundGridDataSet(3, 3, grid); foreach (var aroundGrid in set) { //如果是玩家的unit 那么更新高亮 if (mapData.GetUnitDataByGid(aroundGrid.Id, out var unit) && mapData.GetPlayerIdByUnitId(unit.Id,out var pid) && pid == mapData.PlayerMap.SelfPlayerId) unit.RenderMark = true; } return true; } } }