public static long AddRopeData(MyRopeData publicData, long ropeId) { if (ropeId == 0) ropeId = MyEntityIdentifier.AllocateId(); // Avoid referencing external objects during addition. They might not have been created yet. var ropeData = new InternalRopeData { Public = publicData, RopeId = ropeId, }; Debug.Assert(!m_hookIdToRopeId.ContainsKey(ropeData.Public.HookEntityIdA), "Hook already has rope attached!"); Debug.Assert(!m_hookIdToRopeId.ContainsKey(ropeData.Public.HookEntityIdB), "Hook already has rope attached!"); Debug.Assert(!m_ropeIdToRope.ContainsKey(ropeData.RopeId), "Rope with given ID already exists!"); m_ropeIdToRope[ropeData.RopeId] = ropeData; m_hookIdToRopeId[ropeData.Public.HookEntityIdA] = ropeId; m_hookIdToRopeId[ropeData.Public.HookEntityIdB] = ropeId; if (ropeData.Public.Definition.EnableRayCastRelease && Sync.IsServer) { m_ropeIdToRayCastRelease.Add(ropeId, ropeData); } m_ropeIdToInit.Add(ropeId); return ropeId; }
private static Vector3 ComputeTorqueFromRopeImpulse(WindingData windingData, InternalRopeData ropeData, Vector3 ropeDirectionVector, Vector3 centerDelta) { /* * /R = rope direction vector (unit length, world space) * /A = drum axis (unit length, world space) * /r = displacement vector for torque application (world space) from center of mass * /tau = torque applied * /C_d = center delta (center of winding (world space) - center of mass (world space)) * /F = force * r = drum radius * I = impulse applied * * /r = |/R x /A| * r + C_d * /F = /R * -I * /tau = /r x /F */ Vector3 A, r, F, tau; Vector3.Normalize(ref ropeDirectionVector, out ropeDirectionVector); A = windingData.CurrentDummyWorld.Backward; Vector3.Cross(ref ropeDirectionVector, ref A, out r); r = r * windingData.Radius + centerDelta; F = ropeDirectionVector * ropeData.ImpulseApplied; Vector3.Cross(ref r, ref F, out tau); return tau; }
private static void ApplyRopeLimits(InternalRopeData ropeData, RopeDrumLimits limits = null) { if (limits == null) m_hookIdToRopeLimits.TryGetValue(ropeData.Public.HookEntityIdA, out limits); if (limits == null) m_hookIdToRopeLimits.TryGetValue(ropeData.Public.HookEntityIdB, out limits); if (limits != null) { Debug.Assert( m_hookIdToRopeLimits.ContainsKey(ropeData.Public.HookEntityIdA) ^ m_hookIdToRopeLimits.ContainsKey(ropeData.Public.HookEntityIdB), "Rope should only be connected to one drum with rope limits."); ropeData.Public.MinRopeLength = limits.MinLength; ropeData.Public.MaxRopeLength = limits.MaxLength; WindingData winding; float newLength; if (m_hookIdToWinding.TryGetValue(ropeData.Public.HookEntityIdA, out winding) && winding.IsUnlocked) newLength = limits.MaxLength; else if (m_hookIdToWinding.TryGetValue(ropeData.Public.HookEntityIdB, out winding) && winding.IsUnlocked) newLength = limits.MaxLength; else newLength = MathHelper.Clamp(ropeData.Public.CurrentRopeLength, limits.MinLength, limits.MaxLength); ropeData.Public.CurrentRopeLength = newLength; if (ropeData.ConstraintData != null) { // Would be nice if I could leave this up to the normal update by changing only target rope length. // But target rope length is limited to only certain delta in actual length per update. ropeData.ConstraintData.LinearLimit = newLength; ropeData.Constraint.RigidBodyA.Activate(); ropeData.Constraint.RigidBodyB.Activate(); } } ropeData.TargetRopeLength = ropeData.Public.CurrentRopeLength; }
private static void RemoveConstraint(InternalRopeData ropeData) { if (ropeData.Constraint == null) return; if (ropeData.Constraint.RigidBodyA != null) ropeData.Constraint.RigidBodyA.Activate(); if (ropeData.Constraint.RigidBodyB != null) ropeData.Constraint.RigidBodyB.Activate(); var physics = ropeData.GridA.Physics; if (physics != null) physics.RemoveConstraint(ropeData.Constraint); if (!ropeData.Constraint.IsDisposed) ropeData.Constraint.Dispose(); ropeData.Constraint = null; // HkConstraint deletes constraint data as well. Is this correct? (prevents sharing // constraint data, as each instance reduces reference count on data by 2 on dispose!) ropeData.ConstraintData = null; MyCubeGrid.BreakGridGroupLink(GridLinkTypeEnum.Physical, ropeData.RopeId, ropeData.GridA, ropeData.GridB); }
private static void CreateConstraint(InternalRopeData ropeData, HookData hookA, HookData hookB, MyCubeBlock blockA, MyCubeBlock blockB) { if (ropeData.GridA == ropeData.GridB) return; var physicsA = blockA.CubeGrid.Physics; var physicsB = blockB.CubeGrid.Physics; if (physicsA == null || physicsB == null || !physicsA.RigidBody.IsAddedToWorld || !physicsB.RigidBody.IsAddedToWorld) return; Vector3D posA, posB; ComputeLocalPosition(blockA, hookA, out posA); ComputeLocalPosition(blockB, hookB, out posB); ropeData.ConstraintData = new HkRopeConstraintData(); { Vector3 posAf = (Vector3)posA; Vector3 posBf = (Vector3)posB; ropeData.ConstraintData.SetInBodySpace( posAf, posBf, physicsA, physicsB); } posA = Vector3D.Transform(posA, physicsA.GetWorldMatrix()); posB = Vector3D.Transform(posB, physicsB.GetWorldMatrix()); ropeData.ConstraintData.LinearLimit = ropeData.Public.CurrentRopeLength; ropeData.ConstraintData.Strength = 0.6f; ropeData.Constraint = new HkConstraint(physicsA.RigidBody, physicsB.RigidBody, ropeData.ConstraintData); physicsA.AddConstraint(ropeData.Constraint); ropeData.Constraint.Enabled = true; ropeData.ConstraintData.Update(ropeData.Constraint); MyCubeGrid.CreateGridGroupLink(GridLinkTypeEnum.Physical, ropeData.RopeId, blockA.CubeGrid, blockB.CubeGrid); physicsA.RigidBody.Activate(); physicsB.RigidBody.Activate(); }
private static void CreateConstraint(InternalRopeData ropeData) { CreateConstraint(ropeData, m_hookIdToHook[ropeData.Public.HookEntityIdA], m_hookIdToHook[ropeData.Public.HookEntityIdB], (MyCubeBlock)MyEntities.GetEntityById(ropeData.Public.HookEntityIdA), (MyCubeBlock)MyEntities.GetEntityById(ropeData.Public.HookEntityIdB)); }