632 lines
21 KiB
C#
632 lines
21 KiB
C#
using System.Collections.Generic;
|
|
using Unity.Netcode;
|
|
using Unity.Netcode.Components;
|
|
using UnityEngine;
|
|
using UnityEngine.Serialization;
|
|
|
|
public enum DraggableMovementMode
|
|
{
|
|
Free3D = 0,
|
|
KeepWorldHeight = 1,
|
|
FollowGround = 2
|
|
}
|
|
|
|
[RequireComponent(typeof(Rigidbody), typeof(NetworkRigidbody))]
|
|
public sealed class NetworkDraggableInteractable : NetworkInteractable, IWorkstationItemControl
|
|
{
|
|
private const ulong NoDragger = ulong.MaxValue;
|
|
private static readonly HashSet<NetworkDraggableInteractable> SpawnedDraggables = new();
|
|
|
|
[Header("Weight")]
|
|
[SerializeField, Min(0.1f)] private float weight = 35f;
|
|
[SerializeField, Min(0.1f)] private float pullStrengthPerPlayer = 50f;
|
|
[SerializeField, Range(1, 2)] private int maximumDraggers = 2;
|
|
|
|
[Header("Dragging")]
|
|
[SerializeField] private Vector3 dragOffset = new(0f, 1f, 1.8f);
|
|
[SerializeField, Min(0.1f)] private float maximumDragSpeed = 3f;
|
|
[SerializeField, Range(0.05f, 1f)] private float minimumSpeedMultiplier = 0.35f;
|
|
[SerializeField, Min(0.5f)] private float maximumDraggerDistance = 4.5f;
|
|
[SerializeField, Min(0.01f)] private float positionSmoothTime = 0.12f;
|
|
[SerializeField, Min(0.1f)] private float rotationFollowSpeed = 8f;
|
|
[SerializeField] private Vector3 rotationOffset;
|
|
[FormerlySerializedAs("keepCurrentHeight")]
|
|
[SerializeField] private DraggableMovementMode movementMode;
|
|
|
|
[Header("Ground Following")]
|
|
[SerializeField] private LayerMask groundLayers = ~0;
|
|
[SerializeField] private Transform groundContactPoint;
|
|
[SerializeField, Min(0.01f)] private float groundProbeRadius = 0.2f;
|
|
[SerializeField, Min(0.1f)] private float groundProbeHeight = 1.25f;
|
|
[SerializeField, Min(0.1f)] private float maximumGroundDrop = 2f;
|
|
[SerializeField, Range(0f, 89f)] private float maximumGroundAngle = 55f;
|
|
[SerializeField, Min(0f)] private float groundClearance = 0.02f;
|
|
[SerializeField, Min(0.1f)] private float maximumGroundVerticalSpeed = 6f;
|
|
[SerializeField] private bool alignToGround = true;
|
|
[SerializeField, Min(0.1f)] private float groundAlignmentSpeed = 10f;
|
|
|
|
[Header("Physics")]
|
|
[SerializeField] private Rigidbody physicsBody;
|
|
[SerializeField] private Collider[] objectColliders;
|
|
[SerializeField, Min(0.05f)] private float collisionRefreshInterval = 0.25f;
|
|
|
|
private readonly NetworkVariable<ulong> firstDraggerClientId = new(
|
|
NoDragger,
|
|
NetworkVariableReadPermission.Everyone,
|
|
NetworkVariableWritePermission.Server);
|
|
|
|
private readonly NetworkVariable<ulong> secondDraggerClientId = new(
|
|
NoDragger,
|
|
NetworkVariableReadPermission.Everyone,
|
|
NetworkVariableWritePermission.Server);
|
|
|
|
private readonly NetworkVariable<bool> isExternallyControlled = new(
|
|
false,
|
|
NetworkVariableReadPermission.Everyone,
|
|
NetworkVariableWritePermission.Server);
|
|
|
|
private readonly HashSet<Collider> ignoredPlayerColliders = new();
|
|
private readonly RaycastHit[] groundHits = new RaycastHit[16];
|
|
private float nextCollisionRefreshTime;
|
|
private Vector3 localGroundContactPoint;
|
|
private Vector3 smoothedGroundNormal = Vector3.up;
|
|
private Vector3 dragVelocity;
|
|
|
|
public float Weight => weight;
|
|
public int ActiveDraggerCount
|
|
{
|
|
get
|
|
{
|
|
int count = firstDraggerClientId.Value == NoDragger ? 0 : 1;
|
|
if (secondDraggerClientId.Value != NoDragger)
|
|
count++;
|
|
return count;
|
|
}
|
|
}
|
|
public int RequiredDraggerCount => Mathf.Max(1, Mathf.CeilToInt(weight / pullStrengthPerPlayer));
|
|
public bool HasEnoughPullStrength => ActiveDraggerCount >= RequiredDraggerCount;
|
|
public bool IsExternallyControlled => isExternallyControlled.Value;
|
|
|
|
private bool HasAnyDragger => ActiveDraggerCount > 0;
|
|
private bool IsDraggedByLocalPlayer =>
|
|
NetworkManager != null && IsDragger(NetworkManager.LocalClientId);
|
|
|
|
public override string InteractionPrompt
|
|
{
|
|
get
|
|
{
|
|
if (IsExternallyControlled)
|
|
return "In machine";
|
|
|
|
if (IsDraggedByLocalPlayer)
|
|
return "Release";
|
|
|
|
int activeDraggers = ActiveDraggerCount;
|
|
if (activeDraggers == 0)
|
|
return $"{InteractionLabel} ({weight:0.#} kg)";
|
|
|
|
if (activeDraggers < maximumDraggers)
|
|
return !HasEnoughPullStrength
|
|
? $"Help drag ({activeDraggers}/{RequiredDraggerCount})"
|
|
: $"Join drag ({activeDraggers}/{maximumDraggers})";
|
|
|
|
return HasEnoughPullStrength ? "In use" : "Too heavy";
|
|
}
|
|
}
|
|
|
|
public override bool IsInteractionAvailable => base.IsInteractionAvailable &&
|
|
!IsExternallyControlled &&
|
|
(IsDraggedByLocalPlayer ||
|
|
(ActiveDraggerCount < maximumDraggers &&
|
|
(NetworkManager == null ||
|
|
!TryGetDraggedObject(NetworkManager.LocalClientId, this, out _))));
|
|
|
|
private void Awake()
|
|
{
|
|
ResolvePhysicsReferences();
|
|
ApplyWeight();
|
|
}
|
|
|
|
private void OnValidate()
|
|
{
|
|
ResolvePhysicsReferences();
|
|
ApplyWeight();
|
|
}
|
|
|
|
public override void OnNetworkSpawn()
|
|
{
|
|
SpawnedDraggables.Add(this);
|
|
firstDraggerClientId.OnValueChanged += HandleDraggerChanged;
|
|
secondDraggerClientId.OnValueChanged += HandleDraggerChanged;
|
|
isExternallyControlled.OnValueChanged += HandleExternalControlChanged;
|
|
ApplyDraggingState();
|
|
}
|
|
|
|
public override void OnNetworkDespawn()
|
|
{
|
|
SpawnedDraggables.Remove(this);
|
|
firstDraggerClientId.OnValueChanged -= HandleDraggerChanged;
|
|
secondDraggerClientId.OnValueChanged -= HandleDraggerChanged;
|
|
isExternallyControlled.OnValueChanged -= HandleExternalControlChanged;
|
|
RestorePlayerCollisions();
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (!HasAnyDragger || Time.time < nextCollisionRefreshTime)
|
|
return;
|
|
|
|
nextCollisionRefreshTime = Time.time + collisionRefreshInterval;
|
|
IgnoreCollisionsWithPlayers();
|
|
}
|
|
|
|
private void FixedUpdate()
|
|
{
|
|
if (!IsServer || !IsSpawned || physicsBody == null || IsExternallyControlled)
|
|
return;
|
|
|
|
RemoveInvalidDraggers();
|
|
if (!HasEnoughPullStrength ||
|
|
!TryGetCombinedDragTarget(out Vector3 target, out Vector3 forward))
|
|
{
|
|
dragVelocity = Vector3.zero;
|
|
return;
|
|
}
|
|
|
|
float totalStrength = ActiveDraggerCount * pullStrengthPerPlayer;
|
|
float loadRatio = Mathf.Clamp01(weight / totalStrength);
|
|
float speedMultiplier = Mathf.Lerp(1f, minimumSpeedMultiplier, loadRatio);
|
|
float movementSpeed = maximumDragSpeed * speedMultiplier;
|
|
|
|
switch (movementMode)
|
|
{
|
|
case DraggableMovementMode.KeepWorldHeight:
|
|
target.y = physicsBody.position.y;
|
|
FollowDragTarget(target, forward, movementSpeed, Vector3.up);
|
|
break;
|
|
|
|
case DraggableMovementMode.FollowGround:
|
|
MoveAlongGround(target, forward, movementSpeed);
|
|
break;
|
|
|
|
default:
|
|
FollowDragTarget(target, forward, movementSpeed, Vector3.up);
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected override bool CanInteractOnServer(ulong senderClientId)
|
|
{
|
|
if (IsExternallyControlled)
|
|
return false;
|
|
|
|
if (IsDragger(senderClientId))
|
|
return true;
|
|
|
|
return ActiveDraggerCount < maximumDraggers &&
|
|
!TryGetDraggedObject(senderClientId, this, out _);
|
|
}
|
|
|
|
protected override void InteractOnServer(ulong senderClientId, NetworkObject playerObject)
|
|
{
|
|
if (IsDragger(senderClientId))
|
|
RemoveDragger(senderClientId);
|
|
else
|
|
AddDragger(senderClientId);
|
|
}
|
|
|
|
private void AddDragger(ulong clientId)
|
|
{
|
|
if (IsExternallyControlled || TryGetDraggedObject(clientId, this, out _))
|
|
return;
|
|
|
|
if (firstDraggerClientId.Value == NoDragger)
|
|
firstDraggerClientId.Value = clientId;
|
|
else if (maximumDraggers > 1 && secondDraggerClientId.Value == NoDragger)
|
|
secondDraggerClientId.Value = clientId;
|
|
}
|
|
|
|
private void RemoveDragger(ulong clientId)
|
|
{
|
|
if (firstDraggerClientId.Value == clientId)
|
|
{
|
|
firstDraggerClientId.Value = secondDraggerClientId.Value;
|
|
secondDraggerClientId.Value = NoDragger;
|
|
}
|
|
else if (secondDraggerClientId.Value == clientId)
|
|
{
|
|
secondDraggerClientId.Value = NoDragger;
|
|
}
|
|
}
|
|
|
|
private void RemoveInvalidDraggers()
|
|
{
|
|
ulong first = firstDraggerClientId.Value;
|
|
ulong second = secondDraggerClientId.Value;
|
|
|
|
if (first != NoDragger && !IsDraggerValid(first))
|
|
RemoveDragger(first);
|
|
|
|
if (second != NoDragger && !IsDraggerValid(second))
|
|
RemoveDragger(second);
|
|
}
|
|
|
|
private bool IsDraggerValid(ulong clientId)
|
|
{
|
|
if (!TryGetPlayerObject(clientId, out NetworkObject playerObject))
|
|
return false;
|
|
|
|
float maximumDistanceSquared = maximumDraggerDistance * maximumDraggerDistance;
|
|
return (playerObject.transform.position - physicsBody.position).sqrMagnitude <= maximumDistanceSquared;
|
|
}
|
|
|
|
private bool TryGetCombinedDragTarget(out Vector3 target, out Vector3 forward)
|
|
{
|
|
target = Vector3.zero;
|
|
forward = Vector3.zero;
|
|
int validTargets = 0;
|
|
|
|
AddDragTarget(firstDraggerClientId.Value, ref target, ref forward, ref validTargets);
|
|
AddDragTarget(secondDraggerClientId.Value, ref target, ref forward, ref validTargets);
|
|
|
|
if (validTargets == 0)
|
|
return false;
|
|
|
|
target /= validTargets;
|
|
forward = Vector3.ProjectOnPlane(forward, Vector3.up);
|
|
|
|
if (forward.sqrMagnitude < 0.0001f)
|
|
forward = Vector3.ProjectOnPlane(target - physicsBody.position, Vector3.up);
|
|
|
|
if (forward.sqrMagnitude < 0.0001f)
|
|
forward = Vector3.ProjectOnPlane(physicsBody.transform.forward, Vector3.up);
|
|
|
|
forward.Normalize();
|
|
return true;
|
|
}
|
|
|
|
private void AddDragTarget(
|
|
ulong clientId,
|
|
ref Vector3 target,
|
|
ref Vector3 forward,
|
|
ref int validTargets)
|
|
{
|
|
if (clientId == NoDragger || !TryGetPlayerObject(clientId, out NetworkObject playerObject))
|
|
return;
|
|
|
|
FirstPersonCameraController cameraController =
|
|
playerObject.GetComponent<FirstPersonCameraController>();
|
|
Vector3 aimForward = cameraController != null
|
|
? cameraController.AimForward
|
|
: playerObject.transform.forward;
|
|
|
|
target += playerObject.transform.position +
|
|
playerObject.transform.right * dragOffset.x +
|
|
Vector3.up * dragOffset.y +
|
|
aimForward * dragOffset.z;
|
|
forward += aimForward;
|
|
validTargets++;
|
|
}
|
|
|
|
private static bool TryGetDraggedObject(
|
|
ulong clientId,
|
|
NetworkDraggableInteractable except,
|
|
out NetworkDraggableInteractable draggedObject)
|
|
{
|
|
foreach (NetworkDraggableInteractable candidate in SpawnedDraggables)
|
|
{
|
|
if (candidate != null && candidate != except && candidate.IsDragger(clientId))
|
|
{
|
|
draggedObject = candidate;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
draggedObject = null;
|
|
return false;
|
|
}
|
|
|
|
public static bool TryGetDraggedObject(
|
|
ulong clientId,
|
|
out NetworkDraggableInteractable draggedObject) =>
|
|
TryGetDraggedObject(clientId, null, out draggedObject);
|
|
|
|
public void RequestRelease()
|
|
{
|
|
if (IsSpawned && IsDraggedByLocalPlayer)
|
|
RequestReleaseRpc();
|
|
}
|
|
|
|
public bool TryAcquireExternalControl()
|
|
{
|
|
if (!IsServer || !IsSpawned || IsExternallyControlled)
|
|
return false;
|
|
|
|
isExternallyControlled.Value = true;
|
|
|
|
firstDraggerClientId.Value = NoDragger;
|
|
secondDraggerClientId.Value = NoDragger;
|
|
ApplyDraggingState();
|
|
return true;
|
|
}
|
|
|
|
public bool TryReleaseExternalControl()
|
|
{
|
|
if (!IsServer || !IsSpawned || !IsExternallyControlled)
|
|
return false;
|
|
|
|
isExternallyControlled.Value = false;
|
|
ApplyDraggingState();
|
|
return true;
|
|
}
|
|
|
|
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
|
|
private void RequestReleaseRpc(RpcParams rpcParams = default)
|
|
{
|
|
ulong senderClientId = rpcParams.Receive.SenderClientId;
|
|
if (!IsExternallyControlled && IsDragger(senderClientId))
|
|
RemoveDragger(senderClientId);
|
|
}
|
|
|
|
private bool IsDragger(ulong clientId) =>
|
|
firstDraggerClientId.Value == clientId || secondDraggerClientId.Value == clientId;
|
|
|
|
private void HandleDraggerChanged(ulong _, ulong __) => ApplyDraggingState();
|
|
|
|
private void HandleExternalControlChanged(bool _, bool __) => ApplyDraggingState();
|
|
|
|
private void ApplyDraggingState()
|
|
{
|
|
if (physicsBody != null)
|
|
{
|
|
bool shouldBeKinematic = HasAnyDragger || IsExternallyControlled || !IsServer;
|
|
|
|
if (physicsBody.isKinematic && !shouldBeKinematic)
|
|
physicsBody.isKinematic = false;
|
|
|
|
if (!physicsBody.isKinematic)
|
|
{
|
|
physicsBody.linearVelocity = Vector3.zero;
|
|
physicsBody.angularVelocity = Vector3.zero;
|
|
}
|
|
|
|
physicsBody.isKinematic = shouldBeKinematic;
|
|
}
|
|
|
|
if (HasAnyDragger || IsExternallyControlled)
|
|
{
|
|
dragVelocity = Vector3.zero;
|
|
CacheGroundContactPoint();
|
|
smoothedGroundNormal = physicsBody != null ? physicsBody.transform.up : Vector3.up;
|
|
IgnoreCollisionsWithPlayers();
|
|
}
|
|
else
|
|
{
|
|
dragVelocity = Vector3.zero;
|
|
RestorePlayerCollisions();
|
|
}
|
|
}
|
|
|
|
private void ResolvePhysicsReferences()
|
|
{
|
|
if (physicsBody == null)
|
|
physicsBody = GetComponent<Rigidbody>();
|
|
|
|
if (objectColliders == null || objectColliders.Length == 0)
|
|
objectColliders = GetComponentsInChildren<Collider>(true);
|
|
|
|
CacheGroundContactPoint();
|
|
}
|
|
|
|
private void ApplyWeight()
|
|
{
|
|
if (physicsBody != null)
|
|
physicsBody.mass = Mathf.Max(0.1f, weight);
|
|
}
|
|
|
|
private void FollowDragTarget(
|
|
Vector3 target,
|
|
Vector3 forward,
|
|
float movementSpeed,
|
|
Vector3 surfaceNormal)
|
|
{
|
|
Vector3 nextPosition = Vector3.SmoothDamp(
|
|
physicsBody.position,
|
|
target,
|
|
ref dragVelocity,
|
|
positionSmoothTime,
|
|
movementSpeed,
|
|
Time.fixedDeltaTime);
|
|
|
|
physicsBody.MovePosition(nextPosition);
|
|
physicsBody.MoveRotation(CalculateDragRotation(forward, surfaceNormal));
|
|
}
|
|
|
|
private void MoveAlongGround(
|
|
Vector3 dragTarget,
|
|
Vector3 forward,
|
|
float movementSpeed)
|
|
{
|
|
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;
|
|
|
|
if (!TryGetGroundSurface(probePosition, out Vector3 groundPoint, out Vector3 groundNormal))
|
|
return;
|
|
|
|
Quaternion targetRotation = CalculateDragRotation(forward, groundNormal);
|
|
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);
|
|
|
|
physicsBody.MovePosition(new Vector3(nextPlanarPosition.x, nextHeight, nextPlanarPosition.z));
|
|
|
|
physicsBody.MoveRotation(targetRotation);
|
|
}
|
|
|
|
private bool TryGetGroundSurface(
|
|
Vector3 probePosition,
|
|
out Vector3 groundPoint,
|
|
out Vector3 groundNormal)
|
|
{
|
|
Vector3 origin = probePosition + Vector3.up * groundProbeHeight;
|
|
float castDistance = groundProbeHeight + maximumGroundDrop;
|
|
int hitCount = Physics.SphereCastNonAlloc(
|
|
origin,
|
|
groundProbeRadius,
|
|
Vector3.down,
|
|
groundHits,
|
|
castDistance,
|
|
groundLayers,
|
|
QueryTriggerInteraction.Ignore);
|
|
|
|
float nearestDistance = float.PositiveInfinity;
|
|
groundPoint = default;
|
|
groundNormal = Vector3.up;
|
|
|
|
for (int index = 0; index < hitCount; index++)
|
|
{
|
|
RaycastHit hit = groundHits[index];
|
|
if (hit.collider == null || IsOwnCollider(hit.collider) ||
|
|
hit.collider.GetComponentInParent<CharacterController>() != null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (Vector3.Angle(Vector3.up, hit.normal) > maximumGroundAngle ||
|
|
hit.distance >= nearestDistance)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
nearestDistance = hit.distance;
|
|
groundPoint = hit.point;
|
|
groundNormal = hit.normal;
|
|
}
|
|
|
|
return !float.IsPositiveInfinity(nearestDistance);
|
|
}
|
|
|
|
private Quaternion CalculateDragRotation(Vector3 forward, Vector3 groundNormal)
|
|
{
|
|
Vector3 targetUp = alignToGround ? groundNormal : Vector3.up;
|
|
float normalBlend = 1f - Mathf.Exp(-groundAlignmentSpeed * Time.fixedDeltaTime);
|
|
smoothedGroundNormal = Vector3.Slerp(
|
|
smoothedGroundNormal,
|
|
targetUp,
|
|
normalBlend).normalized;
|
|
|
|
Vector3 surfaceForward = Vector3.ProjectOnPlane(forward, smoothedGroundNormal);
|
|
if (surfaceForward.sqrMagnitude < 0.0001f)
|
|
surfaceForward = Vector3.ProjectOnPlane(physicsBody.transform.forward, smoothedGroundNormal);
|
|
|
|
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);
|
|
}
|
|
|
|
private void CacheGroundContactPoint()
|
|
{
|
|
if (physicsBody == null)
|
|
return;
|
|
|
|
if (groundContactPoint != null)
|
|
{
|
|
localGroundContactPoint = physicsBody.transform.InverseTransformPoint(groundContactPoint.position);
|
|
return;
|
|
}
|
|
|
|
bool hasBounds = false;
|
|
Bounds combinedBounds = default;
|
|
|
|
if (objectColliders != null)
|
|
{
|
|
foreach (Collider objectCollider in objectColliders)
|
|
{
|
|
if (objectCollider == null || objectCollider.isTrigger || !objectCollider.enabled)
|
|
continue;
|
|
|
|
if (!hasBounds)
|
|
{
|
|
combinedBounds = objectCollider.bounds;
|
|
hasBounds = true;
|
|
}
|
|
else
|
|
{
|
|
combinedBounds.Encapsulate(objectCollider.bounds);
|
|
}
|
|
}
|
|
}
|
|
|
|
Vector3 contactWorldPosition = hasBounds
|
|
? new Vector3(combinedBounds.center.x, combinedBounds.min.y, combinedBounds.center.z)
|
|
: physicsBody.position;
|
|
|
|
localGroundContactPoint = physicsBody.transform.InverseTransformPoint(contactWorldPosition);
|
|
}
|
|
|
|
private bool IsOwnCollider(Collider candidate)
|
|
{
|
|
if (objectColliders == null)
|
|
return false;
|
|
|
|
foreach (Collider objectCollider in objectColliders)
|
|
{
|
|
if (objectCollider == candidate)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
ignoredPlayerColliders.Add(playerCollider);
|
|
}
|
|
}
|
|
|
|
private void RestorePlayerCollisions()
|
|
{
|
|
foreach (Collider playerCollider in ignoredPlayerColliders)
|
|
{
|
|
if (playerCollider == null)
|
|
continue;
|
|
|
|
foreach (Collider objectCollider in objectColliders)
|
|
{
|
|
if (objectCollider != null)
|
|
Physics.IgnoreCollision(objectCollider, playerCollider, false);
|
|
}
|
|
}
|
|
|
|
ignoredPlayerColliders.Clear();
|
|
}
|
|
}
|