260 lines
9.9 KiB
C#
260 lines
9.9 KiB
C#
using System.Collections.Generic;
|
||
using Gameplay;
|
||
using Gameplay.Character;
|
||
using Gameplay.Level;
|
||
using Gameplay.Unit;
|
||
using PhxhSDK;
|
||
|
||
public class AutoDeploymentManager : Singlenton<AutoDeploymentManager>
|
||
{
|
||
public bool IsAutoDeployEnabled { get; private set; } = true;
|
||
|
||
// 存储每个格子的前出等级
|
||
private Dictionary<int, float> _cellForwardScores = new Dictionary<int, float>();
|
||
|
||
// 敌人分组信息
|
||
private List<EnemyGroup> _enemyGroups = new List<EnemyGroup>();
|
||
|
||
// 记录已分配的格子
|
||
private HashSet<int> _occupiedCells = new HashSet<int>();
|
||
|
||
private class EnemyGroup
|
||
{
|
||
public int centerCellIndex; // 改用cellIndex替代世界坐标
|
||
public int count;
|
||
}
|
||
|
||
private const int GROUP_DISTANCE_THRESHOLD = 3; // 六边形格子距离阈值
|
||
|
||
private void GroupEnemies(List<GameUnit> enemies, Map map)
|
||
{
|
||
_enemyGroups.Clear();
|
||
|
||
foreach (var enemy in enemies)
|
||
{
|
||
var enemyCellIndex = enemy.transData.cellIndex;
|
||
var added = false;
|
||
|
||
// 尝试加入现有分组
|
||
foreach (var group in _enemyGroups)
|
||
{
|
||
// 使用 MapUtils.Distance 计算格子距离
|
||
int distance = MapUtils.Distance(map, enemyCellIndex, group.centerCellIndex);
|
||
if (distance <= GROUP_DISTANCE_THRESHOLD)
|
||
{
|
||
// 更新组中心格子
|
||
var oldCenterCell = group.centerCellIndex;
|
||
var newCenterCell =
|
||
CalculateGroupCenterCell(group.centerCellIndex, enemyCellIndex, group.count, map);
|
||
group.centerCellIndex = newCenterCell;
|
||
group.count++;
|
||
added = true;
|
||
// DebugUtil.LogError($"[GroupEnemies] 敌人(格子={enemyCellIndex})加入组(中心={oldCenterCell}->新中心={newCenterCell}, 数量={group.count})");
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 如果没有合适的分组,创建新分组
|
||
if (!added)
|
||
{
|
||
_enemyGroups.Add(new EnemyGroup
|
||
{
|
||
centerCellIndex = enemyCellIndex,
|
||
count = 1
|
||
});
|
||
// DebugUtil.LogError($"[GroupEnemies] 创建新敌人组: 中心格子 = {enemyCellIndex}, 数量 = 1");
|
||
}
|
||
}
|
||
// DebugUtil.LogError($"[GroupEnemies] 敌人分组完成,共 {_enemyGroups.Count} 个组");
|
||
}
|
||
|
||
private int CalculateGroupCenterCell(int currentCenterCell, int newCellIndex, int currentCount, Map map)
|
||
{
|
||
// 获取当前中心和新格子的世界坐标
|
||
var currentCenterPos = map.TGSCellIndex2WorldPosition(currentCenterCell);
|
||
var newCellPos = map.TGSCellIndex2WorldPosition(newCellIndex);
|
||
|
||
// 计算新的中心点位置
|
||
var newCenterPos = (currentCenterPos * currentCount + newCellPos) / (currentCount + 1);
|
||
|
||
// 找到最接近这个世界坐标的格子
|
||
map.WorldPosition2TGSCellIndex(newCenterPos, out int nearestCellIndex);
|
||
return nearestCellIndex;
|
||
}
|
||
|
||
public void AutoDeploy(Level level)
|
||
{
|
||
// 清空已分配格子记录
|
||
_occupiedCells.Clear();
|
||
|
||
// 1. 获取可用的己方单位
|
||
var availableUnits = new List<GameUnit>();
|
||
for (var i = 0; i < GameUnitManager.instance.totalUnits.count; i++)
|
||
{
|
||
var unit = GameUnitManager.instance.totalUnits.GetByIndex(i);
|
||
if (unit.commonData.troopId == ETroopsId.Self &&
|
||
!GameUnitManager.instance.infightUnits.Contains(unit.GetID()))
|
||
{
|
||
availableUnits.Add(unit);
|
||
}
|
||
}
|
||
// DebugUtil.LogError($"[AutoDeploy] 找到可用己方单位: {availableUnits.Count}个");
|
||
|
||
// 2. 获取敌方单位
|
||
var enemies = new List<GameUnit>();
|
||
for (var i = 0; i < GameUnitManager.instance.infightUnits.count; i++)
|
||
{
|
||
var unit = GameUnitManager.instance.infightUnits.GetByIndex(i);
|
||
if (unit.commonData.troopId != ETroopsId.Self)
|
||
{
|
||
enemies.Add(unit);
|
||
}
|
||
}
|
||
// DebugUtil.LogError($"[AutoDeploy] 找到敌方单位: {enemies.Count}个");
|
||
|
||
// 3. 对敌人进行分组
|
||
GroupEnemies(enemies, level.Map);
|
||
|
||
// 4. 计算每个格子的前出等级
|
||
CalculateCellForwardScores(level.Map.MapData, level.GetLevelData().preparingRegionId);
|
||
// DebugUtil.LogError($"[AutoDeploy] 格子前出等级计算完成,共 {_cellForwardScores.Count} 个格子");
|
||
|
||
// 5. 对可用单位按前出程度排序
|
||
var sortedUnits = new List<GameUnit>(availableUnits);
|
||
UnitDeploymentSorter.SortUnitsForDeployment(sortedUnits);
|
||
// DebugUtil.LogError("[AutoDeploy] 单位按前出程度排序完成");
|
||
|
||
// 6. 为每个单位分配位置
|
||
int deployedCount = 0;
|
||
foreach(var unit in sortedUnits)
|
||
{
|
||
var bestCell = FindBestCellForUnit(unit);
|
||
if (bestCell >= 0)
|
||
{
|
||
var yaw = LevelUtils.SetCharaterToward(level.GetLevelData().preparingRegionToward);
|
||
|
||
// 部署单位
|
||
GameUnitManager.instance.MoveUnitToFight(unit.GetID(), bestCell, yaw);
|
||
|
||
// 标记格子为已占用
|
||
_occupiedCells.Add(bestCell);
|
||
deployedCount++;
|
||
|
||
// DebugUtil.LogError($"[AutoDeploy] 部署单位: ID = {unit.GetID()}, 职业 = {unit.commonData.eJob}, 格子 = {bestCell}");
|
||
}
|
||
else
|
||
{
|
||
// DebugUtil.LogError($"[AutoDeploy] 未找到合适格子部署单位: ID = {unit.GetID()}, 职业 = {unit.commonData.eJob}");
|
||
}
|
||
}
|
||
// DebugUtil.LogError($"[AutoDeploy] 自动部署完成,成功部署 {deployedCount}/{sortedUnits.Count} 个单位");
|
||
}
|
||
|
||
private int FindBestCellForUnit(GameUnit unit)
|
||
{
|
||
var unitForwardLevel = UnitForwardLevelHelper.GetUnitForwardLevel(unit);
|
||
var bestScore = float.MinValue;
|
||
var bestCell = -1;
|
||
|
||
// DebugUtil.LogError($"[FindBestCellForUnit] 为单位寻找最佳格子: ID = {unit.GetID()}, 职业 = {unit.commonData.eJob}, 前出等级 = {unitForwardLevel}");
|
||
|
||
// 遍历所有计算过前出等级的格子
|
||
foreach (var kvp in _cellForwardScores)
|
||
{
|
||
var cellIndex = kvp.Key;
|
||
var score = kvp.Value;
|
||
|
||
// 检查格子是否已被占用(使用 HashSet 直接检查)
|
||
if (_occupiedCells.Contains(cellIndex)) continue;
|
||
|
||
// 根据单位的前出程度调整分数
|
||
var adjustedScore = score * unitForwardLevel;
|
||
|
||
if (adjustedScore > bestScore)
|
||
{
|
||
bestScore = adjustedScore;
|
||
bestCell = cellIndex;
|
||
}
|
||
}
|
||
|
||
/*if (bestCell >= 0)
|
||
{
|
||
DebugUtil.LogError($"[FindBestCellForUnit] 找到最佳格子: {bestCell}, 调整后评分 = {bestScore}");
|
||
}
|
||
else
|
||
{
|
||
DebugUtil.LogError($"[FindBestCellForUnit] 未找到合适格子");
|
||
}*/
|
||
|
||
return bestCell;
|
||
}
|
||
|
||
private void CalculateCellForwardScores(MapData mapData, int preparingRegionId)
|
||
{
|
||
// DebugUtil.LogError("[CalculateCellForwardScores] 开始计算格子前出等级");
|
||
_cellForwardScores.Clear();
|
||
var preparingRegion = mapData.GetRegion(preparingRegionId);
|
||
if (preparingRegion == null)
|
||
{
|
||
// DebugUtil.LogError($"[CalculateCellForwardScores] 错误:找不到准备区域(ID={preparingRegionId})");
|
||
return;
|
||
}
|
||
|
||
// DebugUtil.LogError($"[CalculateCellForwardScores] 准备区域格子数: {preparingRegion.positions.Count}");
|
||
|
||
// 对准备区域的每个格子计算分数
|
||
foreach (var cellIndex in preparingRegion.positions)
|
||
{
|
||
float score = 0;
|
||
|
||
// 计算与所有敌人组的距离评分
|
||
foreach (var group in _enemyGroups)
|
||
{
|
||
// 使用 MapUtils.Distance 计算格子距离
|
||
int distance = MapUtils.Distance(
|
||
LevelManager.Instance.CurrentLevel.Map,
|
||
cellIndex,
|
||
group.centerCellIndex);
|
||
// 距离越近分数越高,同时考虑敌人组的数量权重
|
||
// 使用 1.0f / (distance + 1) 确保不会除以0,并且距离越近分数越高
|
||
var groupScore = (1.0f / (distance + 1)) * group.count;
|
||
score += groupScore;
|
||
}
|
||
|
||
_cellForwardScores[cellIndex] = score;
|
||
}
|
||
|
||
/*// 记录最高分和最低分
|
||
if (_cellForwardScores.Count > 0)
|
||
{
|
||
var maxScore = _cellForwardScores.Max(p => p.Value);
|
||
var minScore = _cellForwardScores.Min(p => p.Value);
|
||
DebugUtil.LogError($"[CalculateCellForwardScores] 格子评分范围: 最低 = {minScore}, 最高 = {maxScore}");
|
||
}
|
||
|
||
DebugUtil.LogError($"[CalculateCellForwardScores] 计算完成,共 {_cellForwardScores.Count} 个格子");*/
|
||
}
|
||
|
||
public void SetAutoDeployEnabled(bool enabled)
|
||
{
|
||
IsAutoDeployEnabled = enabled;
|
||
// DebugUtil.LogError($"[SetAutoDeployEnabled] 自动部署功能已{(enabled ? "启用" : "禁用")}");
|
||
if (enabled && LevelManager.Instance.CurrentLevel != null)
|
||
{
|
||
AutoDeploy(LevelManager.Instance.CurrentLevel);
|
||
}
|
||
}
|
||
|
||
public void OnLevelPreparationStart()
|
||
{
|
||
if (IsAutoDeployEnabled)
|
||
{
|
||
DebugUtil.Log("[OnLevelPreparationStart] 自动部署功能已启用,开始执行自动部署");
|
||
AutoDeploy(LevelManager.Instance.CurrentLevel);
|
||
}
|
||
else
|
||
{
|
||
DebugUtil.Log("[OnLevelPreparationStart] 自动部署功能未启用,跳过自动部署");
|
||
}
|
||
}
|
||
} |