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 Player Player;
|
||||||
|
|
||||||
public GameStateBase CurrentGameState => _gameStates[_currentGameState];
|
public GameStateBase CurrentGameState => _gameStates[_currentGameState];
|
||||||
|
public GameStateType CurrentGameStateType => _currentGameState;
|
||||||
|
|
||||||
private void InitGameState()
|
private void InitGameState()
|
||||||
{
|
{
|
||||||
|
|
@ -169,4 +170,4 @@ namespace Procedure
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ namespace Simulation
|
||||||
public int SourceType;
|
public int SourceType;
|
||||||
public int SourceEntityId;
|
public int SourceEntityId;
|
||||||
public int SourceOwnerEntityId;
|
public int SourceOwnerEntityId;
|
||||||
|
public bool SourceWasActiveAtQueryTime;
|
||||||
public float3 Position;
|
public float3 Position;
|
||||||
public float Radius;
|
public float Radius;
|
||||||
public int MaxTargets;
|
public int MaxTargets;
|
||||||
|
|
@ -98,6 +99,7 @@ namespace Simulation
|
||||||
{
|
{
|
||||||
public int SourceEntityId;
|
public int SourceEntityId;
|
||||||
public int SourceOwnerEntityId;
|
public int SourceOwnerEntityId;
|
||||||
|
public bool SourceWasActiveAtQueryTime;
|
||||||
public Vector3 Center;
|
public Vector3 Center;
|
||||||
public float Radius;
|
public float Radius;
|
||||||
public int MaxTargets;
|
public int MaxTargets;
|
||||||
|
|
@ -474,6 +476,7 @@ namespace Simulation
|
||||||
SourceType = CollisionSourceTypeProjectile,
|
SourceType = CollisionSourceTypeProjectile,
|
||||||
SourceEntityId = projectile.EntityId,
|
SourceEntityId = projectile.EntityId,
|
||||||
SourceOwnerEntityId = projectile.OwnerEntityId,
|
SourceOwnerEntityId = projectile.OwnerEntityId,
|
||||||
|
SourceWasActiveAtQueryTime = true,
|
||||||
Position = projectile.Position,
|
Position = projectile.Position,
|
||||||
Radius = radius,
|
Radius = radius,
|
||||||
MaxTargets = math.max(1, maxTargets),
|
MaxTargets = math.max(1, maxTargets),
|
||||||
|
|
@ -483,8 +486,9 @@ namespace Simulation
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddAreaCollisionQuery(int queryId, int sourceEntityId, int sourceOwnerEntityId, in Vector3 center,
|
private void AddAreaCollisionQuery(int queryId, int sourceEntityId, int sourceOwnerEntityId,
|
||||||
float radius, int maxTargets, int shapeType, in Vector3 direction, float halfAngleDeg)
|
bool sourceWasActiveAtQueryTime, in Vector3 center, float radius, int maxTargets, int shapeType,
|
||||||
|
in Vector3 direction, float halfAngleDeg)
|
||||||
{
|
{
|
||||||
if (!_collisionQueryInputs.IsCreated || radius <= 0f)
|
if (!_collisionQueryInputs.IsCreated || radius <= 0f)
|
||||||
{
|
{
|
||||||
|
|
@ -508,6 +512,7 @@ namespace Simulation
|
||||||
SourceType = CollisionSourceTypeArea,
|
SourceType = CollisionSourceTypeArea,
|
||||||
SourceEntityId = sourceEntityId,
|
SourceEntityId = sourceEntityId,
|
||||||
SourceOwnerEntityId = sourceOwnerEntityId,
|
SourceOwnerEntityId = sourceOwnerEntityId,
|
||||||
|
SourceWasActiveAtQueryTime = sourceWasActiveAtQueryTime,
|
||||||
Position = new float3(center.x, center.y, center.z),
|
Position = new float3(center.x, center.y, center.z),
|
||||||
Radius = radius,
|
Radius = radius,
|
||||||
MaxTargets = math.max(1, maxTargets),
|
MaxTargets = math.max(1, maxTargets),
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ namespace Simulation
|
||||||
}
|
}
|
||||||
|
|
||||||
int resolvedOwnerEntityId = sourceOwnerEntityId != 0 ? sourceOwnerEntityId : sourceEntityId;
|
int resolvedOwnerEntityId = sourceOwnerEntityId != 0 ? sourceOwnerEntityId : sourceEntityId;
|
||||||
|
bool sourceWasActiveAtQueryTime = IsCollisionSourceActiveAtQueryTime(sourceEntityId);
|
||||||
Vector3 normalizedDirection = direction;
|
Vector3 normalizedDirection = direction;
|
||||||
normalizedDirection.y = 0f;
|
normalizedDirection.y = 0f;
|
||||||
if (normalizedDirection.sqrMagnitude <= Mathf.Epsilon)
|
if (normalizedDirection.sqrMagnitude <= Mathf.Epsilon)
|
||||||
|
|
@ -121,6 +122,7 @@ namespace Simulation
|
||||||
{
|
{
|
||||||
SourceEntityId = sourceEntityId,
|
SourceEntityId = sourceEntityId,
|
||||||
SourceOwnerEntityId = resolvedOwnerEntityId,
|
SourceOwnerEntityId = resolvedOwnerEntityId,
|
||||||
|
SourceWasActiveAtQueryTime = sourceWasActiveAtQueryTime,
|
||||||
Center = center,
|
Center = center,
|
||||||
Radius = Mathf.Max(0.01f, radius),
|
Radius = Mathf.Max(0.01f, radius),
|
||||||
MaxTargets = Mathf.Max(1, maxTargets),
|
MaxTargets = Mathf.Max(1, maxTargets),
|
||||||
|
|
@ -238,8 +240,9 @@ namespace Simulation
|
||||||
for (int i = 0; i < areaQueryCount; i++)
|
for (int i = 0; i < areaQueryCount; i++)
|
||||||
{
|
{
|
||||||
AreaCollisionRequestData request = _areaCollisionRequests[i];
|
AreaCollisionRequestData request = _areaCollisionRequests[i];
|
||||||
AddAreaCollisionQuery(queryId, request.SourceEntityId, request.SourceOwnerEntityId, in request.Center,
|
AddAreaCollisionQuery(queryId, request.SourceEntityId, request.SourceOwnerEntityId,
|
||||||
request.Radius, request.MaxTargets, request.ShapeType, in request.Direction, request.HalfAngleDeg);
|
request.SourceWasActiveAtQueryTime, in request.Center, request.Radius, request.MaxTargets,
|
||||||
|
request.ShapeType, in request.Direction, request.HalfAngleDeg);
|
||||||
queryId++;
|
queryId++;
|
||||||
builtAreaQueryCount++;
|
builtAreaQueryCount++;
|
||||||
if (request.Radius > maxQueryRadius)
|
if (request.Radius > maxQueryRadius)
|
||||||
|
|
@ -628,6 +631,11 @@ namespace Simulation
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!query.SourceWasActiveAtQueryTime)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
EntityBase sourceEntity = TryGetEntityById(hitEvent.SourceEntityId);
|
EntityBase sourceEntity = TryGetEntityById(hitEvent.SourceEntityId);
|
||||||
if (sourceEntity == null || !sourceEntity.Available)
|
if (sourceEntity == null || !sourceEntity.Available)
|
||||||
{
|
{
|
||||||
|
|
@ -644,7 +652,7 @@ namespace Simulation
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
AIUtility.PerformCollision(target, sourceEntity);
|
AIUtility.PerformCollision(target, sourceEntity, true);
|
||||||
resolvedHitCount++;
|
resolvedHitCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -787,10 +795,16 @@ namespace Simulation
|
||||||
{
|
{
|
||||||
areaCandidateCount++;
|
areaCandidateCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectedCount++;
|
||||||
|
if (selectedCount >= query.MaxTargets)
|
||||||
|
{
|
||||||
|
reachedLimit = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasEnemyTargets)
|
if (!hasEnemyTargets || reachedLimit)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -893,6 +907,27 @@ namespace Simulation
|
||||||
return projectile.LifeTime > 0f && projectile.Age >= projectile.LifeTime;
|
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,
|
private static void ExecuteProjectileMovement(int index, NativeArray<ProjectileJobInputData> inputs,
|
||||||
NativeArray<ProjectileJobOutputData> outputs, float deltaTime, float3 playerPosition,
|
NativeArray<ProjectileJobOutputData> outputs, float deltaTime, float3 playerPosition,
|
||||||
float maxSqrDistanceFromPlayer, float maxVerticalOffsetFromPlayer)
|
float maxSqrDistanceFromPlayer, float maxVerticalOffsetFromPlayer)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using CustomDebugger;
|
||||||
using CustomUtility;
|
using CustomUtility;
|
||||||
using Entity;
|
using Entity;
|
||||||
using Entity.EntityData;
|
using Entity.EntityData;
|
||||||
|
using Procedure;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityGameFramework.Runtime;
|
using UnityGameFramework.Runtime;
|
||||||
|
|
||||||
|
|
@ -69,11 +70,23 @@ namespace Simulation
|
||||||
|
|
||||||
public void SetUseSimulationMovement(bool enabled)
|
public void SetUseSimulationMovement(bool enabled)
|
||||||
{
|
{
|
||||||
|
if (IsBattleStateActive())
|
||||||
|
{
|
||||||
|
Log.Warning("SetUseSimulationMovement is ignored during Battle. Change this switch outside Battle.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_useSimulationMovement = enabled;
|
_useSimulationMovement = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetUseJobSimulation(bool enabled)
|
public void SetUseJobSimulation(bool enabled)
|
||||||
{
|
{
|
||||||
|
if (IsBattleStateActive())
|
||||||
|
{
|
||||||
|
Log.Warning("SetUseJobSimulation is ignored during Battle. Change this switch outside Battle.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_useJobSimulation = enabled;
|
_useJobSimulation = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,6 +95,18 @@ namespace Simulation
|
||||||
_useBurstJobs = enabled;
|
_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()
|
protected override void Awake()
|
||||||
{
|
{
|
||||||
base.Awake();
|
base.Awake();
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,11 @@ namespace CustomUtility
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void PerformCollision(TargetableObject entity, EntityBase other)
|
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)
|
if (entity == null || other == null)
|
||||||
{
|
{
|
||||||
|
|
@ -204,7 +209,7 @@ namespace CustomUtility
|
||||||
EnemyProjectile enemyProjectile = other as EnemyProjectile;
|
EnemyProjectile enemyProjectile = other as EnemyProjectile;
|
||||||
if (enemyProjectile != null)
|
if (enemyProjectile != null)
|
||||||
{
|
{
|
||||||
if (!enemyProjectile.IsActive) return;
|
if (!ignoreRuntimeState && !enemyProjectile.IsActive) return;
|
||||||
|
|
||||||
ImpactData entityImpactData = entity.GetImpactData();
|
ImpactData entityImpactData = entity.GetImpactData();
|
||||||
ImpactData projectileImpactData = enemyProjectile.GetImpactData();
|
ImpactData projectileImpactData = enemyProjectile.GetImpactData();
|
||||||
|
|
@ -224,7 +229,7 @@ namespace CustomUtility
|
||||||
WeaponBase weapon = other as WeaponBase;
|
WeaponBase weapon = other as WeaponBase;
|
||||||
if (weapon != null)
|
if (weapon != null)
|
||||||
{
|
{
|
||||||
if (!weapon.IsAttacking) return;
|
if (!ignoreRuntimeState && !weapon.IsAttacking) return;
|
||||||
ImpactData entityImpactData = entity.GetImpactData();
|
ImpactData entityImpactData = entity.GetImpactData();
|
||||||
ImpactData weaponImpactData = weapon.GetImpactData();
|
ImpactData weaponImpactData = weapon.GetImpactData();
|
||||||
if (GetRelation(entityImpactData.Camp, weaponImpactData.Camp) == RelationType.Friendly)
|
if (GetRelation(entityImpactData.Camp, weaponImpactData.Camp) == RelationType.Friendly)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue