This commit is contained in:
2026-03-03 17:30:02 +08:00
parent e1dea4059c
commit 14c3654846
10 changed files with 711 additions and 86 deletions

View File

@@ -36,7 +36,11 @@ namespace WulaFallenEmpire
// === 缓存 ===
private CellRect collisionAreaCache = default;
private int lastAreaRecalculationTick = -1;
// === 地形阻挡相关 ===
private float currentTerrainBlockSeverity = 0f;
private int lastTerrainCheckTick = -1;
public CompProperties_HighSpeedCollision Props => (CompProperties_HighSpeedCollision)props;
public override void PostSpawnSetup(bool respawningAfterLoad)
@@ -53,29 +57,169 @@ namespace WulaFallenEmpire
lastPosition = parent.Position;
lastPositionTick = Find.TickManager.TicksGame;
}
public override void CompTick()
{
base.CompTick();
if (!parent.Spawned || parent.Destroyed)
return;
Pawn pawn = parent as Pawn;
if (pawn == null || pawn.Dead || pawn.Downed)
return;
// 检查是否死亡或不能移动
if (!CanMove(pawn))
{
ResetToStage0();
return;
}
// 每帧更新
ProcessFrame(pawn);
// 地形阻挡检查(降低频率)
if (Props.narrowTerrainBlocked &&
(Find.TickManager.TicksGame - lastTerrainCheckTick >= Props.terrainCheckInterval))
{
UpdateTerrainBlockStatus(pawn);
lastTerrainCheckTick = Find.TickManager.TicksGame;
}
}
/// <summary>
/// 更新地形阻挡状态
/// </summary>
private void UpdateTerrainBlockStatus(Pawn pawn)
{
if (!Props.narrowTerrainBlocked || Props.maxBlockPenalty <= 0f)
{
currentTerrainBlockSeverity = 0f;
UpdateBlockedHediff(pawn, 0f);
return;
}
// 获取碰撞区域
CellRect collisionArea = GetCollisionArea(pawn);
// 统计空闲格子和被占据格子
int totalCells = 0;
int occupiedCells = 0;
foreach (IntVec3 cell in collisionArea)
{
if (!cell.InBounds(pawn.Map))
continue;
totalCells++;
// 检查是否被不可通行建筑占据
if (IsCellBlockedByImpassable(cell, pawn.Map))
{
occupiedCells++;
}
}
// 计算阻挡严重度
float blockSeverity = CalculateBlockSeverity(totalCells, occupiedCells);
// 立即设置阻挡严重度(移除平滑过渡)
currentTerrainBlockSeverity = blockSeverity;
// 更新Hediff
UpdateBlockedHediff(pawn, currentTerrainBlockSeverity);
// 调试日志
if (Props.enableDebugLogging && currentTerrainBlockSeverity > 0.01f)
{
Log.Message($"[HighSpeedCollision] Terrain Block: {pawn.Label}, " +
$"Occupied: {occupiedCells}/{totalCells}, " +
$"Severity: {currentTerrainBlockSeverity:P0}");
}
}
/// <summary>
/// 检查单元格是否被不可通行建筑占据
/// </summary>
private bool IsCellBlockedByImpassable(IntVec3 cell, Map map)
{
// 获取单元格内的所有建筑
var things = cell.GetThingList(map);
foreach (var thing in things)
{
if (thing is Building building)
{
// 检查是否可通行
if (building.def.passability == Traversability.Impassable)
{
return true;
}
}
}
return false;
}
/// <summary>
/// 计算阻挡严重度
/// </summary>
private float CalculateBlockSeverity(int totalCells, int occupiedCells)
{
if (totalCells == 0 || occupiedCells == 0)
return 0f;
int freeCells = totalCells - occupiedCells;
float freeRatio = (float)freeCells / totalCells;
// 使用公式:(1 - maxBlockPenalty) + maxBlockPenalty * (空闲格子/(空闲格子+被占据格子))
// 简化后1 - maxBlockPenalty + maxBlockPenalty * (freeCells / totalCells)
// 但实际上,我们应该计算减速比例,然后转换为严重度
float speedMultiplier = (1f - Props.maxBlockPenalty) +
Props.maxBlockPenalty * (freeRatio);
// 严重度 = 1 - 速度乘数
return 1f - speedMultiplier;
}
/// <summary>
/// 平滑过渡
/// </summary>
private float SmoothTransition(float current, float target, float speed)
{
if (Mathf.Abs(current - target) < 0.01f)
return target;
return Mathf.Lerp(current, target, speed);
}
/// <summary>
/// 更新阻挡Hediff
/// </summary>
private void UpdateBlockedHediff(Pawn pawn, float severity)
{
if (Props.blockedHediff == null)
return;
// 获取或添加Hediff
Hediff hediff = pawn.health.hediffSet.GetFirstHediffOfDef(Props.blockedHediff);
if (severity <= 0.01f)
{
// 移除Hediff
if (hediff != null)
{
pawn.health.RemoveHediff(hediff);
}
return;
}
// 添加或更新Hediff
if (hediff == null)
{
hediff = HediffMaker.MakeHediff(Props.blockedHediff, pawn);
pawn.health.AddHediff(hediff);
}
// 更新严重度
hediff.Severity = severity;
}
/// <summary>
/// 获取当前地形阻挡严重度供HediffComp使用
/// </summary>
public float GetCurrentTerrainBlockSeverity()
{
return currentTerrainBlockSeverity;
}
/// <summary>
/// 处理每帧逻辑
/// </summary>
@@ -846,7 +990,28 @@ namespace WulaFallenEmpire
/// 绘制速度历史图
/// </summary>
public bool debugDrawSpeedHistory = false;
// === 狭窄地形阻挡配置 ===
/// <summary>
/// 是否启用狭窄地形阻挡
/// </summary>
public bool narrowTerrainBlocked = false;
/// <summary>
/// 最高阻挡减益值0-1之间
/// </summary>
public float maxBlockPenalty = 0.5f;
/// <summary>
/// 地形检查间隔ticks
/// </summary>
public int terrainCheckInterval = 60;
/// <summary>
/// 阻挡减益Hediff定义
/// </summary>
public HediffDef blockedHediff;
public CompProperties_HighSpeedCollision()
{
compClass = typeof(CompHighSpeedCollision);

View File

@@ -48,9 +48,9 @@ namespace WulaFallenEmpire
private int lastAttackTargetTick;
// 集中火力目标
private static LocalTargetInfo focusTarget = LocalTargetInfo.Invalid;
private static int lastFocusSetTick = 0;
private static Thing lastFocusPawn = null;
public static LocalTargetInfo focusTarget = LocalTargetInfo.Invalid;
public static int lastFocusSetTick = 0;
public static Thing lastFocusPawn = null;
// Gizmo 缓存
private Command_Toggle cachedGizmo;
@@ -278,8 +278,8 @@ namespace WulaFallenEmpire
}
}
}
private void TryAcquireTarget()
public void TryAcquireTarget()
{
// 1. 首先检查是否有集中火力目标且可以对其开火
if (focusTarget.IsValid && focusTarget.Thing != null && focusTarget.Thing.Spawned)
@@ -690,7 +690,7 @@ namespace WulaFallenEmpire
if (IsMasterTurret)
{
// 如果有集中火力目标,添加清除按钮
if (focusTarget.IsValid && lastFocusPawn == parent)
if (focusTarget.IsValid && focusTarget != null && lastFocusPawn == parent)
{
cachedFocusGizmo.defaultLabel = "Wula_ClearFocus".Translate();
cachedFocusGizmo.defaultDesc = "Wula_ClearFocusDesc".Translate();
@@ -713,7 +713,7 @@ namespace WulaFallenEmpire
private void ShowTargetSelectMenu()
{
// 如果已经有集中火力目标,清除它
if (focusTarget.IsValid && lastFocusPawn == parent)
if (focusTarget.IsValid && focusTarget != null && lastFocusPawn == parent)
{
focusTarget = LocalTargetInfo.Invalid;
return;