public static AttachNodeSim New(PartSim partSim, String newId, AttachNode.NodeType newNodeType) { AttachNodeSim nodeSim = pool.Borrow(); nodeSim.attachedPartSim = partSim; nodeSim.nodeType = newNodeType; nodeSim.id = newId; return(nodeSim); }
public AttachedPartInfo(AnimatedAttachment animatedAttachment, Part attachedPart) { this.animatedAttachment = animatedAttachment; this.attachedPart = attachedPart; AttachNode.NodeType nodeType = AttachNode.NodeType.Stack; if (attachedPart && attachedPart.srfAttachNode.attachedPart) { nodeType = AttachNode.NodeType.Surface; } this.nodeType = nodeType; }
internal void Load(int index, ConfigNode root) { ConfigNode attachNodeInfo = root.GetNode("ATTACH_NODE_INFO", index); if (attachNodeInfo == null) { printf("Failed to find ATTACH_NODE_INFO!"); return; } loaded = true; if (!attachNodeInfo.HasNode("POS_ROT")) { printf("Failed to find POS_ROT!"); return; } //string attachedPartName = attachNodeInfo.GetValue("attachedPart"); string colliderName = attachNodeInfo.GetValue("colliderName"); Collider[] colliders = animatedAttachment.part.GetPartColliders(); foreach (Collider collider in colliders) { if (collider.name == colliderName) { this.collider = collider; } } nodeType = (AttachNode.NodeType)Enum.Parse(typeof(AttachNode.NodeType), attachNodeInfo.GetValue("nodeType")); if (attachedPartOffset == null) { attachedPartOffset = new PosRot(); } attachedPartOffset.Load(attachNodeInfo, "offset"); }
public void UpdateAttachments(State flightState, bool debug, bool debugPeriodic) { // If the is no actual part attached to the attach node, then we can bail out. // Part attachedPart = GetAttachedPart(); if (debugPeriodic) { printf("UA: %s %s %s %s", attachedPart != null ? attachedPart.name : null, nodeType, stackAttachNode != null ? stackAttachNode.id : "null", stackAttachNode != null ? stackAttachNode.attachedPartId.ToString() : "null"); } // We don't want to mess with the joint attaching this part to its parent. // Also, take of the special case where they are both null, otherwise we // will incorrectly get a match between them, resulting in loss of function // if the animated part is the root part. if ((attachedPart == animatedAttachment.part.parent) && (attachedPart != null)) { if (debugPeriodic) { printf("Skipping parent"); } return; } switch (nodeType) { case AttachNode.NodeType.Surface: if (collider == null) { SetCollider(); if (debug) { printf("Setting collider to %s", collider.name); } } break; case AttachNode.NodeType.Stack: if (stackAttachNode == null) { stackAttachNode = animatedAttachment.part.FindAttachNodeByPart(attachedPart); // Sometimes life throws lemons at you, like when the user actvated attachments in flight if (stackAttachNode == null) { // Try again as surface attached nodeType = AttachNode.NodeType.Surface; return; } if (debug) { printf("Setting attach node to %s", stackAttachNode.id); } } break; } Transform referenceTransform = GetReferenceTransform(); // If this attach node is defined in the cfg, then bail out now, it will not be movable if (referenceTransform == null) { if (debugPeriodic) { printf("Skipping cfg based node: %s", stackAttachNode.id); } return; } // Get the position and rotation of the node transform relative to the part. // The nodeTransform itself will only contain its positions and rotation // relative to the immediate parent in the model PosRot referencePosRot = PosRot.GetPosRot(referenceTransform, animatedAttachment.part); // We can't animate decoupling shrouds if (referencePosRot == null) { if (debugPeriodic) { printf("Skipping decoupler shroud"); } return; } bool active = animatedAttachment.activated; if (EditorLogic.fetch && (EditorLogic.fetch.EditorConstructionMode != ConstructionMode.Place)) { active = false; } // Take note of newly attached parts, including at initial ship load if (attachedPart == null || !active) { if (debugPeriodic) { if (attachedPart == null) { printf("No part attached"); } } attachedPartOffset = null; return; } if (attachedPartOffset == null || attachedPartOriginal == null) { // Get attached part position relative to this part PosRot localPosRot = new PosRot(); Transform parent = attachedPart.transform.parent; // Let the engine calculate the local position instead of doing the calculation ourselves.. attachedPart.transform.parent = animatedAttachment.part.transform; localPosRot.position = attachedPart.transform.localPosition; localPosRot.rotation = attachedPart.transform.localRotation; attachedPart.transform.parent = parent; // We could do parenting trick for this too, but seems we loose the scaling if (attachedPartOffset == null) { printf("Recording attachedPartOffset"); attachedPartOffset = new PosRot(); attachedPartOffset.rotation = referencePosRot.rotation.Inverse() * localPosRot.rotation; attachedPartOffset.position = referencePosRot.rotation.Inverse() * (localPosRot.position - referencePosRot.position); } if (attachedPartOriginal == null) { printf("Recording attachedPartOriginal"); attachedPartOriginal = new PosRot(); attachedPartOriginal.rotation = localPosRot.rotation; } } // Calculate the attached parts position in the frame of reference of this part PosRot attachedPartPosRot = new PosRot { rotation = referencePosRot.rotation * attachedPartOffset.rotation, position = referencePosRot.position + referencePosRot.rotation * attachedPartOffset.position }; /* A sub part can either be connected directly by their transform having a parent transform, * or be connected through a joint. In the first case, the sub part will directly move with * their parent as their position is in in the reference frame of the parent local space. * In the latter case, the sub part lacks a parent transform, and the position is in the vessel * space instead, and parts are held together by forces working through the joints. * The first case occurs in two situations. In the VAB editor, all parts are connected by * parent transforms. And, during flight, a physicsless part will also be connected to the parent * this way - for example some science parts. * Joints are used for normal physics based parts during flight. */ if (attachedPart.transform.parent != null) { // If a parent was found, we will just update the position of the part directly since no physics is involved attachedPart.transform.localRotation = attachedPartPosRot.rotation; attachedPart.transform.localPosition = attachedPartPosRot.position; if (debugPeriodic) { printf("Updated pos without physics"); } // There is nothing more to do, so bail out return; } // In the editor, while changing action groups, the parent will be null for some reason. // We can catch that here by making sure there exists a joint if (attachedPart.attachJoint == null) { if (debugPeriodic) { printf("No attach joint found"); } return; } // Things get tricker if the parts are connected by joints. We need to setup the joint // to apply forces to the sub part. ConfigurableJoint joint = attachedPart.attachJoint.Joint; // It is not possible to change values of a JointDrive after creation, so we must create a // new one and apply it to the joint. Seems we can't only create it at startup either. switch (joint.name) { case "AnimatedAttachment": if (joint.xMotion != ConfigurableJointMotion.Free && flightState == State.STARTED) { animatedAttachment.initJointDrive = true; } break; case "MechanicsToolkit": break; default: animatedAttachment.initJointDrive = true; break; } if (animatedAttachment.initJointDrive) { animatedAttachment.initJointDrive = false; joint.name = "AnimatedAttachment"; jointDrive = new JointDrive(); printf("Creating a new drive mode. Previous: %s, %s, %s, %s, %s", joint.name, joint.xDrive.positionSpring, animatedAttachment.part.name, animatedAttachment.part.started, joint.angularXMotion); /* * printf(string.Format("maximumForce: {0}", animatedAttachment.maximumForce)); * printf(string.Format("positionDamper: {0}", animatedAttachment.positionDamper)); * printf(string.Format("positionSpring: {0}", animatedAttachment.positionSpring)); */ // The joint will not respond to changes to targetRotation/Position in locked mode, // so change it to free in all directions joint.xMotion = ConfigurableJointMotion.Free; joint.yMotion = ConfigurableJointMotion.Free; joint.zMotion = ConfigurableJointMotion.Free; joint.angularXMotion = ConfigurableJointMotion.Free; joint.angularYMotion = ConfigurableJointMotion.Free; joint.angularZMotion = ConfigurableJointMotion.Free; // Create a new joint with settings from the cfg file or user selection jointDrive.maximumForce = animatedAttachment.maximumForce; jointDrive.positionDamper = animatedAttachment.positionDamper; jointDrive.positionSpring = animatedAttachment.positionSpring; // Same drive in all directions.. is there benefits of separating them? joint.angularXDrive = jointDrive; joint.angularYZDrive = jointDrive; joint.xDrive = jointDrive; joint.yDrive = jointDrive; joint.zDrive = jointDrive; //} if (debug) { printf("%s", joint); } } if (debug) { printf("%s", attachedPartPosRot); } if (debug) { printf("%s", attachedPartOriginal); } // Update the joint.targetRotation using this convenience function, since the joint // reference frame has weird axes. Arguments are current and original rotation. joint.SetTargetRotationLocal( attachedPartPosRot.rotation, attachedPartOriginal.rotation); /* Move the attached part by updating the connectedAnchor instead of the joint.targetPosition. * This is easier since the anchor is in the reference frame of this part, and we already have the * position in that reference frame. It also makes sense from the view that since it really is the * attachment point of the attached part that is moving. There might be benefits of using the targetPosition * though, and should be possible to calculate it fairly easily if needed. */ joint.connectedAnchor = referencePosRot.position; // Make sure the target position is zero joint.targetPosition = Vector3.zero; // This scaling and rotation is to convert to joint space... maybe? // Determined by random tinkering and is magical as far as I am concerned joint.anchor = attachedPartOffset.rotation.Inverse() * Vector3.Scale( new Vector3(-1, -1, -1), attachedPartOffset.position); if (debugPeriodic) { printf("%s; %s; %s -> %s; %s -> %s; %s", referencePosRot, attachedPartPosRot, attachedPartOffset, attachedPartOriginal.rotation.eulerAngles, joint.targetRotation.eulerAngles, joint.anchor, joint.connectedAnchor ); } // Debug info if (debug) { // Show debug vectors for the child part if (axisJoint == null) { axisJoint = new AxisInfo(joint.transform); } if (lineAnchor == null) { lineAnchor = new LineInfo(animatedAttachment.part.transform, Color.cyan); } lineAnchor.Update(Vector3.zero, joint.connectedAnchor); if (lineNodeToPart == null) { lineNodeToPart = new LineInfo(animatedAttachment.part.transform, Color.magenta); } lineNodeToPart.Update( referencePosRot.position, attachedPartPosRot.position); } else { if (axisJoint != null) { axisJoint = null; } } // Debug info if (debug) { // Show debug vectors for the attachNodes if (orientationAttachNode == null) { orientationAttachNode = new OrientationInfo(animatedAttachment.part.transform, referencePosRot.position, referencePosRot.position + attachedPartOffset.orientation); } if (stackAttachNode != null) { orientationAttachNode.Update(referencePosRot.position, referencePosRot.position + stackAttachNode.orientation); } } else { if (orientationAttachNode != null) { orientationAttachNode = null; } } }
public AttachNodeSim(PartSim partSim, String newId, AttachNode.NodeType newNodeType) { attachedPartSim = partSim; nodeType = newNodeType; id = newId; }