This commit is contained in:
2026-08-14 18:07:12 +03:00
parent 78a94a17d0
commit 7a0ee6b519
2 changed files with 79 additions and 23 deletions
@@ -15,12 +15,15 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
[SerializeField, Min(0.05f)] private float collisionRefreshInterval = 0.25f;
[Header("Holding Follow")]
[SerializeField, Min(0.01f)] private float positionSmoothTime = 0.12f;
[SerializeField, Min(0.1f)] private float maximumFollowSpeed = 12f;
[SerializeField, Min(0.1f)] private float maximumFollowDistance = 1.25f;
[SerializeField, Min(0.5f)] private float maximumHoldDistance = 4.5f;
[SerializeField, Min(0.1f)] private float rotationFollowSpeed = 14f;
[Header("Local Presentation")]
[Tooltip("Removes the server round-trip delay for the player currently carrying the item.")]
[SerializeField] private bool correctLocalHolderPresentation = true;
[SerializeField, Min(0.1f)] private float maximumLocalCorrectionDistance = 2f;
[Header("Throw")]
[SerializeField, Min(0f)] private float throwForce = 6f;
[SerializeField, Min(0f)] private float throwUpwardForce = 0.5f;
@@ -38,6 +41,7 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
private readonly HashSet<Collider> ignoredPlayerColliders = new();
private readonly HashSet<Collider> desiredIgnoredColliders = new();
private readonly List<Collider> collidersToRestore = new();
private readonly RaycastHit[] localCorrectionHits = new RaycastHit[24];
private float nextCollisionRefreshTime;
private bool initialUseGravity;
private CollisionDetectionMode initialCollisionDetectionMode;
@@ -125,6 +129,28 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
}
private void LateUpdate()
{
if (!correctLocalHolderPresentation || IsServer || !IsSpawned ||
!IsHeldByLocalPlayer || IsExternallyControlled || physicsBody == null ||
!TryGetPlayerObject(holderClientId.Value, out NetworkObject holder))
{
return;
}
Transform anchor = ResolveHoldingAnchor(holder);
Vector3 targetPosition = anchor.TransformPoint(HoldingOffset);
Vector3 targetDelta = targetPosition - physicsBody.position;
if (targetDelta.sqrMagnitude >
maximumLocalCorrectionDistance * maximumLocalCorrectionDistance ||
HasBlockingColliderForLocalCorrection(targetDelta))
{
return;
}
transform.SetPositionAndRotation(targetPosition, anchor.rotation);
}
public void RequestThrow()
{
if (IsSpawned && IsHeldByLocalPlayer)
@@ -266,17 +292,10 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
return false;
}
float distance = targetDelta.magnitude;
float speedDistance = Mathf.Max(maximumFollowDistance, 0.01f);
float desiredSpeed = maximumFollowSpeed * Mathf.Clamp01(distance / speedDistance);
Vector3 desiredVelocity = distance > 0.0001f
? targetDelta / distance * desiredSpeed
: Vector3.zero;
float maximumAcceleration = maximumFollowSpeed / Mathf.Max(positionSmoothTime, 0.01f);
Vector3 velocityChange = Vector3.ClampMagnitude(
desiredVelocity - physicsBody.linearVelocity,
maximumAcceleration * Time.fixedDeltaTime);
physicsBody.AddForce(velocityChange, ForceMode.VelocityChange);
Vector3 targetVelocity = targetDelta / Mathf.Max(Time.fixedDeltaTime, 0.001f);
physicsBody.linearVelocity = Vector3.ClampMagnitude(
targetVelocity,
maximumFollowSpeed);
DriveRotation(anchor.rotation);
return true;
@@ -292,15 +311,52 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
if (angle > 180f)
angle -= 360f;
Vector3 desiredAngularVelocity = axis.normalized *
(angle * Mathf.Deg2Rad * rotationFollowSpeed);
desiredAngularVelocity = Vector3.ClampMagnitude(
desiredAngularVelocity,
Vector3 targetAngularVelocity = axis.normalized *
(angle * Mathf.Deg2Rad / Mathf.Max(Time.fixedDeltaTime, 0.001f));
physicsBody.angularVelocity = Vector3.ClampMagnitude(
targetAngularVelocity,
rotationFollowSpeed);
Vector3 angularVelocityChange = Vector3.ClampMagnitude(
desiredAngularVelocity - physicsBody.angularVelocity,
rotationFollowSpeed * 4f * Time.fixedDeltaTime);
physicsBody.AddTorque(angularVelocityChange, ForceMode.VelocityChange);
}
private bool HasBlockingColliderForLocalCorrection(Vector3 targetDelta)
{
float distance = targetDelta.magnitude;
if (distance <= 0.0001f)
return false;
int hitCount = Physics.RaycastNonAlloc(
physicsBody.position,
targetDelta / distance,
localCorrectionHits,
distance,
~0,
QueryTriggerInteraction.Ignore);
for (int hitIndex = 0; hitIndex < hitCount; hitIndex++)
{
Collider hitCollider = localCorrectionHits[hitIndex].collider;
if (hitCollider == null ||
ignoredPlayerColliders.Contains(hitCollider) ||
IsObjectCollider(hitCollider))
{
continue;
}
return true;
}
return false;
}
private bool IsObjectCollider(Collider candidate)
{
foreach (Collider objectCollider in objectColliders)
{
if (objectCollider == candidate)
return true;
}
return false;
}
private void HandleHolderChanged(ulong _, ulong __) => ApplyHoldingState();
+2 -2
View File
@@ -341314,7 +341314,7 @@ PrefabInstance:
objectReference: {fileID: 2055952141}
- target: {fileID: 1187608763751665767, guid: 8cc9c4d7d9e04d640bbd0616e7926670, type: 3}
propertyPath: m_VersionIndex
value: 1189
value: 1192
objectReference: {fileID: 0}
- target: {fileID: 2057801181638564846, guid: 8cc9c4d7d9e04d640bbd0616e7926670, type: 3}
propertyPath: m_Mesh
@@ -363686,7 +363686,7 @@ PrefabInstance:
objectReference: {fileID: 1230761045}
- target: {fileID: 5333406013407316476, guid: 6eee6df5dab550446b41008fa6fff89a, type: 3}
propertyPath: m_VersionIndex
value: 3432
value: 3435
objectReference: {fileID: 0}
- target: {fileID: 5521966715159789732, guid: 6eee6df5dab550446b41008fa6fff89a, type: 3}
propertyPath: m_LocalPosition.x