using System; using Unity.Collections; using Unity.Entities; using Unity.Mathematics; using UnityEngine; namespace Unity.Physics.Authoring { [BakingType] public struct JointEntityBaking : IComponentData { public Entity Entity; } public class BallAndSocketJoint : BaseJoint { // Editor only settings [HideInInspector] public bool EditPivots; [Tooltip("If checked, PositionLocal will snap to match PositionInConnectedEntity")] public bool AutoSetConnected = true; public float3 PositionLocal; public float3 PositionInConnectedEntity; public virtual void UpdateAuto() { if (AutoSetConnected) { RigidTransform bFromA = math.mul(math.inverse(worldFromB), worldFromA); PositionInConnectedEntity = math.transform(bFromA, PositionLocal); } } } public abstract class JointBaker : Baker where T : BaseJoint { protected PhysicsConstrainedBodyPair GetConstrainedBodyPair(BaseJoint authoring) { return new PhysicsConstrainedBodyPair( GetEntity(TransformUsageFlags.Dynamic), authoring.ConnectedBody == null ? Entity.Null : GetEntity(authoring.ConnectedBody, TransformUsageFlags.Dynamic), authoring.EnableCollision ); } public Entity CreateJointEntity(uint worldIndex, PhysicsConstrainedBodyPair constrainedBodyPair, PhysicsJoint joint) { using (var joints = new NativeArray(1, Allocator.Temp) { [0] = joint }) using (var jointEntities = new NativeList(1, Allocator.Temp)) { CreateJointEntities(worldIndex, constrainedBodyPair, joints, jointEntities); return jointEntities[0]; } } public uint GetWorldIndex(Component c) { uint worldIndex = 0; if (c) { var physicsBody = GetComponent(c); if (physicsBody != null) { worldIndex = physicsBody.WorldIndex; } } return worldIndex; } public uint GetWorldIndexFromBaseJoint(BaseJoint authoring) { var physicsBody = GetComponent(authoring); uint worldIndex = physicsBody.WorldIndex; if (authoring.ConnectedBody == null) { return worldIndex; } var connectedBody = GetComponent(authoring.ConnectedBody); if (connectedBody != null) { Assertions.Assert.AreEqual(worldIndex, connectedBody.WorldIndex); } return worldIndex; } public void CreateJointEntities(uint worldIndex, PhysicsConstrainedBodyPair constrainedBodyPair, NativeArray joints, NativeList newJointEntities) { if (!joints.IsCreated || joints.Length == 0) return; if (newJointEntities.IsCreated) newJointEntities.Clear(); else newJointEntities = new NativeList(joints.Length, Allocator.Temp); // create all new joints var multipleJoints = joints.Length > 1; var entity = GetEntity(TransformUsageFlags.Dynamic); for (var i = 0; i < joints.Length; ++i) { var jointEntity = CreateAdditionalEntity(TransformUsageFlags.Dynamic); AddSharedComponent(jointEntity, new PhysicsWorldIndex(worldIndex)); AddComponent(jointEntity, constrainedBodyPair); AddComponent(jointEntity, joints[i]); newJointEntities.Add(jointEntity); if (GetComponent() != null) { AddComponent(jointEntity, new JointEntityBaking() { Entity = entity }); AddSharedComponentManaged(jointEntity, new ModifyJointLimits()); } } if (multipleJoints) { // set companion buffers for new joints for (var i = 0; i < joints.Length; ++i) { var companions = AddBuffer(newJointEntities[i]); for (var j = 0; j < joints.Length; ++j) { if (i == j) continue; companions.Add(new PhysicsJointCompanion {JointEntity = newJointEntities[j]}); } } } } } class BallAndSocketJointBaker : JointBaker { public override void Bake(BallAndSocketJoint authoring) { authoring.UpdateAuto(); var physicsJoint = PhysicsJoint.CreateBallAndSocket(authoring.PositionLocal, authoring.PositionInConnectedEntity); physicsJoint.SetImpulseEventThresholdAllConstraints(authoring.MaxImpulse); var constraintBodyPair = GetConstrainedBodyPair(authoring); uint worldIndex = GetWorldIndexFromBaseJoint(authoring); CreateJointEntity(worldIndex, constraintBodyPair, physicsJoint); } } }