fix 1
1. 修复投射物闪避口径(使用 Value,与全局伤害逻辑一致) - 将 SimulationWorld 内投射物伤害计算改为直接复用 AIUtility.CalcDamageHP(...)。 - 删除了 SimulationWorld 里那套重复且使用 dodgeStat.Percent 的私有计算函数,避免再次分叉。 2. 修复目标选择索引“重建过于激进” - 去掉了 Job Tick 末尾的“每帧强制 MarkDirty + Build”。 - 改为在 Job 输出回写时,只有敌人 XZ 坐标发生变化才标记 dirty。 - 空间索引构建条件改为“仅 dirty 时重建”,不再因跨帧自动重建。
This commit is contained in:
parent
1a45b513f2
commit
688fefe848
|
|
@ -226,9 +226,6 @@ namespace Simulation
|
|||
RecycleInactiveProjectiles();
|
||||
}
|
||||
}
|
||||
|
||||
MarkEnemyTargetSpatialIndexDirty();
|
||||
BuildEnemyTargetSpatialIndexIfNeeded();
|
||||
}
|
||||
|
||||
private JobHandle ExecuteEnemyMovementJob(in SimulationTickContext context)
|
||||
|
|
|
|||
|
|
@ -619,9 +619,23 @@ namespace Simulation
|
|||
private void ApplyJobOutputToSimulation()
|
||||
{
|
||||
int enemyCount = Mathf.Min(_enemies.Count, _enemyJobOutputs.Length);
|
||||
bool hasEnemyPositionChanged = false;
|
||||
for (int i = 0; i < enemyCount; i++)
|
||||
{
|
||||
_enemies[i] = ConvertToEnemySimData(_enemyJobOutputs[i]);
|
||||
EnemyJobOutputData output = _enemyJobOutputs[i];
|
||||
if (!hasEnemyPositionChanged)
|
||||
{
|
||||
Vector3 currentPosition = _enemies[i].Position;
|
||||
hasEnemyPositionChanged = currentPosition.x != output.Position.x ||
|
||||
currentPosition.z != output.Position.z;
|
||||
}
|
||||
|
||||
_enemies[i] = ConvertToEnemySimData(output);
|
||||
}
|
||||
|
||||
if (hasEnemyPositionChanged)
|
||||
{
|
||||
MarkEnemyTargetSpatialIndexDirty();
|
||||
}
|
||||
|
||||
int projectileCount = Mathf.Min(_projectiles.Count, _projectileJobOutputs.Length);
|
||||
|
|
|
|||
|
|
@ -453,7 +453,7 @@ namespace Simulation
|
|||
return false;
|
||||
}
|
||||
|
||||
damage = CalculateProjectileDamage(sourceImpact.AttackBase, sourceImpact.AttackStat,
|
||||
damage = AIUtility.CalcDamageHP(sourceImpact.AttackBase, sourceImpact.AttackStat,
|
||||
targetImpact.DefenseStat,
|
||||
targetImpact.DodgeStat);
|
||||
shouldDispatchPresentation = true;
|
||||
|
|
@ -537,36 +537,6 @@ namespace Simulation
|
|||
return false;
|
||||
}
|
||||
|
||||
private static int CalculateProjectileDamage(int attack, StatProperty attackStat, StatProperty defenseStat,
|
||||
StatProperty dodgeStat)
|
||||
{
|
||||
if (dodgeStat != null)
|
||||
{
|
||||
if (UnityEngine.Random.value < Mathf.Clamp(dodgeStat.Percent, 0f, 0.9f))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
float damage = attack;
|
||||
if (attackStat != null)
|
||||
{
|
||||
damage = (attack + attackStat.Value) * attackStat.Percent;
|
||||
}
|
||||
|
||||
if (defenseStat != null)
|
||||
{
|
||||
damage = (damage - defenseStat.Value) / defenseStat.Percent;
|
||||
}
|
||||
|
||||
if (damage < 1f)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return Mathf.CeilToInt(damage);
|
||||
}
|
||||
|
||||
private static bool TryGetTargetableEntity(int entityId, out TargetableObject target)
|
||||
{
|
||||
target = null;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ namespace Simulation
|
|||
{
|
||||
private NativeParallelMultiHashMap<long, int> _enemyTargetBuckets;
|
||||
private bool _enemyTargetBucketsDirty = true;
|
||||
private int _enemyTargetBucketsFrame = -1;
|
||||
|
||||
[SerializeField] private float _targetSelectionCellSize = 2f;
|
||||
|
||||
|
|
@ -85,7 +84,6 @@ namespace Simulation
|
|||
|
||||
_enemyTargetBuckets = new NativeParallelMultiHashMap<long, int>(256, Allocator.Persistent);
|
||||
_enemyTargetBucketsDirty = true;
|
||||
_enemyTargetBucketsFrame = -1;
|
||||
}
|
||||
|
||||
private void DisposeEnemyTargetSpatialIndex()
|
||||
|
|
@ -97,7 +95,6 @@ namespace Simulation
|
|||
|
||||
_enemyTargetBuckets = default;
|
||||
_enemyTargetBucketsDirty = true;
|
||||
_enemyTargetBucketsFrame = -1;
|
||||
}
|
||||
|
||||
private void ClearEnemyTargetSpatialIndex()
|
||||
|
|
@ -108,20 +105,18 @@ namespace Simulation
|
|||
}
|
||||
|
||||
_enemyTargetBucketsDirty = true;
|
||||
_enemyTargetBucketsFrame = -1;
|
||||
}
|
||||
|
||||
private void MarkEnemyTargetSpatialIndexDirty()
|
||||
{
|
||||
_enemyTargetBucketsDirty = true;
|
||||
_enemyTargetBucketsFrame = -1;
|
||||
}
|
||||
|
||||
private void BuildEnemyTargetSpatialIndexIfNeeded()
|
||||
{
|
||||
InitializeEnemyTargetSpatialIndex();
|
||||
|
||||
if (!_enemyTargetBucketsDirty && _enemyTargetBucketsFrame == Time.frameCount)
|
||||
if (!_enemyTargetBucketsDirty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -148,7 +143,6 @@ namespace Simulation
|
|||
}
|
||||
|
||||
_enemyTargetBucketsDirty = false;
|
||||
_enemyTargetBucketsFrame = Time.frameCount;
|
||||
}
|
||||
|
||||
private float GetTargetSelectionCellSize()
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
schema: spec-driven
|
||||
|
||||
# Project context (optional)
|
||||
# This is shown to AI when creating artifacts.
|
||||
# Add your tech stack, conventions, style guides, domain knowledge, etc.
|
||||
# Example:
|
||||
# context: |
|
||||
# Tech stack: TypeScript, React, Node.js
|
||||
# We use conventional commits
|
||||
# Domain: e-commerce platform
|
||||
|
||||
# Per-artifact rules (optional)
|
||||
# Add custom rules for specific artifacts.
|
||||
# Example:
|
||||
# rules:
|
||||
# proposal:
|
||||
# - Keep proposals under 500 words
|
||||
# - Always include a "Non-goals" section
|
||||
# tasks:
|
||||
# - Break tasks into chunks of max 2 hours
|
||||
Loading…
Reference in New Issue