160 lines
8.2 KiB
C#
160 lines
8.2 KiB
C#
// standalone utility functions for PredictedRigidbody component.
|
|
using System;
|
|
using UnityEngine;
|
|
|
|
namespace Mirror
|
|
{
|
|
public static class PredictionUtils2D
|
|
{
|
|
// rigidbody ///////////////////////////////////////////////////////////
|
|
// move a Rigidbody + settings from one GameObject to another.
|
|
public static void MoveRigidbody(GameObject source, GameObject destination, bool destroySource = true)
|
|
{
|
|
// create a new Rigidbody component on destination.
|
|
// note that adding a Joint automatically adds a Rigidbody.
|
|
// so first check if one was added yet.
|
|
Rigidbody2D original = source.GetComponent<Rigidbody2D>();
|
|
if (original == null) throw new Exception($"Prediction: attempted to move {source}'s Rigidbody to the predicted copy, but there was no component.");
|
|
Rigidbody2D rigidbodyCopy;
|
|
if (!destination.TryGetComponent(out rigidbodyCopy))
|
|
rigidbodyCopy = destination.AddComponent<Rigidbody2D>();
|
|
|
|
// copy all properties
|
|
rigidbodyCopy.mass = original.mass;
|
|
#if UNITY_6000_0_OR_NEWER
|
|
rigidbodyCopy.linearDamping = original.linearDamping;
|
|
rigidbodyCopy.angularDamping = original.angularDamping;
|
|
#else
|
|
rigidbodyCopy.drag = original.drag;
|
|
rigidbodyCopy.angularDrag = original.angularDrag;
|
|
#endif
|
|
rigidbodyCopy.isKinematic = original.isKinematic;
|
|
rigidbodyCopy.interpolation = original.interpolation;
|
|
rigidbodyCopy.collisionDetectionMode = original.collisionDetectionMode;
|
|
// fix: need to set freezeRotation before constraints:
|
|
// https://github.com/MirrorNetworking/Mirror/pull/3946
|
|
rigidbodyCopy.freezeRotation = original.freezeRotation;
|
|
rigidbodyCopy.constraints = original.constraints;
|
|
|
|
// moving (Configurable)Joints messes up their range of motion unless
|
|
// we reset to initial position first (we do this in PredictedRigibody.cs).
|
|
// so here we don't set the Rigidbody's physics position at all.
|
|
// rigidbodyCopy.position = original.position;
|
|
// rigidbodyCopy.rotation = original.rotation;
|
|
|
|
// projects may keep Rigidbodies as kinematic sometimes. in that case, setting velocity would log an error
|
|
if (!original.isKinematic)
|
|
{
|
|
#if UNITY_6000_0_OR_NEWER
|
|
rigidbodyCopy.linearVelocity = original.linearVelocity;
|
|
#else
|
|
rigidbodyCopy.velocity = original.velocity;
|
|
#endif
|
|
rigidbodyCopy.angularVelocity = original.angularVelocity;
|
|
}
|
|
|
|
// destroy original
|
|
if (destroySource) GameObject.Destroy(original);
|
|
}
|
|
|
|
// helper function: if a collider is on a child, copy that child first.
|
|
// this way child's relative position/rotation/scale are preserved.
|
|
public static GameObject CopyRelativeTransform(GameObject source, Transform sourceChild, GameObject destination)
|
|
{
|
|
// is this on the source root? then we want to put it on the destination root.
|
|
if (sourceChild == source.transform) return destination;
|
|
|
|
// is this on a child? then create the same child with the same transform on destination.
|
|
// note this is technically only correct for the immediate child since
|
|
// .localPosition is relative to parent, but this is good enough.
|
|
GameObject child = new GameObject(sourceChild.name);
|
|
child.transform.SetParent(destination.transform, true);
|
|
child.transform.localPosition = sourceChild.localPosition;
|
|
child.transform.localRotation = sourceChild.localRotation;
|
|
child.transform.localScale = sourceChild.localScale;
|
|
|
|
// assign the same Layer for the physics copy.
|
|
// games may use a custom physics collision matrix, layer matters.
|
|
child.layer = sourceChild.gameObject.layer;
|
|
|
|
return child;
|
|
}
|
|
|
|
// colliders ///////////////////////////////////////////////////////////
|
|
// move all BoxColliders + settings from one GameObject to another.
|
|
public static void MoveBoxColliders(GameObject source, GameObject destination, bool destroySource = true)
|
|
{
|
|
// colliders may be on children
|
|
BoxCollider2D[] sourceColliders = source.GetComponentsInChildren<BoxCollider2D>();
|
|
foreach (BoxCollider2D sourceCollider in sourceColliders)
|
|
{
|
|
// copy the relative transform:
|
|
// if collider is on root, it returns destination root.
|
|
// if collider is on a child, it creates and returns a child on destination.
|
|
GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination);
|
|
BoxCollider2D colliderCopy = target.AddComponent<BoxCollider2D>();
|
|
colliderCopy.offset = sourceCollider.offset;
|
|
colliderCopy.size = sourceCollider.size;
|
|
colliderCopy.isTrigger = sourceCollider.isTrigger;
|
|
if (destroySource) GameObject.Destroy(sourceCollider);
|
|
}
|
|
}
|
|
|
|
// move all SphereColliders + settings from one GameObject to another.
|
|
public static void MoveSphereColliders(GameObject source, GameObject destination, bool destroySource = true)
|
|
{
|
|
// colliders may be on children
|
|
CircleCollider2D[] sourceColliders = source.GetComponentsInChildren<CircleCollider2D>();
|
|
foreach (CircleCollider2D sourceCollider in sourceColliders)
|
|
{
|
|
// copy the relative transform:
|
|
// if collider is on root, it returns destination root.
|
|
// if collider is on a child, it creates and returns a child on destination.
|
|
GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination);
|
|
CircleCollider2D colliderCopy = target.AddComponent<CircleCollider2D>();
|
|
colliderCopy.offset = sourceCollider.offset;
|
|
colliderCopy.radius = sourceCollider.radius;
|
|
colliderCopy.isTrigger = sourceCollider.isTrigger;
|
|
if (destroySource) GameObject.Destroy(sourceCollider);
|
|
}
|
|
}
|
|
|
|
// move all CapsuleColliders + settings from one GameObject to another.
|
|
public static void MoveCapsuleColliders(GameObject source, GameObject destination, bool destroySource = true)
|
|
{
|
|
// colliders may be on children
|
|
CapsuleCollider2D[] sourceColliders = source.GetComponentsInChildren<CapsuleCollider2D>();
|
|
foreach (CapsuleCollider2D sourceCollider in sourceColliders)
|
|
{
|
|
// copy the relative transform:
|
|
// if collider is on root, it returns destination root.
|
|
// if collider is on a child, it creates and returns a child on destination.
|
|
GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination);
|
|
CapsuleCollider2D colliderCopy = target.AddComponent<CapsuleCollider2D>();
|
|
colliderCopy.offset = sourceCollider.offset;
|
|
colliderCopy.size = sourceCollider.size;
|
|
colliderCopy.direction = sourceCollider.direction;
|
|
colliderCopy.isTrigger = sourceCollider.isTrigger;
|
|
if (destroySource) GameObject.Destroy(sourceCollider);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// move all Colliders + settings from one GameObject to another.
|
|
public static void MoveAllColliders(GameObject source, GameObject destination, bool destroySource = true)
|
|
{
|
|
MoveBoxColliders(source, destination, destroySource);
|
|
MoveSphereColliders(source, destination, destroySource);
|
|
MoveCapsuleColliders(source, destination, destroySource);
|
|
}
|
|
// all /////////////////////////////////////////////////////////////////
|
|
// move all physics components from one GameObject to another.
|
|
public static void MovePhysicsComponents(GameObject source, GameObject destination, bool destroySource = true)
|
|
{
|
|
MoveAllColliders(source, destination, destroySource);
|
|
MoveRigidbody(source, destination, destroySource);
|
|
}
|
|
}
|
|
}
|