using UnityEngine;
using System.Collections;
using RootMotion.Dynamics;
using RootMotion;
namespace RootMotion.Dynamics
{
///
/// PuppetMaster prop designed to work with Prop Muscles.
///
public class PuppetMasterProp : MonoBehaviour
{
[Tooltip("Mesh Root will be parented to Prop Muscle's target when this prop is picked up. To make sure the mesh and the colliders match up, Mesh Root's localPosition/Rotation must be zero.")]
///
/// Mesh Root will be parented to Prop Muscle's target when this prop is picked up. To make sure the mesh and the colliders match up, Mesh Root's localPosition/Rotation must be zero.
///
public Transform meshRoot;
[Tooltip("The muscle properties that will be applied to the Prop Muscle when this prop is picked up.")]
///
/// The muscle properties that will be applied to the Prop Muscle when this prop is picked up.
///
public Muscle.Props muscleProps;
[Tooltip("If true, this prop's layer will be forced to PuppetMaster layer and target's layer forced to PuppetMaster's Target Root's layer when the prop is picked up.")]
///
/// If true, this prop's layer will be forced to PuppetMaster layer and target's layer forced to PuppetMaster's Target Root's layer when the prop is picked up.
///
public bool forceLayers = true;
[Tooltip("Mass of the prop while picked up. When dropped, mass of the original Rigidbody will be used.")]
///
/// Mass of the prop while picked up. When dropped, mass of the original Rigidbody will be used.
///
public float mass = 1f;
[Tooltip("This has no other purpose but helping you distinguish props by PropMuscle.currentProp.propType.")]
///
/// This has no other purpose but helping you distinguish PropMuscle.currentProp by type.
///
public int propType;
[LargeHeader("Materials")]
[Tooltip("If assigned, sets prop colliders to this PhysicMaterial when picked up. If no material assigned, will maintain the original PhysicMaterial (unless otherwise controlled by BehaviourPuppet's Group Overrides).")]
///
/// If assigned, sets prop colliders to this PhysicMaterial when picked up. If no materials assigned here, will maintain the original PhysicMaterial.
///
public PhysicMaterial pickedUpMaterial;
[LargeHeader("Additional Pin")]
[Tooltip("Adds this to Prop Muscle's 'Additional Pin Offset' when this prop is picked up.")]
///
/// Adds this to Prop Muscle's 'Additional Pin Offset' when this prop is picked up.
///
public Vector3 additionalPinOffsetAdd;
[Tooltip("The pin weight multiplier of the additional pin. Increasing this weight will make the prop follow animation better, but will increase jitter when colliding with objects.")]
///
/// The pin weight of the additional pin. Increasing this weight will make the prop follow animation better, but will increase jitter when colliding with objects.
///
[Range(0f, 1f)] public float additionalPinWeight = 1f;
[Tooltip("Multiplies the mass of the additional pin by this value when this prop is picked up. The Rigidbody on this prop will be destroyed on pick-up and reattached on drop, so its mass is not used while picked up.")]
///
/// Multiplies the mass of the additional pin by this value when this prop is picked up. The Rigidbody on this prop will be destroyed on pick-up and reattached on drop, so its mass is not used while picked up.
///
public float additionalPinMass = 1f;
///
/// Is the prop currently picked up?
///
public bool isPickedUp { get; private set; }
///
/// Returns either the Rigidbody of the prop when it is dropped or the Rigidbody of the prop muscle when it is picked up.
///
public Rigidbody GetRigidbody()
{
if (r != null) return r;
if (isPickedUp) return propMuscle.rigidbody;
return null;
}
public Vector3 inertiaTensor { get; private set; }
public Vector3 localCenterOfMass { get; private set; }
protected virtual void OnPickUp(PuppetMaster puppetMaster, int propMuscleIndex) { }
protected virtual void OnDrop(PuppetMaster puppetMaster, int propMuscleIndex) { }
protected Muscle propMuscle { get; private set; }
private int defaultLayer;
private Transform defaultParent;
private Collider[] colliders = new Collider[0];
private PhysicMaterial[] droppedMaterials = new PhysicMaterial[0];
private Rigidbody r;
private float _mass;
private float _drag;
private float _angularDrag;
private bool _useGravity;
private bool _isKinematic;
private RigidbodyInterpolation _interpolation;
private CollisionDetectionMode _collisionDetectionMode;
private RigidbodyConstraints _constraints;
private Collider[] emptyColliders = new Collider[0];
// Called by PropMuscle when this prop is picked up
public void PickUp(PuppetMaster puppetMaster, int propMuscleIndex)
{
RemoveRigidbody();
transform.parent = puppetMaster.muscles[propMuscleIndex].transform;
transform.position = puppetMaster.muscles[propMuscleIndex].transform.position;
transform.rotation = puppetMaster.muscles[propMuscleIndex].transform.rotation;
meshRoot.parent = puppetMaster.muscles[propMuscleIndex].target;
meshRoot.localPosition = Vector3.zero;
meshRoot.localRotation = Quaternion.identity;
puppetMaster.muscles[propMuscleIndex].props = muscleProps;
if (pickedUpMaterial != null)
{
foreach (Collider c in colliders)
{
c.sharedMaterial = pickedUpMaterial;
}
}
if (forceLayers)
{
foreach (Collider c in colliders)
{
if (!c.isTrigger) c.gameObject.layer = puppetMaster.muscles[propMuscleIndex].joint.gameObject.layer;
}
}
puppetMaster.muscles[propMuscleIndex].colliders = colliders;
puppetMaster.UpdateInternalCollisions(puppetMaster.muscles[propMuscleIndex]);
isPickedUp = true;
propMuscle = puppetMaster.muscles[propMuscleIndex];
OnPickUp(puppetMaster, propMuscleIndex);
}
// Called by PropMuscle when this prop is dropped
public void Drop(PuppetMaster puppetMaster, int propMuscleIndex)
{
if (!puppetMaster.muscles[propMuscleIndex].joint.gameObject.activeInHierarchy)
{
transform.position = puppetMaster.muscles[propMuscleIndex].target.position;
transform.rotation = puppetMaster.muscles[propMuscleIndex].target.rotation;
}
ReattachRigidbody();
if (!puppetMaster.muscles[propMuscleIndex].joint.gameObject.activeInHierarchy || puppetMaster.muscles[propMuscleIndex].rigidbody.isKinematic)
{
r.velocity = puppetMaster.muscles[propMuscleIndex].mappedVelocity;
r.angularVelocity = puppetMaster.muscles[propMuscleIndex].mappedAngularVelocity;
}
transform.parent = defaultParent;
meshRoot.parent = transform;
meshRoot.localPosition = Vector3.zero;
meshRoot.localRotation = Quaternion.identity;
for (int i = 0; i < colliders.Length; i++)
{
colliders[i].sharedMaterial = droppedMaterials[i];
}
puppetMaster.ResetInternalCollisions(puppetMaster.muscles[propMuscleIndex], false);
puppetMaster.muscles[propMuscleIndex].colliders = emptyColliders;
if (forceLayers)
{
foreach (Collider c in colliders)
{
if (!c.isTrigger) c.gameObject.layer = defaultLayer;
}
}
isPickedUp = false;
propMuscle = null;
OnDrop(puppetMaster, propMuscleIndex);
}
protected virtual void Awake()
{
r = GetComponent();
defaultParent = transform.parent;
colliders = GetComponentsInChildren();
droppedMaterials = new PhysicMaterial[colliders.Length];
for (int i = 0; i < colliders.Length; i++)
{
droppedMaterials[i] = colliders[i].sharedMaterial;
}
}
protected virtual void Start()
{
muscleProps.group = Muscle.Group.Prop;
if (meshRoot == null)
{
Debug.LogError("PuppetMasterProp does not have a 'Mesh Root' Transform assigned.", transform);
enabled = false;
return;
}
if (meshRoot == transform)
{
Debug.LogError("PuppetMasterProp's 'Mesh Root' can not be the PuppetMasterProp's own Transform.", transform);
enabled = false;
return;
}
defaultLayer = gameObject.layer;
foreach (Collider c in colliders)
{
if (!c.isTrigger)
{
defaultLayer = c.gameObject.layer;
break;
}
}
}
protected virtual void Update()
{
if (isPickedUp)
{
transform.localPosition = Vector3.zero;
transform.localRotation = Quaternion.identity;
}
}
private void RemoveRigidbody()
{
if (r == null) return;
inertiaTensor = r.inertiaTensor;
localCenterOfMass = r.centerOfMass;
_mass = r.mass;
_drag = r.drag;
_angularDrag = r.angularDrag;
_useGravity = r.useGravity;
_isKinematic = r.isKinematic;
_interpolation = r.interpolation;
_collisionDetectionMode = r.collisionDetectionMode;
_constraints = r.constraints;
Destroy(r);
}
private void ReattachRigidbody()
{
if (r != null) return;
r = gameObject.AddComponent();
r.mass = _mass;
r.drag = _drag;
r.angularDrag = _angularDrag;
r.useGravity = _useGravity;
r.isKinematic = _isKinematic;
r.interpolation = _interpolation;
r.collisionDetectionMode = _collisionDetectionMode;
r.constraints = _constraints;
}
void OnDrawGizmosSelected()
{
if (Application.isPlaying) return;
if (muscleProps != null) muscleProps.group = Muscle.Group.Prop;
if (meshRoot != null && meshRoot != transform)
{
meshRoot.parent = transform;
meshRoot.position = transform.position;
meshRoot.rotation = transform.rotation;
}
}
}
}