2025-09-30 16:04:50 +08:00

1150 lines
49 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.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 BubbleManager BubbleManager;
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<uint, GridRenderer> ROGridMap;
public Dictionary<uint, CityInfoRenderer> ROCityInfoMap;
public Dictionary<uint, UnitRenderer> 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交互部分 --------//
//移动和攻击的高亮RenderDataset中存放了所有需要更新的对象
public HashSet<uint> HighlightGridIdSet = new HashSet<uint>();
public bool HighlightGridIdSetRenderMark = false;
public HashSet<uint> HighlightUnitIdSet = new HashSet<uint>();
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<uint, GridRenderer>();
ROCityInfoMap = new Dictionary<uint, CityInfoRenderer>();
ROUnitMap = new Dictionary<uint, UnitRenderer>();
// 初始化主要的渲染模块(grid city unit projectileManager)
InitGridCityUnitObject();
//初始化相机模块
InitCameraObject();
//初始化HintManager
BubbleManager = new BubbleManager();
BubbleManager.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<Transform>();
//清理战场把上一局Grid里面留下的东西清理干净
ClearAllChildren(_unitRenderMap);
ClearAllChildren(_gridRenderMap);
ClearAllChildren(_cityInfoRenderMap);
ClearAllChildren(HintRenderMap);
ClearAllChildren(ROMap.transform.Find("ProjectileMap"));
_unitPrefab = Resources.Load<GameObject>($"Prefab/unitPrefab");
_gridPrefab = Resources.Load<GameObject>($"Prefab/tilePrefab");
_cityInfoPrefab = Resources.Load<GameObject>($"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<CameraController>();
return true;
}
public void Update()
{
//处理所有飞行道具。这个不会被暂停
ProjectileManager.Update();
//HintManager
BubbleManager.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<uint> toRemove = new List<uint>();
foreach (var roUnitId in ROUnitMap.Keys)
{
if (!Main.MapData.UnitMap.GetUnitDataByUnitId(roUnitId, out var unitData))
toRemove.Add(roUnitId);
}
foreach (var roUnitId in toRemove)
{
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);
}
}
//当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.CalcCounterDamage(Main.MapData, unitData,unitDataB) >= unitData.Health
&& unitData.GetUnitFullType.UnitType != UnitType.Minder)
{
targetGridData.VFXRenderMarkDieHintStart = true;
//1代表这是被杀死提示
targetGridData.VFXRenderMarkDieHintStartParam = 1;
}
ROUnitMap[unitDataB.Id].SetAttackHighlight(true);
}
//如果是友军目标且unit的AP>0
if (sig == MoveAttackType.Ally && unitData.AP > 0)
{
ret = true;
if (!Main.MapData.GetUnitDataByGid(targetGridData.Id, out var unitDataB))
continue;
ROUnitMap[unitDataB.Id].SetAllyHighlight(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;
//如果是Ally目标且unit的AP>0
if (sig == MoveAttackType.Ally && unitData.AP > 0 )
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<SpriteRenderer>();
// 获取UnitTypeInfo
UnitType explorerUnitType = UnitType.Warrior; // 使用战士单位类型
if (Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(explorerUnitType, GiantType.None,0, out var unitTypeInfo))
{
// 使用GetUnitSpriteByInfo方法获取精灵
if (Table.Instance.UnitTypeDataAssets.GetUnitSpriteByInfo(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<int> bestDirections = new List<int>();
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<int> bestDirections = new List<int>();
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<GridData> queue = new Queue<GridData>();
HashSet<uint> visited = new HashSet<uint>();
Dictionary<uint, int> steps = new Dictionary<uint, int>();
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;
}
}
}