fix 2
1. MaxTargets 现在严格生效(包含玩家候选) - 玩家先被加入候选后,会计入 selectedCount,达到上限后不再继续查敌人桶。 2. UseSimulationMovement/UseJobSimulation 战斗中不生效 - 在 SimulationWorld 的 setter 中增加 Battle 状态保护:战斗中调用会被忽略并打 warning。 - 在 ProcedureGame 暴露当前状态类型,供 SimulationWorld 判断。 3. AOE 结算不再依赖结算时刻的 Weapon.IsAttacking - 在 AOE query 入队时快照 source 活跃状态(武器用 IsAttacking)。 - Query 数据结构增加 SourceWasActiveAtQueryTime。 - 结算时使用该快照判定,并通过 AIUtility.PerformCollision(..., ignoreRuntimeState: true) 避免被实时状态误伤。
This commit is contained in:
parent
688fefe848
commit
76094b711b
|
|
@ -35,6 +35,7 @@ namespace Procedure
|
|||
public Player Player;
|
||||
|
||||
public GameStateBase CurrentGameState => _gameStates[_currentGameState];
|
||||
public GameStateType CurrentGameStateType => _currentGameState;
|
||||
|
||||
private void InitGameState()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ namespace Simulation
|
|||
public int SourceType;
|
||||
public int SourceEntityId;
|
||||
public int SourceOwnerEntityId;
|
||||
public bool SourceWasActiveAtQueryTime;
|
||||
public float3 Position;
|
||||
public float Radius;
|
||||
public int MaxTargets;
|
||||
|
|
@ -98,6 +99,7 @@ namespace Simulation
|
|||
{
|
||||
public int SourceEntityId;
|
||||
public int SourceOwnerEntityId;
|
||||
public bool SourceWasActiveAtQueryTime;
|
||||
public Vector3 Center;
|
||||
public float Radius;
|
||||
public int MaxTargets;
|
||||
|
|
@ -474,6 +476,7 @@ namespace Simulation
|
|||
SourceType = CollisionSourceTypeProjectile,
|
||||
SourceEntityId = projectile.EntityId,
|
||||
SourceOwnerEntityId = projectile.OwnerEntityId,
|
||||
SourceWasActiveAtQueryTime = true,
|
||||
Position = projectile.Position,
|
||||
Radius = radius,
|
||||
MaxTargets = math.max(1, maxTargets),
|
||||
|
|
@ -483,8 +486,9 @@ namespace Simulation
|
|||
});
|
||||
}
|
||||
|
||||
private void AddAreaCollisionQuery(int queryId, int sourceEntityId, int sourceOwnerEntityId, in Vector3 center,
|
||||
float radius, int maxTargets, int shapeType, in Vector3 direction, float halfAngleDeg)
|
||||
private void AddAreaCollisionQuery(int queryId, int sourceEntityId, int sourceOwnerEntityId,
|
||||
bool sourceWasActiveAtQueryTime, in Vector3 center, float radius, int maxTargets, int shapeType,
|
||||
in Vector3 direction, float halfAngleDeg)
|
||||
{
|
||||
if (!_collisionQueryInputs.IsCreated || radius <= 0f)
|
||||
{
|
||||
|
|
@ -508,6 +512,7 @@ namespace Simulation
|
|||
SourceType = CollisionSourceTypeArea,
|
||||
SourceEntityId = sourceEntityId,
|
||||
SourceOwnerEntityId = sourceOwnerEntityId,
|
||||
SourceWasActiveAtQueryTime = sourceWasActiveAtQueryTime,
|
||||
Position = new float3(center.x, center.y, center.z),
|
||||
Radius = radius,
|
||||
MaxTargets = math.max(1, maxTargets),
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ namespace Simulation
|
|||
}
|
||||
|
||||
int resolvedOwnerEntityId = sourceOwnerEntityId != 0 ? sourceOwnerEntityId : sourceEntityId;
|
||||
bool sourceWasActiveAtQueryTime = IsCollisionSourceActiveAtQueryTime(sourceEntityId);
|
||||
Vector3 normalizedDirection = direction;
|
||||
normalizedDirection.y = 0f;
|
||||
if (normalizedDirection.sqrMagnitude <= Mathf.Epsilon)
|
||||
|
|
@ -121,6 +122,7 @@ namespace Simulation
|
|||
{
|
||||
SourceEntityId = sourceEntityId,
|
||||
SourceOwnerEntityId = resolvedOwnerEntityId,
|
||||
SourceWasActiveAtQueryTime = sourceWasActiveAtQueryTime,
|
||||
Center = center,
|
||||
Radius = Mathf.Max(0.01f, radius),
|
||||
MaxTargets = Mathf.Max(1, maxTargets),
|
||||
|
|
@ -238,8 +240,9 @@ namespace Simulation
|
|||
for (int i = 0; i < areaQueryCount; i++)
|
||||
{
|
||||
AreaCollisionRequestData request = _areaCollisionRequests[i];
|
||||
AddAreaCollisionQuery(queryId, request.SourceEntityId, request.SourceOwnerEntityId, in request.Center,
|
||||
request.Radius, request.MaxTargets, request.ShapeType, in request.Direction, request.HalfAngleDeg);
|
||||
AddAreaCollisionQuery(queryId, request.SourceEntityId, request.SourceOwnerEntityId,
|
||||
request.SourceWasActiveAtQueryTime, in request.Center, request.Radius, request.MaxTargets,
|
||||
request.ShapeType, in request.Direction, request.HalfAngleDeg);
|
||||
queryId++;
|
||||
builtAreaQueryCount++;
|
||||
if (request.Radius > maxQueryRadius)
|
||||
|
|
@ -628,6 +631,11 @@ namespace Simulation
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!query.SourceWasActiveAtQueryTime)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
EntityBase sourceEntity = TryGetEntityById(hitEvent.SourceEntityId);
|
||||
if (sourceEntity == null || !sourceEntity.Available)
|
||||
{
|
||||
|
|
@ -644,7 +652,7 @@ namespace Simulation
|
|||
continue;
|
||||
}
|
||||
|
||||
AIUtility.PerformCollision(target, sourceEntity);
|
||||
AIUtility.PerformCollision(target, sourceEntity, true);
|
||||
resolvedHitCount++;
|
||||
}
|
||||
|
||||
|
|
@ -787,10 +795,16 @@ namespace Simulation
|
|||
{
|
||||
areaCandidateCount++;
|
||||
}
|
||||
|
||||
selectedCount++;
|
||||
if (selectedCount >= query.MaxTargets)
|
||||
{
|
||||
reachedLimit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasEnemyTargets)
|
||||
if (!hasEnemyTargets || reachedLimit)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -893,6 +907,27 @@ namespace Simulation
|
|||
return projectile.LifeTime > 0f && projectile.Age >= projectile.LifeTime;
|
||||
}
|
||||
|
||||
private static bool IsCollisionSourceActiveAtQueryTime(int sourceEntityId)
|
||||
{
|
||||
EntityBase sourceEntity = TryGetEntityById(sourceEntityId);
|
||||
if (sourceEntity == null || !sourceEntity.Available)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sourceEntity is WeaponBase weapon)
|
||||
{
|
||||
return weapon.IsAttacking;
|
||||
}
|
||||
|
||||
if (sourceEntity is EnemyProjectile projectile)
|
||||
{
|
||||
return projectile.IsActive;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void ExecuteProjectileMovement(int index, NativeArray<ProjectileJobInputData> inputs,
|
||||
NativeArray<ProjectileJobOutputData> outputs, float deltaTime, float3 playerPosition,
|
||||
float maxSqrDistanceFromPlayer, float maxVerticalOffsetFromPlayer)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using CustomDebugger;
|
|||
using CustomUtility;
|
||||
using Entity;
|
||||
using Entity.EntityData;
|
||||
using Procedure;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
|
|
@ -69,11 +70,23 @@ namespace Simulation
|
|||
|
||||
public void SetUseSimulationMovement(bool enabled)
|
||||
{
|
||||
if (IsBattleStateActive())
|
||||
{
|
||||
Log.Warning("SetUseSimulationMovement is ignored during Battle. Change this switch outside Battle.");
|
||||
return;
|
||||
}
|
||||
|
||||
_useSimulationMovement = enabled;
|
||||
}
|
||||
|
||||
public void SetUseJobSimulation(bool enabled)
|
||||
{
|
||||
if (IsBattleStateActive())
|
||||
{
|
||||
Log.Warning("SetUseJobSimulation is ignored during Battle. Change this switch outside Battle.");
|
||||
return;
|
||||
}
|
||||
|
||||
_useJobSimulation = enabled;
|
||||
}
|
||||
|
||||
|
|
@ -82,6 +95,18 @@ namespace Simulation
|
|||
_useBurstJobs = enabled;
|
||||
}
|
||||
|
||||
private static bool IsBattleStateActive()
|
||||
{
|
||||
var procedureComponent = GameEntry.Procedure;
|
||||
if (procedureComponent == null ||
|
||||
procedureComponent.CurrentProcedure is not ProcedureGame procedureGame)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return procedureGame.CurrentGameStateType == GameStateType.Battle;
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
|
|
|||
|
|
@ -159,6 +159,11 @@ namespace CustomUtility
|
|||
}
|
||||
|
||||
public static void PerformCollision(TargetableObject entity, EntityBase other)
|
||||
{
|
||||
PerformCollision(entity, other, false);
|
||||
}
|
||||
|
||||
public static void PerformCollision(TargetableObject entity, EntityBase other, bool ignoreRuntimeState)
|
||||
{
|
||||
if (entity == null || other == null)
|
||||
{
|
||||
|
|
@ -204,7 +209,7 @@ namespace CustomUtility
|
|||
EnemyProjectile enemyProjectile = other as EnemyProjectile;
|
||||
if (enemyProjectile != null)
|
||||
{
|
||||
if (!enemyProjectile.IsActive) return;
|
||||
if (!ignoreRuntimeState && !enemyProjectile.IsActive) return;
|
||||
|
||||
ImpactData entityImpactData = entity.GetImpactData();
|
||||
ImpactData projectileImpactData = enemyProjectile.GetImpactData();
|
||||
|
|
@ -224,7 +229,7 @@ namespace CustomUtility
|
|||
WeaponBase weapon = other as WeaponBase;
|
||||
if (weapon != null)
|
||||
{
|
||||
if (!weapon.IsAttacking) return;
|
||||
if (!ignoreRuntimeState && !weapon.IsAttacking) return;
|
||||
ImpactData entityImpactData = entity.GetImpactData();
|
||||
ImpactData weaponImpactData = weapon.GetImpactData();
|
||||
if (GetRelation(entityImpactData.Camp, weaponImpactData.Camp) == RelationType.Friendly)
|
||||
|
|
|
|||
Loading…
Reference in New Issue