优化 WeaponLance 的攻击逻辑

This commit is contained in:
2026-03-20 09:55:52 +08:00
parent 8d21d53c4d
commit 0d7df18324
16 changed files with 321 additions and 89 deletions
@@ -65,13 +65,15 @@ namespace Simulation
MaxTargets = math.max(1, maxTargets),
ShapeType = CollisionShapeCircle,
Direction = new float3(0f, 0f, 1f),
HalfAngleDeg = 180f
HalfAngleDeg = 180f,
HalfWidth = 0f,
HalfLength = 0f
});
}
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)
in Vector3 direction, float halfAngleDeg, float halfWidth, float halfLength)
{
if (!_collisionQueryInputs.IsCreated || radius <= 0f)
{
@@ -101,7 +103,9 @@ namespace Simulation
MaxTargets = math.max(1, maxTargets),
ShapeType = shapeType,
Direction = new float3(normalizedDirection.x, normalizedDirection.y, normalizedDirection.z),
HalfAngleDeg = Mathf.Clamp(halfAngleDeg, 0f, 180f)
HalfAngleDeg = Mathf.Clamp(halfAngleDeg, 0f, 180f),
HalfWidth = Mathf.Max(0f, halfWidth),
HalfLength = Mathf.Max(0f, halfLength)
});
}
@@ -10,6 +10,7 @@ namespace Simulation
private const int CollisionSourceTypeArea = 2;
private const int CollisionShapeCircle = 0;
private const int CollisionShapeSector = 1;
private const int CollisionShapeRectangle = 2;
// Kept as top-level fields because current regression tests reflect them directly.
private NativeList<CollisionQueryData> _collisionQueryInputs;
@@ -15,6 +15,8 @@ namespace Simulation
public int ShapeType;
public Vector3 Direction;
public float HalfAngleDeg;
public float HalfWidth;
public float HalfLength;
}
}
}
}
@@ -17,6 +17,8 @@ namespace Simulation
public int ShapeType;
public float3 Direction;
public float HalfAngleDeg;
public float HalfWidth;
public float HalfLength;
}
}
}
}
@@ -23,7 +23,6 @@ namespace Simulation
public void Execute(int index)
{
CollisionQueryData query = Queries[index];
float radiusSqr = query.Radius * query.Radius;
int centerCellX = (int)math.floor(query.Position.x / CellSize);
int centerCellZ = (int)math.floor(query.Position.z / CellSize);
int queryRange = math.max(1, (int)math.ceil(query.Radius / CellSize));
@@ -34,10 +33,14 @@ namespace Simulation
query.SourceOwnerEntityId != PlayerTargetEntityId)
{
float3 playerPosition = PlayerPosition;
playerPosition.y = query.Position.y;
if (query.SourceType == CollisionSourceTypeArea)
{
playerPosition.y = query.Position.y;
}
float3 playerDelta = playerPosition - query.Position;
float playerSqrDistance = math.lengthsq(playerDelta);
if (playerSqrDistance <= radiusSqr)
float playerRadiusSqr = query.Radius * query.Radius;
if (playerSqrDistance <= playerRadiusSqr)
{
Candidates.AddNoResize(new CollisionCandidateData
{
@@ -86,12 +89,19 @@ namespace Simulation
continue;
}
float deltaY = query.SourceType == CollisionSourceTypeArea
? 0f
: enemy.Position.y - query.Position.y;
float3 delta = new float3(
enemy.Position.x - query.Position.x,
enemy.Position.y - query.Position.y,
deltaY,
enemy.Position.z - query.Position.z);
float sqrDistance = math.lengthsq(delta);
if (sqrDistance > radiusSqr)
float targetRadius = query.SourceType == CollisionSourceTypeArea
? math.max(0f, enemy.EnemyBodyRadius)
: 0f;
float effectiveRadius = query.Radius + targetRadius;
if (sqrDistance > effectiveRadius * effectiveRadius)
{
continue;
}
@@ -119,4 +129,4 @@ namespace Simulation
}
}
}
}
}
@@ -58,7 +58,8 @@ namespace Simulation
AreaCollisionRequestData request = _areaCollisionRequests[i];
AddAreaCollisionQuery(queryId, request.SourceEntityId, request.SourceOwnerEntityId,
request.SourceWasActiveAtQueryTime, in request.Center, request.Radius, request.MaxTargets,
request.ShapeType, in request.Direction, request.HalfAngleDeg);
request.ShapeType, in request.Direction, request.HalfAngleDeg, request.HalfWidth,
request.HalfLength);
queryId++;
builtAreaQueryCount++;
if (request.Radius > maxQueryRadius)
@@ -12,18 +12,29 @@ namespace Simulation
float radius, int maxTargets = 16)
{
return TryRequestAreaCollisionInternal(sourceEntityId, sourceOwnerEntityId, in center, radius,
maxTargets, CollisionShapeCircle, Vector3.forward, 180f);
maxTargets, CollisionShapeCircle, Vector3.forward, 180f, 0f, 0f);
}
public bool TryRequestSectorCollision(int sourceEntityId, int sourceOwnerEntityId, in Vector3 center,
float radius, in Vector3 direction, float halfAngleDeg, int maxTargets = 16)
{
return TryRequestAreaCollisionInternal(sourceEntityId, sourceOwnerEntityId, in center, radius,
maxTargets, CollisionShapeSector, direction, halfAngleDeg);
maxTargets, CollisionShapeSector, direction, halfAngleDeg, 0f, 0f);
}
public bool TryRequestRectangleCollision(int sourceEntityId, int sourceOwnerEntityId, in Vector3 center,
float halfWidth, float halfLength, in Vector3 direction, int maxTargets = 16)
{
float safeHalfWidth = Mathf.Max(0.01f, halfWidth);
float safeHalfLength = Mathf.Max(0.01f, halfLength);
float boundingRadius = Mathf.Sqrt(safeHalfWidth * safeHalfWidth + safeHalfLength * safeHalfLength);
return TryRequestAreaCollisionInternal(sourceEntityId, sourceOwnerEntityId, in center, boundingRadius,
maxTargets, CollisionShapeRectangle, direction, 0f, safeHalfWidth, safeHalfLength);
}
private bool TryRequestAreaCollisionInternal(int sourceEntityId, int sourceOwnerEntityId,
in Vector3 center, float radius, int maxTargets, int shapeType, in Vector3 direction, float halfAngleDeg)
in Vector3 center, float radius, int maxTargets, int shapeType, in Vector3 direction, float halfAngleDeg,
float halfWidth, float halfLength)
{
if (!_useSimulationMovement)
{
@@ -58,7 +69,9 @@ namespace Simulation
MaxTargets = Mathf.Max(1, maxTargets),
ShapeType = shapeType,
Direction = normalizedDirection,
HalfAngleDeg = Mathf.Clamp(halfAngleDeg, 0f, 180f)
HalfAngleDeg = Mathf.Clamp(halfAngleDeg, 0f, 180f),
HalfWidth = Mathf.Max(0f, halfWidth),
HalfLength = Mathf.Max(0f, halfLength)
});
return true;
@@ -1,3 +1,4 @@
using Components;
using CustomDebugger;
using CustomUtility;
using Definition.DataStruct;
@@ -188,7 +189,8 @@ namespace Simulation
continue;
}
if (!IsAreaTargetInsidePreciseShape(in query, target))
float targetRadius = ResolveAreaTargetRadius(target);
if (!IsAreaTargetInsidePreciseShape(in query, target, targetRadius))
{
continue;
}
@@ -230,7 +232,24 @@ namespace Simulation
return false;
}
private static bool IsAreaTargetInsidePreciseShape(in CollisionQueryData query, TargetableObject target)
private float ResolveAreaTargetRadius(TargetableObject target)
{
if (target == null)
{
return 0f;
}
if (target is EnemyBase && TryGetEnemyData(target.Id, out EnemySimData enemyData))
{
return Mathf.Max(0f, enemyData.EnemyBodyRadius);
}
MovementComponent movementComponent = target.GetComponent<MovementComponent>();
return movementComponent != null ? Mathf.Max(0f, movementComponent.EnemyBodyRadius) : 0f;
}
private static bool IsAreaTargetInsidePreciseShape(in CollisionQueryData query, TargetableObject target,
float targetRadius)
{
if (target == null || target.CachedTransform == null)
{
@@ -241,7 +260,7 @@ namespace Simulation
Vector3 toTarget = target.CachedTransform.position - center;
toTarget.y = 0f;
float radius = Mathf.Max(0.01f, query.Radius);
float radius = Mathf.Max(0.01f, query.Radius + Mathf.Max(0f, targetRadius));
float radiusSqr = radius * radius;
float sqrDistance = toTarget.sqrMagnitude;
if (sqrDistance > radiusSqr)
@@ -249,6 +268,27 @@ namespace Simulation
return false;
}
if (query.ShapeType == CollisionShapeRectangle)
{
Vector3 forwardRect = new Vector3(query.Direction.x, query.Direction.y, query.Direction.z);
forwardRect.y = 0f;
if (forwardRect.sqrMagnitude <= Mathf.Epsilon)
{
forwardRect = Vector3.forward;
}
else
{
forwardRect.Normalize();
}
Vector3 rightRect = Vector3.Cross(Vector3.up, forwardRect);
float halfWidth = Mathf.Max(0.01f, query.HalfWidth + Mathf.Max(0f, targetRadius));
float halfLength = Mathf.Max(0.01f, query.HalfLength + Mathf.Max(0f, targetRadius));
float forwardDistance = Vector3.Dot(toTarget, forwardRect);
float lateralDistance = Vector3.Dot(toTarget, rightRect);
return Mathf.Abs(forwardDistance) <= halfLength && Mathf.Abs(lateralDistance) <= halfWidth;
}
if (query.ShapeType != CollisionShapeSector)
{
return true;