Exemplo n.º 1
0
        /// <summary>Promotes the specified object into a physical connector object.</summary>
        /// <remarks>
        /// The physics will immediately start on the object. If it doesn't have a rigidbody, the one will
        /// be created.
        /// </remarks>
        /// <param name="ownerModule">The part's module which will control the connector.</param>
        /// <param name="obj">The object to be promoted.</param>
        /// <param name = "interactionDistance"></param>
        public static KASInternalPhysicalConnector Promote(
            PartModule ownerModule, GameObject obj, float interactionDistance = 0)
        {
            var connectorRb = obj.GetComponent <Rigidbody>() ?? obj.AddComponent <Rigidbody>();

            connectorRb.useGravity      = false;
            connectorRb.isKinematic     = ownerModule.part.packed;
            connectorRb.velocity        = ownerModule.part.rb.velocity;
            connectorRb.angularVelocity = ownerModule.part.rb.angularVelocity;
            connectorRb.ResetInertiaTensor();
            connectorRb.ResetCenterOfMass();
            var connectorModule = obj.AddComponent <KASInternalPhysicalConnector>();

            connectorModule.ownerModule = ownerModule;

            // Create the interaction collider if requested.
            if (interactionDistance > 0)
            {
                // This mesh is placed on a special layer which is not rendered in the game. It's only
                // used to detect the special zones triggers, so keep it simple.
                var interactionTriggerObj = Meshes2.CreatePrimitive(
                    PrimitiveType.Cube, Vector3.one, null, obj.transform);
                interactionTriggerObj.name = InteractionAreaCollider;
                var collider = interactionTriggerObj.AddComponent <SphereCollider>();
                collider.isTrigger                     = true;
                collider.radius                        = interactionDistance;
                interactionTriggerObj.layer            = (int)KspLayer.TriggerCollider;
                connectorModule._interactionTriggerObj = interactionTriggerObj;
            }

            return(connectorModule);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Creates a mesh that represents the connecting pipe between the source and the target.
        /// </summary>
        /// <remarks>It's only called in the started state.</remarks>
        /// <seealso cref="CreatePipeMesh"/>
        /// <seealso cref="pipeTransform"/>
        protected virtual void CreateLinkPipe()
        {
            var colliderType = pipeColliderIsPhysical
        ? Colliders.PrimitiveCollider.Shape
        : Colliders.PrimitiveCollider.None;

            pipeTransform = Meshes2.CreateCylinder(
                pipeDiameter, 1.0f, pipeMaterial, sourceTransform, colliderType: colliderType).transform;
            pipeTransform.GetComponent <Renderer>().sharedMaterial = pipeMaterial;
            pipeMeshRenderer = pipeTransform.GetComponent <Renderer>(); // To speedup OnUpdate() handling.
            SetupPipe(sourceJointNode.pipeAttach, targetJointNode.pipeAttach);
            var extraScale = 1.0f;

            if (pipeTextureRescaleMode == PipeTextureRescaleMode.Stretch)
            {
                extraScale /=
                    (sourceJointNode.pipeAttach.position - targetJointNode.pipeAttach.position).magnitude;
            }
            RescalePipeTexture(
                pipeTransform, pipeTransform.localScale.z * extraScale, renderer: pipeMeshRenderer);
        }
Exemplo n.º 3
0
        /// <summary>Builds a model for the joint end basing on the configuration.</summary>
        /// <param name="node">The node to setup.</param>
        /// <param name="alignTo">
        /// The object to align the connector to. If it's <c>null</c>, then the model will be parked.
        /// </param>
        // ReSharper disable once VirtualMemberNeverOverridden.Global
        protected virtual void UpdateJointNode(ModelPipeEndNode node, Transform alignTo)
        {
            var config = node.config;
            var makeProceduralModels = alignTo != null || !config.parkPrefabOnly;

            // Return the models back to the owner part to make the search working properly.
            if (node.rootModel != null)
            {
                node.AlignToTransform(null);
            }

            node.parkRootObject = partModelTransform;

            // Create basic setup.
            var nodeName = modelBasename + "-pipeNode" + node.name;

            node.rootModel = partModelTransform.Find(nodeName)
                             ?? new GameObject(nodeName).transform;
            node.rootModel.parent = partModelTransform;
            node.partAttach       = node.rootModel.Find(PartJointTransformName)
                                    ?? new GameObject(PartJointTransformName).transform;
            Hierarchy.MoveToParent(node.partAttach, node.rootModel,
                                   newPosition: Vector3.zero,
                                   newRotation: Quaternion.LookRotation(Vector3.back));
            node.pipeAttach = node.rootModel.Find(PipeJointTransformName)
                              ?? new GameObject(PipeJointTransformName).transform;
            Hierarchy.MoveToParent(node.pipeAttach, node.rootModel,
                                   newPosition: Vector3.zero,
                                   newRotation: Quaternion.LookRotation(Vector3.forward));

            // Add a pipe attachment sphere if set.
            const string sphereName = "pipeSphere";
            var          sphere     = node.pipeAttach.Find(sphereName);

            if (config.sphereDiameter > float.Epsilon && makeProceduralModels)
            {
                if (sphere == null)
                {
                    sphere = Meshes2.CreateSphere(config.sphereDiameter, pipeMaterial, node.pipeAttach,
                                                  colliderType: Colliders.PrimitiveCollider.Shape).transform;
                    sphere.name     = sphereName;
                    sphere.rotation = Quaternion.LookRotation(node.partAttach.up, node.partAttach.forward);
                }
                sphere.GetComponent <Renderer>().sharedMaterial = pipeMaterial; // For performance.
                RescalePipeTexture(sphere, sphere.localScale.z * config.sphereDiameter * 2.0f);
            }
            else if (sphere != null)
            {
                Hierarchy2.SafeDestroy(sphere);
            }

            // Parking position, if defined.
            var parkObjectName = modelBasename + "-park" + node.name;
            var parkAttach     = partModelTransform.Find(parkObjectName);

            if (config.parkAttachAt != null)
            {
                node.parkAttach = parkAttach
          ? parkAttach
          : new GameObject(parkObjectName).transform;
                Hierarchy.MoveToParent(node.parkAttach, partModelTransform,
                                       newPosition: config.parkAttachAt.pos,
                                       newRotation: config.parkAttachAt.rot);
            }
            else if (parkAttach != null)
            {
                Hierarchy2.SafeDestroy(parkAttach);
            }

            // Place prefab between the part and the pipe if specified.
            if (!string.IsNullOrEmpty(config.modelPath))
            {
                // The prefab model can move to the part's model, so make a unique name for it.
                const string prefabName  = "prefabConnector";
                var          prefabModel = node.rootModel.Find(prefabName)
                                           ?? Hierarchy.FindTransformByPath(partModelTransform, config.modelPath);
                if (prefabModel != null)
                {
                    prefabModel.gameObject.SetActive(true);
                    prefabModel.name         = prefabName;
                    prefabModel.parent       = node.rootModel;
                    prefabModel.rotation     = node.partAttach.rotation * config.modelPartAttachAt.rot.Inverse();
                    prefabModel.position     = node.partAttach.TransformPoint(config.modelPartAttachAt.pos);
                    node.pipeAttach.rotation = prefabModel.rotation * config.modelPipeAttachAt.rot;
                    node.pipeAttach.position = prefabModel.TransformPoint(config.modelPipeAttachAt.pos);
                }
                else
                {
                    HostedDebugLog.Error(this, "Cannot find prefab model: {0}", config.modelPath);
                }
            }

            // The offset is intended for the sphere/arm models only.
            if (makeProceduralModels)
            {
                node.pipeAttach.localPosition += new Vector3(0, 0, config.sphereOffset);
            }

            // Add arm pipe.
            const string armName = "sphereArm";
            var          arm     = node.pipeAttach.Find(armName);

            if (config.armDiameter > float.Epsilon && config.sphereOffset > float.Epsilon &&
                makeProceduralModels)
            {
                if (arm == null)
                {
                    arm = Meshes2.CreateCylinder(config.armDiameter, config.sphereOffset, pipeMaterial,
                                                 node.pipeAttach,
                                                 colliderType: Colliders.PrimitiveCollider.Shape).transform;
                    arm.name = armName;
                }
                arm.GetComponent <Renderer>().sharedMaterial = pipeMaterial; // For performance.
                var armTransform = arm.transform;
                armTransform.localPosition = new Vector3(0, 0, -config.sphereOffset / 2);
                armTransform.localRotation = Quaternion.LookRotation(Vector3.forward);
                RescalePipeTexture(armTransform, arm.localScale.z * config.sphereOffset);
            }
            else if (arm != null)
            {
                Hierarchy2.SafeDestroy(arm);
            }

            // Adjust to the new target.
            node.AlignToTransform(alignTo);
        }