Added new Rocket-Processing
This commit is contained in:
@@ -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