Added new Rocket-Processing
This commit is contained in:
@@ -66,11 +66,16 @@ public sealed class NetworkDraggableInteractable : NetworkInteractable, IWorksta
|
||||
NetworkVariableWritePermission.Server);
|
||||
|
||||
private readonly HashSet<Collider> ignoredPlayerColliders = new();
|
||||
private readonly HashSet<Collider> desiredIgnoredColliders = new();
|
||||
private readonly List<Collider> collidersToRestore = new();
|
||||
private readonly RaycastHit[] groundHits = new RaycastHit[16];
|
||||
private float nextCollisionRefreshTime;
|
||||
private Vector3 localGroundContactPoint;
|
||||
private Vector3 smoothedGroundNormal = Vector3.up;
|
||||
private Vector3 dragVelocity;
|
||||
private float dragWorldHeight;
|
||||
private bool hasDragReferenceHeight;
|
||||
private bool initialUseGravity;
|
||||
private CollisionDetectionMode initialCollisionDetectionMode;
|
||||
|
||||
public float Weight => weight;
|
||||
public int ActiveDraggerCount
|
||||
@@ -125,6 +130,12 @@ public sealed class NetworkDraggableInteractable : NetworkInteractable, IWorksta
|
||||
{
|
||||
ResolvePhysicsReferences();
|
||||
ApplyWeight();
|
||||
|
||||
if (physicsBody != null)
|
||||
{
|
||||
initialUseGravity = physicsBody.useGravity;
|
||||
initialCollisionDetectionMode = physicsBody.collisionDetectionMode;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
@@ -157,7 +168,7 @@ public sealed class NetworkDraggableInteractable : NetworkInteractable, IWorksta
|
||||
return;
|
||||
|
||||
nextCollisionRefreshTime = Time.time + collisionRefreshInterval;
|
||||
IgnoreCollisionsWithPlayers();
|
||||
RefreshDraggerCollisions();
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
@@ -168,10 +179,7 @@ public sealed class NetworkDraggableInteractable : NetworkInteractable, IWorksta
|
||||
RemoveInvalidDraggers();
|
||||
if (!HasEnoughPullStrength ||
|
||||
!TryGetCombinedDragTarget(out Vector3 target, out Vector3 forward))
|
||||
{
|
||||
dragVelocity = Vector3.zero;
|
||||
return;
|
||||
}
|
||||
|
||||
float totalStrength = ActiveDraggerCount * pullStrengthPerPlayer;
|
||||
float loadRatio = Mathf.Clamp01(weight / totalStrength);
|
||||
@@ -181,7 +189,7 @@ public sealed class NetworkDraggableInteractable : NetworkInteractable, IWorksta
|
||||
switch (movementMode)
|
||||
{
|
||||
case DraggableMovementMode.KeepWorldHeight:
|
||||
target.y = physicsBody.position.y;
|
||||
target.y = dragWorldHeight;
|
||||
FollowDragTarget(target, forward, movementSpeed, Vector3.up);
|
||||
break;
|
||||
|
||||
@@ -360,6 +368,21 @@ public sealed class NetworkDraggableInteractable : NetworkInteractable, IWorksta
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryReleaseExternalControlToPlayer(ulong clientId)
|
||||
{
|
||||
if (!IsServer || !IsSpawned || !IsExternallyControlled ||
|
||||
TryGetDraggedObject(clientId, this, out _) ||
|
||||
!TryGetPlayerObject(clientId, out _))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
isExternallyControlled.Value = false;
|
||||
AddDragger(clientId);
|
||||
ApplyDraggingState();
|
||||
return IsDragger(clientId);
|
||||
}
|
||||
|
||||
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
|
||||
private void RequestReleaseRpc(RpcParams rpcParams = default)
|
||||
{
|
||||
@@ -379,34 +402,52 @@ public sealed class NetworkDraggableInteractable : NetworkInteractable, IWorksta
|
||||
{
|
||||
if (physicsBody != null)
|
||||
{
|
||||
bool shouldBeKinematic = HasAnyDragger || IsExternallyControlled || !IsServer;
|
||||
bool shouldBeKinematic = IsExternallyControlled || !IsServer;
|
||||
|
||||
if (physicsBody.isKinematic && !shouldBeKinematic)
|
||||
if (shouldBeKinematic)
|
||||
{
|
||||
physicsBody.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
|
||||
physicsBody.isKinematic = true;
|
||||
physicsBody.useGravity = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
physicsBody.isKinematic = false;
|
||||
physicsBody.useGravity = initialUseGravity;
|
||||
physicsBody.collisionDetectionMode = ResolveDynamicCollisionDetectionMode();
|
||||
}
|
||||
|
||||
if (!physicsBody.isKinematic)
|
||||
if (IsExternallyControlled)
|
||||
{
|
||||
physicsBody.linearVelocity = Vector3.zero;
|
||||
physicsBody.angularVelocity = Vector3.zero;
|
||||
}
|
||||
|
||||
physicsBody.isKinematic = shouldBeKinematic;
|
||||
}
|
||||
|
||||
if (HasAnyDragger || IsExternallyControlled)
|
||||
if (HasAnyDragger)
|
||||
{
|
||||
dragVelocity = Vector3.zero;
|
||||
if (!hasDragReferenceHeight && physicsBody != null)
|
||||
{
|
||||
dragWorldHeight = physicsBody.position.y;
|
||||
hasDragReferenceHeight = true;
|
||||
}
|
||||
|
||||
CacheGroundContactPoint();
|
||||
smoothedGroundNormal = physicsBody != null ? physicsBody.transform.up : Vector3.up;
|
||||
IgnoreCollisionsWithPlayers();
|
||||
RefreshDraggerCollisions();
|
||||
}
|
||||
else
|
||||
{
|
||||
dragVelocity = Vector3.zero;
|
||||
hasDragReferenceHeight = false;
|
||||
RestorePlayerCollisions();
|
||||
}
|
||||
}
|
||||
|
||||
private CollisionDetectionMode ResolveDynamicCollisionDetectionMode() =>
|
||||
initialCollisionDetectionMode == CollisionDetectionMode.Discrete
|
||||
? CollisionDetectionMode.ContinuousDynamic
|
||||
: initialCollisionDetectionMode;
|
||||
|
||||
private void ResolvePhysicsReferences()
|
||||
{
|
||||
if (physicsBody == null)
|
||||
@@ -430,16 +471,11 @@ public sealed class NetworkDraggableInteractable : NetworkInteractable, IWorksta
|
||||
float movementSpeed,
|
||||
Vector3 surfaceNormal)
|
||||
{
|
||||
Vector3 nextPosition = Vector3.SmoothDamp(
|
||||
physicsBody.position,
|
||||
DrivePhysicsBody(
|
||||
target,
|
||||
ref dragVelocity,
|
||||
positionSmoothTime,
|
||||
CalculateDragRotation(forward, surfaceNormal),
|
||||
movementSpeed,
|
||||
Time.fixedDeltaTime);
|
||||
|
||||
physicsBody.MovePosition(nextPosition);
|
||||
physicsBody.MoveRotation(CalculateDragRotation(forward, surfaceNormal));
|
||||
movementSpeed);
|
||||
}
|
||||
|
||||
private void MoveAlongGround(
|
||||
@@ -449,18 +485,10 @@ public sealed class NetworkDraggableInteractable : NetworkInteractable, IWorksta
|
||||
{
|
||||
Vector3 currentPosition = physicsBody.position;
|
||||
Vector3 planarTarget = new(dragTarget.x, currentPosition.y, dragTarget.z);
|
||||
Vector3 planarVelocity = new(dragVelocity.x, 0f, dragVelocity.z);
|
||||
Vector3 nextPlanarPosition = Vector3.SmoothDamp(
|
||||
currentPosition,
|
||||
planarTarget,
|
||||
ref planarVelocity,
|
||||
positionSmoothTime,
|
||||
movementSpeed,
|
||||
Time.fixedDeltaTime);
|
||||
nextPlanarPosition.y = currentPosition.y;
|
||||
dragVelocity = new Vector3(planarVelocity.x, dragVelocity.y, planarVelocity.z);
|
||||
|
||||
Vector3 probePosition = nextPlanarPosition;
|
||||
Vector3 planarStep = Vector3.ClampMagnitude(
|
||||
planarTarget - currentPosition,
|
||||
movementSpeed * Time.fixedDeltaTime);
|
||||
Vector3 probePosition = currentPosition + planarStep;
|
||||
|
||||
if (!TryGetGroundSurface(probePosition, out Vector3 groundPoint, out Vector3 groundNormal))
|
||||
return;
|
||||
@@ -469,14 +497,55 @@ public sealed class NetworkDraggableInteractable : NetworkInteractable, IWorksta
|
||||
Vector3 scaledContactPoint = Vector3.Scale(localGroundContactPoint, physicsBody.transform.lossyScale);
|
||||
float contactOffsetY = (targetRotation * scaledContactPoint).y;
|
||||
float targetHeight = groundPoint.y - contactOffsetY + groundClearance;
|
||||
float nextHeight = Mathf.MoveTowards(
|
||||
currentPosition.y,
|
||||
targetHeight,
|
||||
maximumGroundVerticalSpeed * Time.fixedDeltaTime);
|
||||
DrivePhysicsBody(
|
||||
new Vector3(dragTarget.x, targetHeight, dragTarget.z),
|
||||
targetRotation,
|
||||
movementSpeed,
|
||||
maximumGroundVerticalSpeed);
|
||||
}
|
||||
|
||||
physicsBody.MovePosition(new Vector3(nextPlanarPosition.x, nextHeight, nextPlanarPosition.z));
|
||||
private void DrivePhysicsBody(
|
||||
Vector3 targetPosition,
|
||||
Quaternion targetRotation,
|
||||
float maximumPlanarSpeed,
|
||||
float maximumVerticalSpeed)
|
||||
{
|
||||
Vector3 positionDelta = targetPosition - physicsBody.position;
|
||||
float responseTime = Mathf.Max(positionSmoothTime, 0.01f);
|
||||
Vector3 desiredVelocity = positionDelta / responseTime;
|
||||
Vector3 desiredPlanarVelocity = Vector3.ClampMagnitude(
|
||||
new Vector3(desiredVelocity.x, 0f, desiredVelocity.z),
|
||||
maximumPlanarSpeed);
|
||||
desiredVelocity = new Vector3(
|
||||
desiredPlanarVelocity.x,
|
||||
Mathf.Clamp(desiredVelocity.y, -maximumVerticalSpeed, maximumVerticalSpeed),
|
||||
desiredPlanarVelocity.z);
|
||||
|
||||
physicsBody.MoveRotation(targetRotation);
|
||||
float maximumAcceleration = Mathf.Max(
|
||||
maximumPlanarSpeed,
|
||||
maximumVerticalSpeed) / responseTime;
|
||||
Vector3 velocityChange = Vector3.ClampMagnitude(
|
||||
desiredVelocity - physicsBody.linearVelocity,
|
||||
maximumAcceleration * Time.fixedDeltaTime);
|
||||
physicsBody.AddForce(velocityChange, ForceMode.VelocityChange);
|
||||
|
||||
Quaternion rotationDelta = targetRotation * Quaternion.Inverse(physicsBody.rotation);
|
||||
rotationDelta.ToAngleAxis(out float angle, out Vector3 axis);
|
||||
if (axis.sqrMagnitude < 0.0001f || float.IsNaN(axis.x))
|
||||
return;
|
||||
|
||||
if (angle > 180f)
|
||||
angle -= 360f;
|
||||
|
||||
Vector3 desiredAngularVelocity = axis.normalized *
|
||||
(angle * Mathf.Deg2Rad * rotationFollowSpeed);
|
||||
desiredAngularVelocity = Vector3.ClampMagnitude(
|
||||
desiredAngularVelocity,
|
||||
rotationFollowSpeed);
|
||||
Vector3 angularVelocityChange = Vector3.ClampMagnitude(
|
||||
desiredAngularVelocity - physicsBody.angularVelocity,
|
||||
rotationFollowSpeed * 4f * Time.fixedDeltaTime);
|
||||
physicsBody.AddTorque(angularVelocityChange, ForceMode.VelocityChange);
|
||||
}
|
||||
|
||||
private bool TryGetGroundSurface(
|
||||
@@ -538,8 +607,7 @@ public sealed class NetworkDraggableInteractable : NetworkInteractable, IWorksta
|
||||
Quaternion desiredRotation = Quaternion.LookRotation(
|
||||
surfaceForward.normalized,
|
||||
smoothedGroundNormal) * Quaternion.Euler(rotationOffset);
|
||||
float rotationBlend = 1f - Mathf.Exp(-rotationFollowSpeed * Time.fixedDeltaTime);
|
||||
return Quaternion.Slerp(physicsBody.rotation, desiredRotation, rotationBlend);
|
||||
return desiredRotation;
|
||||
}
|
||||
|
||||
private void CacheGroundContactPoint()
|
||||
@@ -596,19 +664,50 @@ public sealed class NetworkDraggableInteractable : NetworkInteractable, IWorksta
|
||||
return false;
|
||||
}
|
||||
|
||||
private void IgnoreCollisionsWithPlayers()
|
||||
private void RefreshDraggerCollisions()
|
||||
{
|
||||
foreach (CharacterController playerCollider in FindObjectsByType<CharacterController>(
|
||||
FindObjectsInactive.Exclude,
|
||||
FindObjectsSortMode.None))
|
||||
{
|
||||
foreach (Collider objectCollider in objectColliders)
|
||||
{
|
||||
if (objectCollider != null && playerCollider != null)
|
||||
Physics.IgnoreCollision(objectCollider, playerCollider, true);
|
||||
}
|
||||
desiredIgnoredColliders.Clear();
|
||||
AddDraggerColliders(firstDraggerClientId.Value);
|
||||
AddDraggerColliders(secondDraggerClientId.Value);
|
||||
|
||||
ignoredPlayerColliders.Add(playerCollider);
|
||||
collidersToRestore.Clear();
|
||||
foreach (Collider ignoredCollider in ignoredPlayerColliders)
|
||||
{
|
||||
if (ignoredCollider == null || !desiredIgnoredColliders.Contains(ignoredCollider))
|
||||
collidersToRestore.Add(ignoredCollider);
|
||||
}
|
||||
|
||||
foreach (Collider colliderToRestore in collidersToRestore)
|
||||
{
|
||||
SetCollisionIgnored(colliderToRestore, false);
|
||||
ignoredPlayerColliders.Remove(colliderToRestore);
|
||||
}
|
||||
|
||||
foreach (Collider desiredCollider in desiredIgnoredColliders)
|
||||
{
|
||||
if (desiredCollider != null && ignoredPlayerColliders.Add(desiredCollider))
|
||||
SetCollisionIgnored(desiredCollider, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddDraggerColliders(ulong clientId)
|
||||
{
|
||||
if (clientId == NoDragger || !TryGetPlayerObject(clientId, out NetworkObject playerObject))
|
||||
return;
|
||||
|
||||
foreach (Collider playerCollider in playerObject.GetComponentsInChildren<Collider>(true))
|
||||
desiredIgnoredColliders.Add(playerCollider);
|
||||
}
|
||||
|
||||
private void SetCollisionIgnored(Collider playerCollider, bool ignored)
|
||||
{
|
||||
if (playerCollider == null)
|
||||
return;
|
||||
|
||||
foreach (Collider objectCollider in objectColliders)
|
||||
{
|
||||
if (objectCollider != null)
|
||||
Physics.IgnoreCollision(objectCollider, playerCollider, ignored);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -619,13 +718,11 @@ public sealed class NetworkDraggableInteractable : NetworkInteractable, IWorksta
|
||||
if (playerCollider == null)
|
||||
continue;
|
||||
|
||||
foreach (Collider objectCollider in objectColliders)
|
||||
{
|
||||
if (objectCollider != null)
|
||||
Physics.IgnoreCollision(objectCollider, playerCollider, false);
|
||||
}
|
||||
SetCollisionIgnored(playerCollider, false);
|
||||
}
|
||||
|
||||
ignoredPlayerColliders.Clear();
|
||||
desiredIgnoredColliders.Clear();
|
||||
collidersToRestore.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
|
||||
[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("Throw")]
|
||||
@@ -35,10 +36,11 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
|
||||
NetworkVariableWritePermission.Server);
|
||||
|
||||
private readonly HashSet<Collider> ignoredPlayerColliders = new();
|
||||
private readonly HashSet<Collider> desiredIgnoredColliders = new();
|
||||
private readonly List<Collider> collidersToRestore = new();
|
||||
private float nextCollisionRefreshTime;
|
||||
private Vector3 followVelocity;
|
||||
private Vector3 previousHolderPosition;
|
||||
private bool hasPreviousHolderPosition;
|
||||
private bool initialUseGravity;
|
||||
private CollisionDetectionMode initialCollisionDetectionMode;
|
||||
|
||||
protected abstract Vector3 HoldingOffset { get; }
|
||||
protected abstract string DropPrompt { get; }
|
||||
@@ -68,6 +70,12 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
|
||||
|
||||
if (objectColliders == null || objectColliders.Length == 0)
|
||||
objectColliders = GetComponentsInChildren<Collider>(true);
|
||||
|
||||
if (physicsBody != null)
|
||||
{
|
||||
initialUseGravity = physicsBody.useGravity;
|
||||
initialCollisionDetectionMode = physicsBody.collisionDetectionMode;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
@@ -75,7 +83,7 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
|
||||
SpawnedHeldObjects.Add(this);
|
||||
holderClientId.OnValueChanged += HandleHolderChanged;
|
||||
isExternallyControlled.OnValueChanged += HandleExternalControlChanged;
|
||||
ApplyHoldingState(IsHeld || IsExternallyControlled);
|
||||
ApplyHoldingState();
|
||||
}
|
||||
|
||||
public override void OnNetworkDespawn()
|
||||
@@ -83,12 +91,24 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
|
||||
holderClientId.OnValueChanged -= HandleHolderChanged;
|
||||
isExternallyControlled.OnValueChanged -= HandleExternalControlChanged;
|
||||
SpawnedHeldObjects.Remove(this);
|
||||
ApplyHoldingState(false);
|
||||
RestorePlayerCollisions();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
private void Update()
|
||||
{
|
||||
if (!IsSpawned || !IsHeld)
|
||||
if (!IsSpawned || !IsHeld || IsExternallyControlled ||
|
||||
Time.time < nextCollisionRefreshTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
nextCollisionRefreshTime = Time.time + collisionRefreshInterval;
|
||||
RefreshHolderCollisions();
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (!IsServer || !IsSpawned || !IsHeld || IsExternallyControlled || physicsBody == null)
|
||||
return;
|
||||
|
||||
if (!TryGetPlayerObject(holderClientId.Value, out NetworkObject holder))
|
||||
@@ -99,15 +119,10 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
|
||||
return;
|
||||
}
|
||||
|
||||
FollowHolderTranslation(holder.transform.position);
|
||||
Transform anchor = ResolveHoldingAnchor(holder);
|
||||
FollowHoldingAnchor(anchor);
|
||||
if (!DriveTowardAnchor(anchor))
|
||||
return;
|
||||
|
||||
if (Time.time >= nextCollisionRefreshTime)
|
||||
{
|
||||
nextCollisionRefreshTime = Time.time + collisionRefreshInterval;
|
||||
IgnoreCollisionsWithPlayers();
|
||||
}
|
||||
}
|
||||
|
||||
public void RequestThrow()
|
||||
@@ -126,7 +141,7 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
|
||||
if (IsHeld)
|
||||
holderClientId.Value = NoHolder;
|
||||
|
||||
ApplyHoldingState(true);
|
||||
ApplyHoldingState();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -136,7 +151,23 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
|
||||
return false;
|
||||
|
||||
isExternallyControlled.Value = false;
|
||||
ApplyHoldingState(IsHeld);
|
||||
ApplyHoldingState();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryReleaseExternalControlToPlayer(ulong clientId)
|
||||
{
|
||||
if (!IsServer || !IsSpawned || !IsExternallyControlled ||
|
||||
TryGetHeldObject(clientId, out _) ||
|
||||
NetworkHandItemInteractable.TryGetHeldItem(clientId, out _) ||
|
||||
!TryGetPlayerObject(clientId, out _))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
isExternallyControlled.Value = false;
|
||||
holderClientId.Value = clientId;
|
||||
ApplyHoldingState();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -208,13 +239,13 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
|
||||
return;
|
||||
|
||||
holderClientId.Value = clientId;
|
||||
ApplyHoldingState(true);
|
||||
ApplyHoldingState();
|
||||
}
|
||||
|
||||
private void StopHolding()
|
||||
{
|
||||
holderClientId.Value = NoHolder;
|
||||
ApplyHoldingState(IsExternallyControlled);
|
||||
ApplyHoldingState();
|
||||
}
|
||||
|
||||
private Transform ResolveHoldingAnchor(NetworkObject holder)
|
||||
@@ -224,94 +255,134 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
|
||||
return cameraController != null ? cameraController.AimTransform : holder.transform;
|
||||
}
|
||||
|
||||
private void FollowHoldingAnchor(Transform anchor)
|
||||
private bool DriveTowardAnchor(Transform anchor)
|
||||
{
|
||||
Vector3 targetPosition = anchor.TransformPoint(HoldingOffset);
|
||||
Vector3 targetDelta = targetPosition - transform.position;
|
||||
Vector3 targetDelta = targetPosition - physicsBody.position;
|
||||
|
||||
if (targetDelta.sqrMagnitude > maximumFollowDistance * maximumFollowDistance)
|
||||
if (targetDelta.sqrMagnitude > maximumHoldDistance * maximumHoldDistance)
|
||||
{
|
||||
transform.position = targetPosition -
|
||||
targetDelta.normalized * maximumFollowDistance;
|
||||
followVelocity = Vector3.zero;
|
||||
StopHolding();
|
||||
return false;
|
||||
}
|
||||
|
||||
transform.position = Vector3.SmoothDamp(
|
||||
transform.position,
|
||||
targetPosition,
|
||||
ref followVelocity,
|
||||
positionSmoothTime,
|
||||
maximumFollowSpeed,
|
||||
Time.deltaTime);
|
||||
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);
|
||||
|
||||
float rotationBlend = 1f - Mathf.Exp(-rotationFollowSpeed * Time.deltaTime);
|
||||
transform.rotation = Quaternion.Slerp(
|
||||
transform.rotation,
|
||||
anchor.rotation,
|
||||
rotationBlend);
|
||||
DriveRotation(anchor.rotation);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void FollowHolderTranslation(Vector3 holderPosition)
|
||||
private void DriveRotation(Quaternion targetRotation)
|
||||
{
|
||||
if (!hasPreviousHolderPosition)
|
||||
{
|
||||
previousHolderPosition = holderPosition;
|
||||
hasPreviousHolderPosition = true;
|
||||
Quaternion rotationDelta = targetRotation * Quaternion.Inverse(physicsBody.rotation);
|
||||
rotationDelta.ToAngleAxis(out float angle, out Vector3 axis);
|
||||
if (axis.sqrMagnitude < 0.0001f || float.IsNaN(axis.x))
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 holderDelta = holderPosition - previousHolderPosition;
|
||||
previousHolderPosition = holderPosition;
|
||||
if (angle > 180f)
|
||||
angle -= 360f;
|
||||
|
||||
transform.position += holderDelta;
|
||||
Vector3 desiredAngularVelocity = axis.normalized *
|
||||
(angle * Mathf.Deg2Rad * rotationFollowSpeed);
|
||||
desiredAngularVelocity = Vector3.ClampMagnitude(
|
||||
desiredAngularVelocity,
|
||||
rotationFollowSpeed);
|
||||
Vector3 angularVelocityChange = Vector3.ClampMagnitude(
|
||||
desiredAngularVelocity - physicsBody.angularVelocity,
|
||||
rotationFollowSpeed * 4f * Time.fixedDeltaTime);
|
||||
physicsBody.AddTorque(angularVelocityChange, ForceMode.VelocityChange);
|
||||
}
|
||||
|
||||
private void HandleHolderChanged(ulong _, ulong currentHolder) =>
|
||||
ApplyHoldingState(currentHolder != NoHolder || IsExternallyControlled);
|
||||
private void HandleHolderChanged(ulong _, ulong __) => ApplyHoldingState();
|
||||
|
||||
private void HandleExternalControlChanged(bool _, bool isControlled) =>
|
||||
ApplyHoldingState(IsHeld || isControlled);
|
||||
private void HandleExternalControlChanged(bool _, bool __) => ApplyHoldingState();
|
||||
|
||||
private void ApplyHoldingState(bool isHeld)
|
||||
private void ApplyHoldingState()
|
||||
{
|
||||
followVelocity = Vector3.zero;
|
||||
hasPreviousHolderPosition = false;
|
||||
|
||||
if (physicsBody != null)
|
||||
{
|
||||
bool shouldBeKinematic = isHeld || !IsServer;
|
||||
bool isPhysicallyHeld = IsHeld && !IsExternallyControlled;
|
||||
bool shouldBeKinematic = IsExternallyControlled || !IsServer;
|
||||
|
||||
if (physicsBody.isKinematic && !shouldBeKinematic)
|
||||
if (shouldBeKinematic)
|
||||
{
|
||||
physicsBody.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
|
||||
physicsBody.isKinematic = true;
|
||||
physicsBody.useGravity = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
physicsBody.isKinematic = false;
|
||||
physicsBody.useGravity = isPhysicallyHeld ? false : initialUseGravity;
|
||||
physicsBody.collisionDetectionMode = ResolveDynamicCollisionDetectionMode();
|
||||
}
|
||||
|
||||
if (!physicsBody.isKinematic)
|
||||
if (!isPhysicallyHeld)
|
||||
{
|
||||
physicsBody.linearVelocity = Vector3.zero;
|
||||
physicsBody.angularVelocity = Vector3.zero;
|
||||
}
|
||||
|
||||
physicsBody.isKinematic = shouldBeKinematic;
|
||||
}
|
||||
|
||||
if (isHeld)
|
||||
IgnoreCollisionsWithPlayers();
|
||||
if (IsHeld && !IsExternallyControlled)
|
||||
RefreshHolderCollisions();
|
||||
else
|
||||
RestorePlayerCollisions();
|
||||
}
|
||||
|
||||
private void IgnoreCollisionsWithPlayers()
|
||||
{
|
||||
foreach (CharacterController playerCollider in FindObjectsByType<CharacterController>(
|
||||
FindObjectsInactive.Exclude,
|
||||
FindObjectsSortMode.None))
|
||||
{
|
||||
foreach (Collider objectCollider in objectColliders)
|
||||
{
|
||||
if (objectCollider != null && playerCollider != null)
|
||||
Physics.IgnoreCollision(objectCollider, playerCollider, true);
|
||||
}
|
||||
private CollisionDetectionMode ResolveDynamicCollisionDetectionMode() =>
|
||||
initialCollisionDetectionMode == CollisionDetectionMode.Discrete
|
||||
? CollisionDetectionMode.ContinuousDynamic
|
||||
: initialCollisionDetectionMode;
|
||||
|
||||
ignoredPlayerColliders.Add(playerCollider);
|
||||
private void RefreshHolderCollisions()
|
||||
{
|
||||
desiredIgnoredColliders.Clear();
|
||||
if (TryGetPlayerObject(holderClientId.Value, out NetworkObject holder))
|
||||
{
|
||||
foreach (Collider holderCollider in holder.GetComponentsInChildren<Collider>(true))
|
||||
desiredIgnoredColliders.Add(holderCollider);
|
||||
}
|
||||
|
||||
collidersToRestore.Clear();
|
||||
foreach (Collider ignoredCollider in ignoredPlayerColliders)
|
||||
{
|
||||
if (ignoredCollider == null || !desiredIgnoredColliders.Contains(ignoredCollider))
|
||||
collidersToRestore.Add(ignoredCollider);
|
||||
}
|
||||
|
||||
foreach (Collider colliderToRestore in collidersToRestore)
|
||||
{
|
||||
SetCollisionIgnored(colliderToRestore, false);
|
||||
ignoredPlayerColliders.Remove(colliderToRestore);
|
||||
}
|
||||
|
||||
foreach (Collider desiredCollider in desiredIgnoredColliders)
|
||||
{
|
||||
if (desiredCollider != null && ignoredPlayerColliders.Add(desiredCollider))
|
||||
SetCollisionIgnored(desiredCollider, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetCollisionIgnored(Collider playerCollider, bool ignored)
|
||||
{
|
||||
if (playerCollider == null)
|
||||
return;
|
||||
|
||||
foreach (Collider objectCollider in objectColliders)
|
||||
{
|
||||
if (objectCollider != null)
|
||||
Physics.IgnoreCollision(objectCollider, playerCollider, ignored);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,13 +393,11 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
|
||||
if (playerCollider == null)
|
||||
continue;
|
||||
|
||||
foreach (Collider objectCollider in objectColliders)
|
||||
{
|
||||
if (objectCollider != null)
|
||||
Physics.IgnoreCollision(objectCollider, playerCollider, false);
|
||||
}
|
||||
SetCollisionIgnored(playerCollider, false);
|
||||
}
|
||||
|
||||
ignoredPlayerColliders.Clear();
|
||||
desiredIgnoredColliders.Clear();
|
||||
collidersToRestore.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user