public void RebuildCritterFromGenomeRecursive(bool physicsOn, bool useSegments, float variableMass, bool editor) { //Debug.Log("RebuildCritterFromGenomeRecursive: " + physicsOn.ToString() + ", " + useSegments.ToString() + ", " + variableMass.ToString() + ", " + editor.ToString()); BoundingBoxMinCorner = Vector3.zero; BoundingBoxMaxCorner = Vector3.zero; // IMPROVE THIS SO IT WORKS FOR BOTH CritterConstructer AND Trainer if (!editor) masterCritterGenome.PreBuildCritter(variableMass); // Delete existing Segment GameObjects if(!useSegments || editor) DeleteSegments(); // Is this the best way to clear the lists? from a memory standpoint... segaddonPhysicalAttributesList.Clear(); segaddonJointAngleSensorList.Clear(); segaddonContactSensorList.Clear(); segaddonRaycastSensorList.Clear(); segaddonCompassSensor1DList.Clear(); segaddonCompassSensor3DList.Clear(); segaddonPositionSensor1DList.Clear(); segaddonPositionSensor3DList.Clear(); segaddonRotationSensor1DList.Clear(); segaddonRotationSensor3DList.Clear(); segaddonVelocitySensor1DList.Clear(); segaddonVelocitySensor3DList.Clear(); segaddonAltimeterList.Clear(); segaddonEarBasicList.Clear(); segaddonGravitySensorList.Clear(); segaddonOscillatorInputList.Clear(); segaddonValueInputList.Clear(); segaddonTimerInputList.Clear(); segaddonJointMotorList.Clear(); segaddonThrusterEffector1DList.Clear(); segaddonThrusterEffector3DList.Clear(); segaddonTorqueEffector1DList.Clear(); segaddonTorqueEffector3DList.Clear(); segaddonMouthBasicList.Clear(); segaddonNoiseMakerBasicList.Clear(); segaddonStickyList.Clear(); segaddonWeaponBasicList.Clear(); InitializeSegmentMaterial(); if (critterSegmentList != null) { critterSegmentList.Clear(); } if(inputChannelsList != null) { inputChannelsList.Clear(); } else { inputChannelsList = new List<BrainInputChannel>(); } if (outputChannelsList != null) { outputChannelsList.Clear(); } else { outputChannelsList = new List<BrainOutputChannel>(); } // interpret Genome and construct critter in its bind pose bool isPendingChildren = true; int currentDepth = 0; // start with RootNode int maxDepth = 20; // safeguard to prevent while loop lock int nextSegmentID = 0; float critterTotalVolume = 0f; List<CritterSegment> builtSegmentsList = new List<CritterSegment>(); // keep track of segments that have been built - linear in-order array 0-n segments List<BuildSegmentInfo> currentBuildSegmentList = new List<BuildSegmentInfo>(); // keeps track of all current-depth segment build-requests, and holds important metadata List<BuildSegmentInfo> nextBuildSegmentList = new List<BuildSegmentInfo>(); // used to keep track of next childSegments that need to be built // *********** Will attempt to traverse the Segments to be created, keeping track of where on each graph (nodes# & segment#) the current build is on. BuildSegmentInfo rootSegmentBuildInfo = new BuildSegmentInfo(); rootSegmentBuildInfo.sourceNode = masterCritterGenome.CritterNodeList[0]; currentBuildSegmentList.Add(rootSegmentBuildInfo); // ROOT NODE IS SPECIAL! // Do a Breadth-first traversal?? while (isPendingChildren) { //int numberOfChildNodes = masterCritterGenome.CritterNodeList[currentNode].attachedJointLinkList.Count; for (int i = 0; i < currentBuildSegmentList.Count; i++) { //Debug.Log("currentDepth: " + currentDepth.ToString() + "builtNodesQueue.Count: " + builtSegmentsList.Count.ToString() + ", pendingNodes: " + currentBuildSegmentList.Count.ToString() + ", i: " + i.ToString()); // Iterate through pending nodes // Build current node --> Segment GameObject newGO = new GameObject("Node" + nextSegmentID.ToString()); CritterSegment newSegment = newGO.AddComponent<CritterSegment>(); builtSegmentsList.Add(newSegment); newGO.layer = LayerMask.NameToLayer("editorSegment"); ; // set segmentGO layer to editorSegment, to distinguish it from Gizmos newGO.transform.SetParent(this.gameObject.transform); if (useSegments) { newGO.GetComponent<MeshRenderer>().material = critterSegmentMaterial; newGO.GetComponent<MeshRenderer>().material.SetFloat("_DisplayTarget", 0f); newGO.GetComponent<MeshRenderer>().material.SetFloat("_Selected", 0f); newGO.AddComponent<BoxCollider>().isTrigger = false; critterSegmentList.Add(newGO); // Add to master Linear list of Segments } else { newGO.SetActive(false); } newSegment.InitGamePiece(); // create the mesh and some other initialization stuff newSegment.sourceNode = currentBuildSegmentList[i].sourceNode; newSegment.id = nextSegmentID; nextSegmentID++; if (currentBuildSegmentList[i].sourceNode.ID == 0) { // is ROOT segment -- Look into doing Root build BEFORE for loop to avoid the need to do this check newGO.transform.position = masterCritterGenome.centerOfMassOffset; newGO.transform.rotation = Quaternion.identity; newSegment.scalingFactor = newSegment.sourceNode.jointLink.recursionScalingFactor; newGO.transform.localScale = currentBuildSegmentList[i].sourceNode.dimensions * newSegment.scalingFactor; critterTotalVolume += newGO.transform.localScale.x * newGO.transform.localScale.y * newGO.transform.localScale.z; newSegment.surfaceArea = new Vector3(newGO.transform.localScale.y * newGO.transform.localScale.z * 2f, newGO.transform.localScale.x * newGO.transform.localScale.z * 2f, newGO.transform.localScale.x * newGO.transform.localScale.y * 2f); } else { // if NOT root segment, can consider parent-related stuff: newSegment.parentSegment = currentBuildSegmentList[i].parentSegment; // Inherit Axis-Inversions from parent segment: newSegment.mirrorX = newSegment.parentSegment.mirrorX; newSegment.mirrorY = newSegment.parentSegment.mirrorY; newSegment.mirrorZ = newSegment.parentSegment.mirrorZ; // inherit scaling factor from parent -- this is later adjusted again if it is part of a recursion chain newSegment.scalingFactor = newSegment.parentSegment.scalingFactor; newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; // propagate scaling factor // Check for if the segment currently being built is a Mirror COPY: if (currentBuildSegmentList[i].isMirror) { //Debug.Log("This is a MIRROR COPY segment - Wow!"); if(currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorX) { // Invert the X-axis (this will propagate down to all this segment's children newSegment.mirrorX = !newSegment.mirrorX; } else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorY) { newSegment.mirrorY = !newSegment.mirrorY; } //else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorZ) { // newSegment.mirrorZ = !newSegment.mirrorZ; //} } } if (physicsOn) { newGO.AddComponent<Rigidbody>().isKinematic = false; if(editor && currentBuildSegmentList[i].sourceNode.ID == 0) newGO.GetComponent<Rigidbody>().isKinematic = true; if(editor) { // TEMPORARY!!!! if editor && physX, build critterMesh so hide segments! //newGO.GetComponent<MeshRenderer>().enabled = false; } //newGO.GetComponent<Rigidbody>().drag = 20f; //newGO.GetComponent<Rigidbody>().angularDrag = 20f; // Bouncy Root: //GameObject anchorGO = new GameObject("Anchor"); //anchorGO.transform.SetParent(this.gameObject.transform); //anchorGO.AddComponent<Rigidbody>().isKinematic = true; /*ConfigurableJoint configJoint = newGO.AddComponent<ConfigurableJoint>(); configJoint.autoConfigureConnectedAnchor = false; configJoint.connectedBody = anchorGO.GetComponent<Rigidbody>(); configJoint.anchor = new Vector3(0f, 0f, 0f); configJoint.connectedAnchor = new Vector3(0f, 0f, 0f); configJoint.xMotion = ConfigurableJointMotion.Locked; configJoint.yMotion = ConfigurableJointMotion.Locked; configJoint.zMotion = ConfigurableJointMotion.Locked; configJoint.angularXMotion = ConfigurableJointMotion.Locked; configJoint.angularYMotion = ConfigurableJointMotion.Locked; configJoint.angularZMotion = ConfigurableJointMotion.Locked; SoftJointLimitSpring limitSpring = configJoint.linearLimitSpring; limitSpring.spring = 80f; limitSpring.damper = 800f; configJoint.linearLimitSpring = limitSpring; SoftJointLimit jointLimit = configJoint.linearLimit; jointLimit.limit = 0.01f; jointLimit.bounciness = 0.01f; configJoint.linearLimit = jointLimit; configJoint.angularXLimitSpring = limitSpring; configJoint.angularYZLimitSpring = limitSpring; */ } // CHECK FOR RECURSION: if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { // if the node being considered has recursions: //Debug.Log("currentNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + "newSegmentRecursion#: " + newSegment.recursionNumber.ToString() + ", parentRecursion#: " + currentBuildSegmentList[i].parentSegment.recursionNumber.ToString()); if (newSegment.sourceNode == currentBuildSegmentList[i].parentSegment.sourceNode) { // if this segment's sourceNode is the same is its parent Segment's sourceNode, then it is not the root of the recursion chain! //Debug.Log("newSegment.sourceNode == currentBuildNodeParentSegmentList[i].sourceNode!"); // Are we at the end of a recursion chain? if (currentBuildSegmentList[i].parentSegment.recursionNumber >= currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) { //Debug.Log("recursion number greater than numRecursions! ( " + currentBuildSegmentList[i].parentSegment.recursionNumber.ToString() + " vs " + currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions.ToString()); newSegment.recursionNumber = currentBuildSegmentList[i].parentSegment.recursionNumber + 1; // //newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; } else { // create new recursion instance!! BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode; // request a segment to be built again based on the current sourceNode newSegment.recursionNumber = currentBuildSegmentList[i].parentSegment.recursionNumber + 1; //newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; // propagate scaling factor newSegmentInfo.parentSegment = newSegment; // parent of itself (the just-built Segment) nextBuildSegmentList.Add(newSegmentInfo); // If the node also has Symmetry: if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode; // uses same sourceNode, but tags as Mirror: newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // this is the root --- its sourceNode has recursion, and this segment is unique from its parentNode: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode; newSegment.recursionNumber = 1; newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); // If the node also has Symmetry: if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode; // uses same sourceNode, but tags as Mirror: newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } // PositionSEGMENT GameObject!!! if (newSegment.id == 0) { // if ROOT NODE: } else { SetSegmentTransform(newGO); // Properly position the SegmentGO where it should be && scale! critterTotalVolume += newGO.transform.localScale.x * newGO.transform.localScale.y * newGO.transform.localScale.z; if (physicsOn) { //newGO.GetComponent<Rigidbody>().isKinematic = false; newGO.GetComponent<Rigidbody>().ResetInertiaTensor(); ConfigurableJoint configJoint = newGO.AddComponent<ConfigurableJoint>(); configJoint.autoConfigureConnectedAnchor = false; configJoint.connectedBody = newSegment.parentSegment.gameObject.GetComponent<Rigidbody>(); configJoint.anchor = GetJointAnchor(newSegment); configJoint.connectedAnchor = GetJointConnectedAnchor(newSegment); // <-- Might be Unnecessary ConfigureJointSettings(newSegment, ref configJoint); // UPDATE THIS TO USE segaddonJointMotorSettings!?!? } } // Check boundingBox: //BoundingBox CheckBoundingBox(newGO); // SEGMENT ADDONS: if (physicsOn) { // Check for Physical Attributes: List<AddonPhysicalAttributes> physicalAttributesList = masterCritterGenome.CheckForAddonPhysicalAttributes(currentBuildSegmentList[i].sourceNode.ID); for(int a = 0; a < physicalAttributesList.Count; a++) { SegaddonPhysicalAttributes newPhysicalAttributes = new SegaddonPhysicalAttributes(physicalAttributesList[a]); newPhysicalAttributes.segmentID = newSegment.id; segaddonPhysicalAttributesList.Add(newPhysicalAttributes); segmentPhysicMaterial.dynamicFriction = newPhysicalAttributes.dynamicFriction[0]; segmentPhysicMaterial.staticFriction = newPhysicalAttributes.staticFriction[0]; segmentPhysicMaterial.bounciness = newPhysicalAttributes.bounciness[0]; RigidbodyConstraints rbConstraints = newGO.GetComponent<Rigidbody>().constraints; if (newPhysicalAttributes.freezePositionX[0]) { rbConstraints = rbConstraints | RigidbodyConstraints.FreezePositionX; } if (newPhysicalAttributes.freezePositionY[0]) { rbConstraints = rbConstraints | RigidbodyConstraints.FreezePositionY; } if (newPhysicalAttributes.freezePositionZ[0]) { rbConstraints = rbConstraints | RigidbodyConstraints.FreezePositionZ; } if (newPhysicalAttributes.freezeRotationX[0]) { rbConstraints = rbConstraints | RigidbodyConstraints.FreezeRotationX; } if (newPhysicalAttributes.freezeRotationY[0]) { rbConstraints = rbConstraints | RigidbodyConstraints.FreezeRotationY; } if (newPhysicalAttributes.freezeRotationZ[0]) { rbConstraints = rbConstraints | RigidbodyConstraints.FreezeRotationZ; } newGO.GetComponent<Rigidbody>().constraints = rbConstraints; newGO.GetComponent<BoxCollider>().material = segmentPhysicMaterial; } #region INPUTS List<AddonJointAngleSensor> jointAngleSensorList = masterCritterGenome.CheckForAddonJointAngleSensor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < jointAngleSensorList.Count; j++) { SegaddonJointAngleSensor newJointAngleSensor = new SegaddonJointAngleSensor(jointAngleSensorList[j]); newJointAngleSensor.segmentID = newSegment.id; segaddonJointAngleSensorList.Add(newJointAngleSensor); if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeX) { string inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleX"; BrainInputChannel BIC_SegmentAngle = new BrainInputChannel(ref newJointAngleSensor.angleX, true, inputChannelName); inputChannelsList.Add(BIC_SegmentAngle); if (newJointAngleSensor.measureVel) { inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleVelX"; BrainInputChannel BIC_SegmentAngleVel = new BrainInputChannel(ref newJointAngleSensor.angleVelX, true, inputChannelName); inputChannelsList.Add(BIC_SegmentAngleVel); } } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeY) { string inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleY"; BrainInputChannel BIC_SegmentAngle = new BrainInputChannel(ref newJointAngleSensor.angleY, true, inputChannelName); inputChannelsList.Add(BIC_SegmentAngle); if (newJointAngleSensor.measureVel) { inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleVelY"; BrainInputChannel BIC_SegmentAngleVel = new BrainInputChannel(ref newJointAngleSensor.angleVelY, true, inputChannelName); inputChannelsList.Add(BIC_SegmentAngleVel); } } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeZ) { string inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleZ"; BrainInputChannel BIC_SegmentAngle = new BrainInputChannel(ref newJointAngleSensor.angleZ, true, inputChannelName); inputChannelsList.Add(BIC_SegmentAngle); if (newJointAngleSensor.measureVel) { inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleVelZ"; BrainInputChannel BIC_SegmentAngleVel = new BrainInputChannel(ref newJointAngleSensor.angleVelZ, true, inputChannelName); inputChannelsList.Add(BIC_SegmentAngleVel); } } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.DualXY) { string inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleX"; BrainInputChannel BIC_SegmentAngleX = new BrainInputChannel(ref newJointAngleSensor.angleX, true, inputChannelName); inputChannelsList.Add(BIC_SegmentAngleX); inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleY"; BrainInputChannel BIC_SegmentAngleY = new BrainInputChannel(ref newJointAngleSensor.angleY, true, inputChannelName); inputChannelsList.Add(BIC_SegmentAngleY); if (newJointAngleSensor.measureVel) { inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleVelX"; BrainInputChannel BIC_SegmentAngleVelX = new BrainInputChannel(ref newJointAngleSensor.angleVelX, true, inputChannelName); inputChannelsList.Add(BIC_SegmentAngleVelX); inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleVelY"; BrainInputChannel BIC_SegmentAngleVelY = new BrainInputChannel(ref newJointAngleSensor.angleVelY, true, inputChannelName); inputChannelsList.Add(BIC_SegmentAngleVelY); } } } List<AddonContactSensor> contactSensorList = masterCritterGenome.CheckForAddonContactSensor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < contactSensorList.Count; j++) { SegaddonContactSensor newContactSensor = new SegaddonContactSensor(contactSensorList[j]); newContactSensor.segmentID = newSegment.id; segaddonContactSensorList.Add(newContactSensor); SegaddonCollisionDetector collisionDetector = newGO.AddComponent<SegaddonCollisionDetector>(); collisionDetector.referencedContactSensor = newContactSensor; string inputChannelName = "Segment " + newContactSensor.segmentID.ToString() + " Contact Sensor"; BrainInputChannel BIC_SegmentContactInput = new BrainInputChannel(ref newContactSensor.contactStatus, true, inputChannelName); inputChannelsList.Add(BIC_SegmentContactInput); } List<AddonRaycastSensor> raycastSensorList = masterCritterGenome.CheckForAddonRaycastSensor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < raycastSensorList.Count; j++) { SegaddonRaycastSensor newRaycastSensor = new SegaddonRaycastSensor(raycastSensorList[j]); newRaycastSensor.segmentID = newSegment.id; segaddonRaycastSensorList.Add(newRaycastSensor); string inputChannelName = "Segment " + newRaycastSensor.segmentID.ToString() + " Raycast Sensor(dist)"; BrainInputChannel BIC_SegmentRaycastInput = new BrainInputChannel(ref newRaycastSensor.distance, true, inputChannelName); inputChannelsList.Add(BIC_SegmentRaycastInput); } List<AddonCompassSensor1D> compassSensor1DList = masterCritterGenome.CheckForAddonCompassSensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < compassSensor1DList.Count; j++) { SegaddonCompassSensor1D newCompassSensor1D = new SegaddonCompassSensor1D(compassSensor1DList[j]); newCompassSensor1D.segmentID = newSegment.id; segaddonCompassSensor1DList.Add(newCompassSensor1D); string inputChannelName = "Segment " + newCompassSensor1D.segmentID.ToString() + " Compass1D"; BrainInputChannel BIC_SegmentCompass1DInput = new BrainInputChannel(ref newCompassSensor1D.dotProduct, true, inputChannelName); inputChannelsList.Add(BIC_SegmentCompass1DInput); } List<AddonCompassSensor3D> compassSensor3DList = masterCritterGenome.CheckForAddonCompassSensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < compassSensor3DList.Count; j++) { SegaddonCompassSensor3D newCompassSensor3D = new SegaddonCompassSensor3D(compassSensor3DList[j]); newCompassSensor3D.segmentID = newSegment.id; segaddonCompassSensor3DList.Add(newCompassSensor3D); string inputChannelName = "Segment " + newCompassSensor3D.segmentID.ToString() + " Compass3D Right"; BrainInputChannel BIC_SegmentCompass3DInputRight = new BrainInputChannel(ref newCompassSensor3D.dotProductRight, true, inputChannelName); inputChannelsList.Add(BIC_SegmentCompass3DInputRight); inputChannelName = "Segment " + newCompassSensor3D.segmentID.ToString() + " Compass3D Up"; BrainInputChannel BIC_SegmentCompass3DInputUp = new BrainInputChannel(ref newCompassSensor3D.dotProductUp, true, inputChannelName); inputChannelsList.Add(BIC_SegmentCompass3DInputUp); inputChannelName = "Segment " + newCompassSensor3D.segmentID.ToString() + " Compass3D Forward"; BrainInputChannel BIC_SegmentCompass3DInputForward = new BrainInputChannel(ref newCompassSensor3D.dotProductForward, true, inputChannelName); inputChannelsList.Add(BIC_SegmentCompass3DInputForward); } List<AddonPositionSensor1D> positionSensor1DList = masterCritterGenome.CheckForAddonPositionSensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < positionSensor1DList.Count; j++) { SegaddonPositionSensor1D newPositionSensor1D = new SegaddonPositionSensor1D(positionSensor1DList[j]); newPositionSensor1D.segmentID = newSegment.id; segaddonPositionSensor1DList.Add(newPositionSensor1D); string inputChannelName = "Segment " + newPositionSensor1D.segmentID.ToString() + " Position1D Forward"; BrainInputChannel BIC_SegmentPosition1DInput = new BrainInputChannel(ref newPositionSensor1D.linearDistance, true, inputChannelName); inputChannelsList.Add(BIC_SegmentPosition1DInput); } List<AddonPositionSensor3D> positionSensor3DList = masterCritterGenome.CheckForAddonPositionSensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < positionSensor3DList.Count; j++) { SegaddonPositionSensor3D newPositionSensor3D = new SegaddonPositionSensor3D(positionSensor3DList[j]); newPositionSensor3D.segmentID = newSegment.id; segaddonPositionSensor3DList.Add(newPositionSensor3D); string inputChannelName = "Segment " + newPositionSensor3D.segmentID.ToString() + " Position3D Right"; BrainInputChannel BIC_SegmentPosition3DInputRight = new BrainInputChannel(ref newPositionSensor3D.distanceRight, true, inputChannelName); inputChannelsList.Add(BIC_SegmentPosition3DInputRight); inputChannelName = "Segment " + newPositionSensor3D.segmentID.ToString() + " Position3D Up"; BrainInputChannel BIC_SegmentPosition3DInputUp = new BrainInputChannel(ref newPositionSensor3D.distanceUp, true, inputChannelName); inputChannelsList.Add(BIC_SegmentPosition3DInputUp); inputChannelName = "Segment " + newPositionSensor3D.segmentID.ToString() + " Position3D Forward"; BrainInputChannel BIC_SegmentPosition3DInputForward = new BrainInputChannel(ref newPositionSensor3D.distanceForward, true, inputChannelName); inputChannelsList.Add(BIC_SegmentPosition3DInputForward); } List<AddonRotationSensor1D> rotationSensor1DList = masterCritterGenome.CheckForAddonRotationSensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < rotationSensor1DList.Count; j++) { SegaddonRotationSensor1D newRotationSensor1D = new SegaddonRotationSensor1D(rotationSensor1DList[j]); newRotationSensor1D.segmentID = newSegment.id; segaddonRotationSensor1DList.Add(newRotationSensor1D); string inputChannelName = "Segment " + newRotationSensor1D.segmentID.ToString() + " Rotation1D"; BrainInputChannel BIC_SegmentRotation1DInput = new BrainInputChannel(ref newRotationSensor1D.rotationRate, true, inputChannelName); inputChannelsList.Add(BIC_SegmentRotation1DInput); } List<AddonRotationSensor3D> rotationSensor3DList = masterCritterGenome.CheckForAddonRotationSensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < rotationSensor3DList.Count; j++) { SegaddonRotationSensor3D newRotationSensor3D = new SegaddonRotationSensor3D(rotationSensor3DList[j]); newRotationSensor3D.segmentID = newSegment.id; segaddonRotationSensor3DList.Add(newRotationSensor3D); string inputChannelName = "Segment " + newRotationSensor3D.segmentID.ToString() + " Rotation3D X"; BrainInputChannel BIC_SegmentRotation3DInputX = new BrainInputChannel(ref newRotationSensor3D.rotationRateX, true, inputChannelName); inputChannelsList.Add(BIC_SegmentRotation3DInputX); inputChannelName = "Segment " + newRotationSensor3D.segmentID.ToString() + " Rotation3D Y"; BrainInputChannel BIC_SegmentRotation3DInputY = new BrainInputChannel(ref newRotationSensor3D.rotationRateY, true, inputChannelName); inputChannelsList.Add(BIC_SegmentRotation3DInputY); inputChannelName = "Segment " + newRotationSensor3D.segmentID.ToString() + " Rotation3D Z"; BrainInputChannel BIC_SegmentRotation3DInputZ = new BrainInputChannel(ref newRotationSensor3D.rotationRateZ, true, inputChannelName); inputChannelsList.Add(BIC_SegmentRotation3DInputZ); } List<AddonVelocitySensor1D> velocitySensor1DList = masterCritterGenome.CheckForAddonVelocitySensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < velocitySensor1DList.Count; j++) { SegaddonVelocitySensor1D newVelocitySensor1D = new SegaddonVelocitySensor1D(velocitySensor1DList[j]); newVelocitySensor1D.segmentID = newSegment.id; segaddonVelocitySensor1DList.Add(newVelocitySensor1D); string inputChannelName = "Segment " + newVelocitySensor1D.segmentID.ToString() + " Velocity1D"; BrainInputChannel BIC_SegmentVelocity1DInput = new BrainInputChannel(ref newVelocitySensor1D.componentVelocity, true, inputChannelName); inputChannelsList.Add(BIC_SegmentVelocity1DInput); } List<AddonVelocitySensor3D> velocitySensor3DList = masterCritterGenome.CheckForAddonVelocitySensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < velocitySensor3DList.Count; j++) { SegaddonVelocitySensor3D newVelocitySensor3D = new SegaddonVelocitySensor3D(velocitySensor3DList[j]); newVelocitySensor3D.segmentID = newSegment.id; segaddonVelocitySensor3DList.Add(newVelocitySensor3D); string inputChannelName = "Segment " + newVelocitySensor3D.segmentID.ToString() + " Velocity3D Right"; BrainInputChannel BIC_SegmentVelocity3DInputRight = new BrainInputChannel(ref newVelocitySensor3D.velocityRight, true, inputChannelName); inputChannelsList.Add(BIC_SegmentVelocity3DInputRight); inputChannelName = "Segment " + newVelocitySensor3D.segmentID.ToString() + " Velocity3D Up"; BrainInputChannel BIC_SegmentVelocity3DInputUp = new BrainInputChannel(ref newVelocitySensor3D.velocityUp, true, inputChannelName); inputChannelsList.Add(BIC_SegmentVelocity3DInputUp); inputChannelName = "Segment " + newVelocitySensor3D.segmentID.ToString() + " Velocity3D Forward"; BrainInputChannel BIC_SegmentVelocity3DInputForward = new BrainInputChannel(ref newVelocitySensor3D.velocityForward, true, inputChannelName); inputChannelsList.Add(BIC_SegmentVelocity3DInputForward); } List<AddonAltimeter> altimeterList = masterCritterGenome.CheckForAddonAltimeter(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < altimeterList.Count; j++) { SegaddonAltimeter newAltimeter = new SegaddonAltimeter(altimeterList[j]); newAltimeter.segmentID = newSegment.id; segaddonAltimeterList.Add(newAltimeter); string inputChannelName = "Segment " + newAltimeter.segmentID.ToString() + " Altimeter"; BrainInputChannel BIC_SegmentAltimeterInput = new BrainInputChannel(ref newAltimeter.altitude, true, inputChannelName); inputChannelsList.Add(BIC_SegmentAltimeterInput); } List<AddonEarBasic> earBasicList = masterCritterGenome.CheckForAddonEarBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < earBasicList.Count; j++) { SegaddonEarBasic newEarBasic = new SegaddonEarBasic(earBasicList[j]); newEarBasic.segmentID = newSegment.id; segaddonEarBasicList.Add(newEarBasic); string inputChannelName = "Segment " + newEarBasic.segmentID.ToString() + " Ear Basic"; BrainInputChannel BIC_SegmentEarBasicInput = new BrainInputChannel(ref newEarBasic.activation, true, inputChannelName); inputChannelsList.Add(BIC_SegmentEarBasicInput); } List<AddonGravitySensor> gravitySensorList = masterCritterGenome.CheckForAddonGravitySensor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < gravitySensorList.Count; j++) { SegaddonGravitySensor newGravitySensor = new SegaddonGravitySensor(gravitySensorList[j]); newGravitySensor.segmentID = newSegment.id; segaddonGravitySensorList.Add(newGravitySensor); string inputChannelName = "Segment " + newGravitySensor.segmentID.ToString() + " Gravity Sensor"; BrainInputChannel BIC_SegmentGravityInput = new BrainInputChannel(ref newGravitySensor.gravityDot, true, inputChannelName); inputChannelsList.Add(BIC_SegmentGravityInput); } List<AddonOscillatorInput> oscillatorInputList = masterCritterGenome.CheckForAddonOscillatorInput(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < oscillatorInputList.Count; j++) { SegaddonOscillatorInput newOscillatorInput = new SegaddonOscillatorInput(oscillatorInputList[j]); newOscillatorInput.segmentID = newSegment.id; segaddonOscillatorInputList.Add(newOscillatorInput); //SegaddonOscillatorInput oscillatorInput = critterBeingTested.segaddonOscillatorInputList[oscillatorInputIndex]; string inputChannelName = "Segment " + newOscillatorInput.segmentID.ToString() + " Oscillator Input"; BrainInputChannel BIC_SegmentOscillatorInput = new BrainInputChannel(ref newOscillatorInput.value, true, inputChannelName); inputChannelsList.Add(BIC_SegmentOscillatorInput); } List<AddonValueInput> valueInputList = masterCritterGenome.CheckForAddonValueInput(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < valueInputList.Count; j++) { SegaddonValueInput newValueInput = new SegaddonValueInput(valueInputList[j]); newValueInput.segmentID = newSegment.id; segaddonValueInputList.Add(newValueInput); string inputChannelName = "Segment " + newValueInput.segmentID.ToString() + " Value Input"; BrainInputChannel BIC_SegmentValueInput = new BrainInputChannel(ref newValueInput.value, true, inputChannelName); inputChannelsList.Add(BIC_SegmentValueInput); } List<AddonTimerInput> timerInputList = masterCritterGenome.CheckForAddonTimerInput(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < timerInputList.Count; j++) { SegaddonTimerInput newTimerInput = new SegaddonTimerInput(timerInputList[j]); newTimerInput.segmentID = newSegment.id; segaddonTimerInputList.Add(newTimerInput); string inputChannelName = "Segment " + newTimerInput.segmentID.ToString() + " Timer Input"; BrainInputChannel BIC_SegmentTimerInput = new BrainInputChannel(ref newTimerInput.value, true, inputChannelName); inputChannelsList.Add(BIC_SegmentTimerInput); } #endregion #region OUTPUTS: List<AddonJointMotor> jointMotorList = masterCritterGenome.CheckForAddonJointMotor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < jointMotorList.Count; j++) { SegaddonJointMotor newJointMotor = new SegaddonJointMotor(jointMotorList[j]); newJointMotor.segmentID = newSegment.id; segaddonJointMotorList.Add(newJointMotor); //SegaddonJointMotor motor = critterBeingTested.segaddonJointMotorList[motorIndex]; if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeX) { string outputChannelName = "Segment " + newJointMotor.segmentID.ToString() + " Motor Target X"; BrainOutputChannel BOC_SegmentAngleVel = new BrainOutputChannel(ref newJointMotor.targetAngularX, true, outputChannelName); outputChannelsList.Add(BOC_SegmentAngleVel); } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeY) { string outputChannelName = "Segment " + newJointMotor.segmentID.ToString() + " Motor Target Y"; BrainOutputChannel BOC_SegmentAngleVel = new BrainOutputChannel(ref newJointMotor.targetAngularY, true, outputChannelName); outputChannelsList.Add(BOC_SegmentAngleVel); } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeZ) { string outputChannelName = "Segment " + newJointMotor.segmentID.ToString() + " Motor Target Z"; BrainOutputChannel BOC_SegmentAngleVel = new BrainOutputChannel(ref newJointMotor.targetAngularZ, true, outputChannelName); outputChannelsList.Add(BOC_SegmentAngleVel); } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.DualXY) { string outputChannelName = "Segment " + newJointMotor.segmentID.ToString() + " Motor Target X"; BrainOutputChannel BOC_SegmentAngleVelX = new BrainOutputChannel(ref newJointMotor.targetAngularX, true, outputChannelName); outputChannelsList.Add(BOC_SegmentAngleVelX); outputChannelName = "Segment " + newJointMotor.segmentID.ToString() + " Motor Target Y"; BrainOutputChannel BOC_SegmentAngleVelY = new BrainOutputChannel(ref newJointMotor.targetAngularY, true, outputChannelName); outputChannelsList.Add(BOC_SegmentAngleVelY); } } List<AddonThrusterEffector1D> thrusterEffector1DList = masterCritterGenome.CheckForAddonThrusterEffector1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < thrusterEffector1DList.Count; j++) { SegaddonThrusterEffector1D newThrusterEffector1D = new SegaddonThrusterEffector1D(thrusterEffector1DList[j]); newThrusterEffector1D.segmentID = newSegment.id; segaddonThrusterEffector1DList.Add(newThrusterEffector1D); string outputChannelName = "Segment " + newThrusterEffector1D.segmentID.ToString() + " Thruster1D"; BrainOutputChannel BOC_SegmentThruster1D = new BrainOutputChannel(ref newThrusterEffector1D.throttle, true, outputChannelName); outputChannelsList.Add(BOC_SegmentThruster1D); } List<AddonThrusterEffector3D> thrusterEffector3DList = masterCritterGenome.CheckForAddonThrusterEffector3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < thrusterEffector3DList.Count; j++) { SegaddonThrusterEffector3D newThrusterEffector3D = new SegaddonThrusterEffector3D(thrusterEffector3DList[j]); newThrusterEffector3D.segmentID = newSegment.id; segaddonThrusterEffector3DList.Add(newThrusterEffector3D); string outputChannelName = "Segment " + newThrusterEffector3D.segmentID.ToString() + " Thruster3D X"; BrainOutputChannel BOC_SegmentThruster3DX = new BrainOutputChannel(ref newThrusterEffector3D.throttleX, true, outputChannelName); outputChannelsList.Add(BOC_SegmentThruster3DX); outputChannelName = "Segment " + newThrusterEffector3D.segmentID.ToString() + " Thruster3D Y"; BrainOutputChannel BOC_SegmentThruster3DY = new BrainOutputChannel(ref newThrusterEffector3D.throttleY, true, outputChannelName); outputChannelsList.Add(BOC_SegmentThruster3DY); outputChannelName = "Segment " + newThrusterEffector3D.segmentID.ToString() + " Thruster3D Z"; BrainOutputChannel BOC_SegmentThruster3DZ = new BrainOutputChannel(ref newThrusterEffector3D.throttleZ, true, outputChannelName); outputChannelsList.Add(BOC_SegmentThruster3DZ); } List<AddonTorqueEffector1D> torqueEffector1DList = masterCritterGenome.CheckForAddonTorqueEffector1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < torqueEffector1DList.Count; j++) { SegaddonTorqueEffector1D newTorqueEffector1D = new SegaddonTorqueEffector1D(torqueEffector1DList[j]); newTorqueEffector1D.segmentID = newSegment.id; segaddonTorqueEffector1DList.Add(newTorqueEffector1D); string outputChannelName = "Segment " + newTorqueEffector1D.segmentID.ToString() + " Torque1D"; BrainOutputChannel BOC_SegmentTorque1D = new BrainOutputChannel(ref newTorqueEffector1D.throttle, true, outputChannelName); outputChannelsList.Add(BOC_SegmentTorque1D); } List<AddonTorqueEffector3D> torqueEffector3DList = masterCritterGenome.CheckForAddonTorqueEffector3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < torqueEffector3DList.Count; j++) { SegaddonTorqueEffector3D newTorqueEffector3D = new SegaddonTorqueEffector3D(torqueEffector3DList[j]); newTorqueEffector3D.segmentID = newSegment.id; segaddonTorqueEffector3DList.Add(newTorqueEffector3D); string outputChannelName = "Segment " + newTorqueEffector3D.segmentID.ToString() + " Torque3D X"; BrainOutputChannel BOC_SegmentTorque3DX = new BrainOutputChannel(ref newTorqueEffector3D.throttleX, true, outputChannelName); outputChannelsList.Add(BOC_SegmentTorque3DX); outputChannelName = "Segment " + newTorqueEffector3D.segmentID.ToString() + " Torque3D Y"; BrainOutputChannel BOC_SegmentTorque3DY = new BrainOutputChannel(ref newTorqueEffector3D.throttleY, true, outputChannelName); outputChannelsList.Add(BOC_SegmentTorque3DY); outputChannelName = "Segment " + newTorqueEffector3D.segmentID.ToString() + " Torque3D Z"; BrainOutputChannel BOC_SegmentTorque3DZ = new BrainOutputChannel(ref newTorqueEffector3D.throttleZ, true, outputChannelName); outputChannelsList.Add(BOC_SegmentTorque3DZ); } List<AddonMouthBasic> mouthBasicList = masterCritterGenome.CheckForAddonMouthBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < mouthBasicList.Count; j++) { SegaddonMouthBasic newMouthBasic = new SegaddonMouthBasic(mouthBasicList[j]); newMouthBasic.segmentID = newSegment.id; segaddonMouthBasicList.Add(newMouthBasic); SegaddonTriggerDetector triggerDetector = newGO.AddComponent<SegaddonTriggerDetector>(); triggerDetector.referencedMouth = newMouthBasic; } List<AddonNoiseMakerBasic> noiseMakerBasicList = masterCritterGenome.CheckForAddonNoiseMakerBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < noiseMakerBasicList.Count; j++) { SegaddonNoiseMakerBasic newNoiseMakerBasic = new SegaddonNoiseMakerBasic(noiseMakerBasicList[j]); newNoiseMakerBasic.segmentID = newSegment.id; segaddonNoiseMakerBasicList.Add(newNoiseMakerBasic); string outputChannelName = "Segment " + newNoiseMakerBasic.segmentID.ToString() + " NoiseMaker"; BrainOutputChannel BOC_SegmentNoiseMaker = new BrainOutputChannel(ref newNoiseMakerBasic.volume, true, outputChannelName); outputChannelsList.Add(BOC_SegmentNoiseMaker); } List<AddonSticky> stickyList = masterCritterGenome.CheckForAddonSticky(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < stickyList.Count; j++) { SegaddonSticky newSticky = new SegaddonSticky(stickyList[j]); newSticky.segmentID = newSegment.id; segaddonStickyList.Add(newSticky); string outputChannelName = "Segment " + newSticky.segmentID.ToString() + " Sticky"; BrainOutputChannel BOC_SegmentSticky = new BrainOutputChannel(ref newSticky.stickiness, true, outputChannelName); outputChannelsList.Add(BOC_SegmentSticky); } List<AddonWeaponBasic> weaponBasicList = masterCritterGenome.CheckForAddonWeaponBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < weaponBasicList.Count; j++) { SegaddonWeaponBasic newWeaponBasic = new SegaddonWeaponBasic(weaponBasicList[j]); newWeaponBasic.segmentID = newSegment.id; segaddonWeaponBasicList.Add(newWeaponBasic); string outputChannelName = "Segment " + newWeaponBasic.segmentID.ToString() + " Weapon"; BrainOutputChannel BOC_SegmentWeapon = new BrainOutputChannel(ref newWeaponBasic.strength, true, outputChannelName); outputChannelsList.Add(BOC_SegmentWeapon); } #endregion } // Figure out how many unique Child nodes this built node has: //int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedJointLinkList.Count; // old int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList.Count; //Debug.Log("numberOfChildNodes: " + numberOfChildNodes.ToString() + "currentBuildSegmentList[i].sourceNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + ", i: " + i.ToString()); for (int c = 0; c < numberOfChildNodes; c++) { // if NO symmetry: // Check if Attaching to a recursion chain && if onlyattachToTail is active: int childID = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList[c]; //Debug.Log("%%%%% c=" + c.ToString() + ", childID: " + childID.ToString() + ", critterNodeListCount: " + masterCritterGenome.CritterNodeList.Count.ToString()); // if(currentBuildSegmentList[i].sourceNode.attachedJointLinkList[c].childNode.parentJointLink.onlyAttachToTailNode) // OLD if (masterCritterGenome.CritterNodeList[childID].jointLink.onlyAttachToTailNode) { if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { if (newSegment.recursionNumber > newSegment.sourceNode.jointLink.numberOfRecursions) { // Only build segment if it is on the end of a recursion chain: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = masterCritterGenome.CritterNodeList[childID]; newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (masterCritterGenome.CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = masterCritterGenome.CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // It only attaches to End nodes, but is parented to a Non-recursive segment, so proceed normally!!! BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = masterCritterGenome.CritterNodeList[childID]; newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (masterCritterGenome.CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = masterCritterGenome.CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // proceed normally: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = masterCritterGenome.CritterNodeList[childID]; newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (masterCritterGenome.CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = masterCritterGenome.CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } } // After all buildNodes have been built, and their subsequent childNodes Enqueued, copy pendingChildQueue into buildNodesQueue currentBuildSegmentList.Clear(); // SWAP LISTS: if (nextBuildSegmentList.Count > 0) { for (int j = 0; j < nextBuildSegmentList.Count; j++) { currentBuildSegmentList.Add(nextBuildSegmentList[j]); } nextBuildSegmentList.Clear(); // empty this list for next depth-round } else { isPendingChildren = false; } if (currentDepth >= maxDepth) { // SAFEGUARD!! prevents infinite loop in case I mess something up isPendingChildren = false; } currentDepth++; } //Debug.Log("RebuildCritterFromGenomeRecursive " + inputChannelsList.Count.ToString() + ", " + outputChannelsList.Count.ToString()); //Debug.Log("RebuildCritterFromGenomeRecursive: COM_Offset: (" + masterCritterGenome.centerOfMassOffset.x.ToString() + ", " + masterCritterGenome.centerOfMassOffset.y.ToString() + ", " + masterCritterGenome.centerOfMassOffset.z.ToString() + "), totalVolume: " + critterTotalVolume.ToString());// + " RootPos: " + critterSegmentList[0].transform.position.ToString()); }
public void PreBuildCritter(float variableMass) { //Debug.Log("RebuildCritterFromGenomeRecursive: " + masterCritterGenome.CritterNodeList.Count.ToString()); // interpret Genome and construct critter in its bind pose bool isPendingChildren = true; int currentDepth = 0; // start with RootNode int maxDepth = 20; // safeguard to prevent while loop lock int nextSegmentID = 0; List<CritterSegment> builtSegmentsList = new List<CritterSegment>(); // keep track of segments that have been built - linear in-order array 0-n segments List<BuildSegmentInfo> currentBuildSegmentList = new List<BuildSegmentInfo>(); // keeps track of all current-depth segment build-requests, and holds important metadata List<BuildSegmentInfo> nextBuildSegmentList = new List<BuildSegmentInfo>(); // used to keep track of next childSegments that need to be built float critterTotalVolume = 0f; // keep track of total volume // *********** Will attempt to traverse the Segments to be created, keeping track of where on each graph (nodes# & segment#) the current build is on. BuildSegmentInfo rootSegmentBuildInfo = new BuildSegmentInfo(); rootSegmentBuildInfo.sourceNode = CritterNodeList[0]; currentBuildSegmentList.Add(rootSegmentBuildInfo); // ROOT NODE IS SPECIAL! // Do a Breadth-first traversal?? #region First WhileLoop while (isPendingChildren) { //int numberOfChildNodes = masterCritterGenome.CritterNodeList[currentNode].attachedJointLinkList.Count; for (int i = 0; i < currentBuildSegmentList.Count; i++) { //Debug.Log("currentDepth: " + currentDepth.ToString() + "builtNodesQueue.Count: " + builtSegmentsList.Count.ToString() + ", pendingNodes: " + currentBuildSegmentList.Count.ToString() + ", i: " + i.ToString()); // Iterate through pending nodes // Build current node --> Segment GameObject newGO = new GameObject("Node" + nextSegmentID.ToString()); CritterSegment newSegment = newGO.AddComponent<CritterSegment>(); builtSegmentsList.Add(newSegment); if(TempCritterConstructionGroup.tempCritterConstructionGroup != null) { newGO.transform.SetParent(TempCritterConstructionGroup.tempCritterConstructionGroup.gameObject.transform); } //newGO.AddComponent<BoxCollider>().isTrigger = false; //critterSegmentList.Add(newGO); // Add to master Linear list of Segments //newSegment.InitGamePiece(); // create the mesh and some other initialization stuff newSegment.sourceNode = currentBuildSegmentList[i].sourceNode; newSegment.id = nextSegmentID; nextSegmentID++; if (currentBuildSegmentList[i].sourceNode.ID == 0) { // is ROOT segment -- Look into doing Root build BEFORE for loop to avoid the need to do this check newGO.transform.position = Vector3.zero; newGO.transform.localPosition = Vector3.zero; newGO.transform.rotation = Quaternion.identity; newSegment.scalingFactor = newSegment.sourceNode.jointLink.recursionScalingFactor; newGO.transform.localScale = currentBuildSegmentList[i].sourceNode.dimensions * newSegment.scalingFactor; //newSegment.surfaceArea = new Vector3(newGO.transform.localScale.y * newGO.transform.localScale.z * 2f, newGO.transform.localScale.x * newGO.transform.localScale.z * 2f, newGO.transform.localScale.x * newGO.transform.localScale.y * 2f); } else { // if NOT root segment, can consider parent-related stuff: newSegment.parentSegment = currentBuildSegmentList[i].parentSegment; // Inherit Axis-Inversions from parent segment: newSegment.mirrorX = newSegment.parentSegment.mirrorX; newSegment.mirrorY = newSegment.parentSegment.mirrorY; newSegment.mirrorZ = newSegment.parentSegment.mirrorZ; // inherit scaling factor from parent -- this is later adjusted again if it is part of a recursion chain newSegment.scalingFactor = newSegment.parentSegment.scalingFactor; newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; // propagate scaling factor // Check for if the segment currently being built is a Mirror COPY: if (currentBuildSegmentList[i].isMirror) { //Debug.Log("This is a MIRROR COPY segment - Wow!"); if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorX) { // Invert the X-axis (this will propagate down to all this segment's children newSegment.mirrorX = !newSegment.mirrorX; } else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorY) { newSegment.mirrorY = !newSegment.mirrorY; } //else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorZ) { // newSegment.mirrorZ = !newSegment.mirrorZ; //} } } // CHECK FOR RECURSION: if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { // if the node being considered has recursions: //Debug.Log("currentNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + "newSegmentRecursion#: " + newSegment.recursionNumber.ToString() + ", parentRecursion#: " + currentBuildSegmentList[i].parentSegment.recursionNumber.ToString()); if (newSegment.sourceNode == currentBuildSegmentList[i].parentSegment.sourceNode) { // if this segment's sourceNode is the same is its parent Segment's sourceNode, then it is not the root of the recursion chain! //Debug.Log("newSegment.sourceNode == currentBuildNodeParentSegmentList[i].sourceNode!"); // Are we at the end of a recursion chain? if (currentBuildSegmentList[i].parentSegment.recursionNumber >= currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) { //Debug.Log("recursion number greater than numRecursions! ( " + currentBuildSegmentList[i].parentSegment.recursionNumber.ToString() + " vs " + currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions.ToString()); newSegment.recursionNumber = currentBuildSegmentList[i].parentSegment.recursionNumber + 1; // //newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; } else { // create new recursion instance!! BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode; // request a segment to be built again based on the current sourceNode newSegment.recursionNumber = currentBuildSegmentList[i].parentSegment.recursionNumber + 1; //newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; // propagate scaling factor newSegmentInfo.parentSegment = newSegment; // parent of itself (the just-built Segment) nextBuildSegmentList.Add(newSegmentInfo); // If the node also has Symmetry: if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode; // uses same sourceNode, but tags as Mirror: newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // this is the root --- its sourceNode has recursion, and this segment is unique from its parentNode: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode; newSegment.recursionNumber = 1; newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); // If the node also has Symmetry: if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode; // uses same sourceNode, but tags as Mirror: newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } // Figure out how many unique Child nodes this built node has: //int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedJointLinkList.Count; // old int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList.Count; //Debug.Log("numberOfChildNodes: " + numberOfChildNodes.ToString() + "currentBuildSegmentList[i].sourceNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + ", i: " + i.ToString()); for (int c = 0; c < numberOfChildNodes; c++) { // if NO symmetry: // Check if Attaching to a recursion chain && if onlyattachToTail is active: int childID = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList[c]; //Debug.Log("%%%%% c=" + c.ToString() + ", childID: " + childID.ToString() + ", critterNodeListCount: " + masterCritterGenome.CritterNodeList.Count.ToString()); // if(currentBuildSegmentList[i].sourceNode.attachedJointLinkList[c].childNode.parentJointLink.onlyAttachToTailNode) // OLD if (CritterNodeList[childID].jointLink.onlyAttachToTailNode) { if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { if (newSegment.recursionNumber > newSegment.sourceNode.jointLink.numberOfRecursions) { // Only build segment if it is on the end of a recursion chain: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // It only attaches to End nodes, but is parented to a Non-recursive segment, so proceed normally!!! BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // proceed normally: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } // PositionSEGMENT GameObject!!! if (newSegment.id == 0) { // if ROOT NODE: } else { SetSegmentTransform(newGO); // Properly position the SegmentGO where it should be && scale! } critterTotalVolume += newGO.transform.localScale.x * newGO.transform.localScale.y * newGO.transform.localScale.z; } // After all buildNodes have been built, and their subsequent childNodes Enqueued, copy pendingChildQueue into buildNodesQueue currentBuildSegmentList.Clear(); // SWAP LISTS: if (nextBuildSegmentList.Count > 0) { for (int j = 0; j < nextBuildSegmentList.Count; j++) { currentBuildSegmentList.Add(nextBuildSegmentList[j]); } nextBuildSegmentList.Clear(); // empty this list for next depth-round } else { isPendingChildren = false; } if (currentDepth >= maxDepth) { // SAFEGUARD!! prevents infinite loop in case I mess something up isPendingChildren = false; } currentDepth++; } #endregion //Debug.Log("RebuildCritterFromGenomeRecursive " + inputChannelsList.Count.ToString() + ", " + outputChannelsList.Count.ToString()); // Re-Size Critter based on target volume: float targetTotalVolume = 4f; float linearScaling = Mathf.Pow(targetTotalVolume / critterTotalVolume, 1f / 3f); for (int i = 0; i < CritterNodeList.Count; i++) { CritterNodeList[i].dimensions.x *= linearScaling; CritterNodeList[i].dimensions.y *= linearScaling; CritterNodeList[i].dimensions.z *= linearScaling; } // interpret Genome and construct critter in its bind pose isPendingChildren = true; currentDepth = 0; // start with RootNode maxDepth = 20; // safeguard to prevent while loop lock nextSegmentID = 0; builtSegmentsList.Clear(); currentBuildSegmentList.Clear(); nextBuildSegmentList.Clear(); // *********** Will attempt to traverse the Segments to be created, keeping track of where on each graph (nodes# & segment#) the current build is on. rootSegmentBuildInfo = new BuildSegmentInfo(); rootSegmentBuildInfo.sourceNode = CritterNodeList[0]; currentBuildSegmentList.Add(rootSegmentBuildInfo); // ROOT NODE IS SPECIAL! // Do a Breadth-first traversal?? #region Second WhileLoop while (isPendingChildren) { //int numberOfChildNodes = masterCritterGenome.CritterNodeList[currentNode].attachedJointLinkList.Count; for (int i = 0; i < currentBuildSegmentList.Count; i++) { //Debug.Log("currentDepth: " + currentDepth.ToString() + "builtNodesQueue.Count: " + builtSegmentsList.Count.ToString() + ", pendingNodes: " + currentBuildSegmentList.Count.ToString() + ", i: " + i.ToString()); // Iterate through pending nodes // Build current node --> Segment GameObject newGO = new GameObject("Node" + nextSegmentID.ToString()); CritterSegment newSegment = newGO.AddComponent<CritterSegment>(); builtSegmentsList.Add(newSegment); newGO.transform.SetParent(TempCritterConstructionGroup.tempCritterConstructionGroup.gameObject.transform); //newGO.AddComponent<BoxCollider>().isTrigger = false; //critterSegmentList.Add(newGO); // Add to master Linear list of Segments //newSegment.InitGamePiece(); // create the mesh and some other initialization stuff newSegment.sourceNode = currentBuildSegmentList[i].sourceNode; newSegment.id = nextSegmentID; nextSegmentID++; if (currentBuildSegmentList[i].sourceNode.ID == 0) { // is ROOT segment -- Look into doing Root build BEFORE for loop to avoid the need to do this check newGO.transform.position = Vector3.zero; newGO.transform.rotation = Quaternion.identity; newSegment.scalingFactor = newSegment.sourceNode.jointLink.recursionScalingFactor; newGO.transform.localScale = currentBuildSegmentList[i].sourceNode.dimensions * newSegment.scalingFactor; //newSegment.surfaceArea = new Vector3(newGO.transform.localScale.y * newGO.transform.localScale.z * 2f, newGO.transform.localScale.x * newGO.transform.localScale.z * 2f, newGO.transform.localScale.x * newGO.transform.localScale.y * 2f); } else { // if NOT root segment, can consider parent-related stuff: newSegment.parentSegment = currentBuildSegmentList[i].parentSegment; // Inherit Axis-Inversions from parent segment: newSegment.mirrorX = newSegment.parentSegment.mirrorX; newSegment.mirrorY = newSegment.parentSegment.mirrorY; newSegment.mirrorZ = newSegment.parentSegment.mirrorZ; // inherit scaling factor from parent -- this is later adjusted again if it is part of a recursion chain newSegment.scalingFactor = newSegment.parentSegment.scalingFactor; newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; // propagate scaling factor // Check for if the segment currently being built is a Mirror COPY: if (currentBuildSegmentList[i].isMirror) { //Debug.Log("This is a MIRROR COPY segment - Wow!"); if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorX) { // Invert the X-axis (this will propagate down to all this segment's children newSegment.mirrorX = !newSegment.mirrorX; } else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorY) { newSegment.mirrorY = !newSegment.mirrorY; } //else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorZ) { // newSegment.mirrorZ = !newSegment.mirrorZ; //} } } // CHECK FOR RECURSION: if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { // if the node being considered has recursions: //Debug.Log("currentNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + "newSegmentRecursion#: " + newSegment.recursionNumber.ToString() + ", parentRecursion#: " + currentBuildSegmentList[i].parentSegment.recursionNumber.ToString()); if (newSegment.sourceNode == currentBuildSegmentList[i].parentSegment.sourceNode) { // if this segment's sourceNode is the same is its parent Segment's sourceNode, then it is not the root of the recursion chain! //Debug.Log("newSegment.sourceNode == currentBuildNodeParentSegmentList[i].sourceNode!"); // Are we at the end of a recursion chain? if (currentBuildSegmentList[i].parentSegment.recursionNumber >= currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) { //Debug.Log("recursion number greater than numRecursions! ( " + currentBuildSegmentList[i].parentSegment.recursionNumber.ToString() + " vs " + currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions.ToString()); newSegment.recursionNumber = currentBuildSegmentList[i].parentSegment.recursionNumber + 1; // //newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; } else { // create new recursion instance!! BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode; // request a segment to be built again based on the current sourceNode newSegment.recursionNumber = currentBuildSegmentList[i].parentSegment.recursionNumber + 1; //newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; // propagate scaling factor newSegmentInfo.parentSegment = newSegment; // parent of itself (the just-built Segment) nextBuildSegmentList.Add(newSegmentInfo); // If the node also has Symmetry: if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode; // uses same sourceNode, but tags as Mirror: newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // this is the root --- its sourceNode has recursion, and this segment is unique from its parentNode: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode; newSegment.recursionNumber = 1; newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); // If the node also has Symmetry: if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode; // uses same sourceNode, but tags as Mirror: newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } // Figure out how many unique Child nodes this built node has: //int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedJointLinkList.Count; // old int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList.Count; //Debug.Log("numberOfChildNodes: " + numberOfChildNodes.ToString() + "currentBuildSegmentList[i].sourceNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + ", i: " + i.ToString()); for (int c = 0; c < numberOfChildNodes; c++) { // if NO symmetry: // Check if Attaching to a recursion chain && if onlyattachToTail is active: int childID = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList[c]; //Debug.Log("%%%%% c=" + c.ToString() + ", childID: " + childID.ToString() + ", critterNodeListCount: " + masterCritterGenome.CritterNodeList.Count.ToString()); // if(currentBuildSegmentList[i].sourceNode.attachedJointLinkList[c].childNode.parentJointLink.onlyAttachToTailNode) // OLD if (CritterNodeList[childID].jointLink.onlyAttachToTailNode) { if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { if (newSegment.recursionNumber > newSegment.sourceNode.jointLink.numberOfRecursions) { // Only build segment if it is on the end of a recursion chain: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // It only attaches to End nodes, but is parented to a Non-recursive segment, so proceed normally!!! BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // proceed normally: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } // PositionSEGMENT GameObject!!! if (newSegment.id == 0) { // if ROOT NODE: } else { SetSegmentTransform(newGO); // Properly position the SegmentGO where it should be && scale! } } // After all buildNodes have been built, and their subsequent childNodes Enqueued, copy pendingChildQueue into buildNodesQueue currentBuildSegmentList.Clear(); // SWAP LISTS: if (nextBuildSegmentList.Count > 0) { for (int j = 0; j < nextBuildSegmentList.Count; j++) { currentBuildSegmentList.Add(nextBuildSegmentList[j]); } nextBuildSegmentList.Clear(); // empty this list for next depth-round } else { isPendingChildren = false; } if (currentDepth >= maxDepth) { // SAFEGUARD!! prevents infinite loop in case I mess something up isPendingChildren = false; } currentDepth++; } #endregion //Debug.Log("RebuildCritterFromGenomeRecursive " + inputChannelsList.Count.ToString() + ", " + outputChannelsList.Count.ToString()); centerOfMassOffset.x = 0f; centerOfMassOffset.y = 0f; centerOfMassOffset.z = 0f; Vector3 avgPos = new Vector3(0f, 0f, 0f); List<float> segmentMassesList = new List<float>(); float critterTotalMass = 0f; // Fill data arrays with Critter stats for CritterSEGMENTS: for (int i = 0; i < builtSegmentsList.Count; i++) { // iterate through every segment float segmentVolume = builtSegmentsList[i].transform.localScale.x * builtSegmentsList[i].transform.localScale.y * builtSegmentsList[i].transform.localScale.z; float segmentMass = Mathf.Lerp(1f, segmentVolume, variableMass); segmentMassesList.Add(segmentMass); critterTotalMass += segmentMass; } float avgMass = critterTotalMass / builtSegmentsList.Count; // string segmentPositions = "CritterPreBuild SegmentPositions: \n"; critterTotalMass /= avgMass; // Adjust to center around 1f; for (int j = 0; j < builtSegmentsList.Count; j++) { // Finalize Segment Mass Value: segmentMassesList[j] /= avgMass; // Center the segment Masses around 1f, to avoid precision errors //critterBeingTested.critterSegmentList[j].GetComponent<Rigidbody>().mass = wormSegmentArray_Mass[j]; float shareOfTotalMass = segmentMassesList[j] / critterTotalMass; avgPos.x += builtSegmentsList[j].transform.position.x * shareOfTotalMass; // multiply position by proportional share of total mass avgPos.y += builtSegmentsList[j].transform.position.y * shareOfTotalMass; avgPos.z += builtSegmentsList[j].transform.position.z * shareOfTotalMass; segmentPositions += "(" + builtSegmentsList[j].transform.position.x.ToString() + ", " + builtSegmentsList[j].transform.position.y.ToString() + ", " + builtSegmentsList[j].transform.position.z.ToString() + ")\n"; } centerOfMassOffset.x = -avgPos.x; centerOfMassOffset.y = -avgPos.y; centerOfMassOffset.z = -avgPos.z; //Debug.Log(segmentPositions + "\nC.O.M: (" + avgPos.x.ToString() + ", " + avgPos.y.ToString() + ", " + avgPos.z.ToString() + ")"); // Delete created Segment GameObjects: // Do I need to delete Components first? TempCritterConstructionGroup.tempCritterConstructionGroup.DeleteSegments(); }
public List<GeneNodeNEAT> GetBlankBrainNodesFromBody() { List<GeneNodeNEAT> newNodeList = new List<GeneNodeNEAT>(); // Split into Input/Output list and put together afterward? List<GeneNodeNEAT> inputNodeList = new List<GeneNodeNEAT>(); List<GeneNodeNEAT> outputNodeList = new List<GeneNodeNEAT>(); int numSegments = 0; int numInputs = 0; int numOutputs = 0; bool isPendingChildren = true; int currentDepth = 0; // start with RootNode int maxDepth = 20; // safeguard to prevent while loop lock int nextSegmentID = 0; int currentBrainNodeID = 0; List<BuildSegmentInfo> currentBuildSegmentList = new List<BuildSegmentInfo>(); // keeps track of all current-depth segment build-requests, and holds important metadata List<BuildSegmentInfo> nextBuildSegmentList = new List<BuildSegmentInfo>(); // used to keep track of next childSegments that need to be built // *********** Will attempt to traverse the Segments to be created, keeping track of where on each graph (nodes# & segment#) the current build is on. BuildSegmentInfo rootSegmentBuildInfo = new BuildSegmentInfo(); rootSegmentBuildInfo.sourceNode = CritterNodeList[0]; currentBuildSegmentList.Add(rootSegmentBuildInfo); // ROOT NODE IS SPECIAL! // Do a Breadth-first traversal?? while (isPendingChildren) { for (int i = 0; i < currentBuildSegmentList.Count; i++) { numSegments++; nextSegmentID++; // PhysicalAttributes no inputs/outputs #region INPUTS // Joint Angle Sensors: if (currentBuildSegmentList[i].sourceNode.ID != 0) { // is NOT ROOT segment -- Look into doing Root build BEFORE for loop to avoid the need to do this check List<AddonJointAngleSensor> jointAngleSensorList = CheckForAddonJointAngleSensor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < jointAngleSensorList.Count; j++) { // HINGE X X X X X if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeX) { if (jointAngleSensorList[j].measureVel[0]) { // ALSO MEASURES ANGULAR VELOCITY: numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; } else { // Only Angle, no velocity: numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeY) { if (jointAngleSensorList[j].measureVel[0]) { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; } else { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeZ) { if (jointAngleSensorList[j].measureVel[0]) { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; } else { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.DualXY) { if (jointAngleSensorList[j].measureVel[0]) { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2); inputNodeList.Add(newNodeNEAT3); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT4 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 3); inputNodeList.Add(newNodeNEAT4); currentBrainNodeID++; } else { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; } } } } List<AddonContactSensor> contactSensorList = CheckForAddonContactSensor(currentBuildSegmentList[i].sourceNode.ID); for(int j = 0; j < contactSensorList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, contactSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonRaycastSensor> raycastSensorList = CheckForAddonRaycastSensor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < raycastSensorList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, raycastSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonCompassSensor1D> compassSensor1DList = CheckForAddonCompassSensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < compassSensor1DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, compassSensor1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonCompassSensor3D> compassSensor3DList = CheckForAddonCompassSensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < compassSensor3DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, compassSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, compassSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, compassSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2); inputNodeList.Add(newNodeNEAT3); currentBrainNodeID++; } List<AddonPositionSensor1D> positionSensor1DList = CheckForAddonPositionSensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < positionSensor1DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, positionSensor1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonPositionSensor3D> positionSensor3DList = CheckForAddonPositionSensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < positionSensor3DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, positionSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, positionSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, positionSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2); inputNodeList.Add(newNodeNEAT3); currentBrainNodeID++; } List<AddonRotationSensor1D> rotationSensor1DList = CheckForAddonRotationSensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < rotationSensor1DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, rotationSensor1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonRotationSensor3D> rotationSensor3DList = CheckForAddonRotationSensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < rotationSensor3DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, rotationSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, rotationSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, rotationSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2); inputNodeList.Add(newNodeNEAT3); currentBrainNodeID++; } List<AddonVelocitySensor1D> velocitySensor1DList = CheckForAddonVelocitySensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < velocitySensor1DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, velocitySensor1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonVelocitySensor3D> velocitySensor3DList = CheckForAddonVelocitySensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < velocitySensor3DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, velocitySensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, velocitySensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, velocitySensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2); inputNodeList.Add(newNodeNEAT3); currentBrainNodeID++; } List<AddonAltimeter> altimeterList = CheckForAddonAltimeter(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < altimeterList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, altimeterList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonEarBasic> earBasicList = CheckForAddonEarBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < earBasicList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, earBasicList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonGravitySensor> gravitySensorList = CheckForAddonGravitySensor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < gravitySensorList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, gravitySensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonOscillatorInput> oscillatorInputList = CheckForAddonOscillatorInput(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < oscillatorInputList.Count; j++) { numInputs++; //Debug.Log("Oscillator: nodeIndex: " + currentBrainNodeID.ToString() + ", " + new Int3(oscillatorInputList[j].innov, currentBuildSegmentList[i].recursionNumber, 0).ToString()); GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, oscillatorInputList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonValueInput> valueInputList = CheckForAddonValueInput(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < valueInputList.Count; j++) { numInputs++; //Debug.Log("Value: nodeIndex: " + currentBrainNodeID.ToString() + ", " + new Int3(valueInputList[j].innov, currentBuildSegmentList[i].recursionNumber, 0).ToString()); GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, valueInputList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } //Debug.Log(currentBuildSegmentList[i].sourceNode.ID.ToString() + " oscillatorInputList Count: " + oscillatorInputList.Count.ToString() + ", valueInputList Count: " + valueInputList.Count.ToString()); List<AddonTimerInput> timerInputList = CheckForAddonTimerInput(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < timerInputList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, timerInputList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } #endregion #region OUTPUTS: if (currentBuildSegmentList[i].sourceNode.ID != 0) { // is NOT ROOT segment -- Look into doing Root build BEFORE for loop to avoid the need to do this check List<AddonJointMotor> jointMotorList = CheckForAddonJointMotor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < jointMotorList.Count; j++) { if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeX) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeY) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeZ) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.DualXY) { numOutputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numOutputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); outputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; } } // %%%%%% DO I STILL NEED THIS SECTION??? // Check for if the segment currently being built is a Mirror COPY: /*if (currentBuildSegmentList[i].isMirror) { //Debug.Log("This is a MIRROR COPY segment - Wow!"); if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorX) { // Invert the X-axis (this will propagate down to all this segment's children //newSegment.mirrorX = !newSegment.mirrorX; } else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorY) { //newSegment.mirrorY = !newSegment.mirrorY; } else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorZ) { //newSegment.mirrorZ = !newSegment.mirrorZ; } }*/ } List<AddonThrusterEffector1D> thrusterEffector1DList = CheckForAddonThrusterEffector1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < thrusterEffector1DList.Count; j++) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, thrusterEffector1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonThrusterEffector3D> thrusterEffector3DList = CheckForAddonThrusterEffector3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < thrusterEffector3DList.Count; j++) { numOutputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, thrusterEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numOutputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, thrusterEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); outputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; numOutputs++; GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, thrusterEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2); outputNodeList.Add(newNodeNEAT3); currentBrainNodeID++; } List<AddonTorqueEffector1D> torqueEffector1DList = CheckForAddonTorqueEffector1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < torqueEffector1DList.Count; j++) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, torqueEffector1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonTorqueEffector3D> torqueEffector3DList = CheckForAddonTorqueEffector3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < torqueEffector3DList.Count; j++) { numOutputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, torqueEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numOutputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, torqueEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); outputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; numOutputs++; GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, torqueEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2); outputNodeList.Add(newNodeNEAT3); currentBrainNodeID++; } List<AddonMouthBasic> mouthBasicList = CheckForAddonMouthBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < mouthBasicList.Count; j++) { // BLANK FOR NOW!!! } List<AddonNoiseMakerBasic> noiseMakerBasicList = CheckForAddonNoiseMakerBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < noiseMakerBasicList.Count; j++) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, noiseMakerBasicList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonSticky> stickyList = CheckForAddonSticky(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < stickyList.Count; j++) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, stickyList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonWeaponBasic> weaponBasicList = CheckForAddonWeaponBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < weaponBasicList.Count; j++) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, weaponBasicList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } #endregion // CHECK FOR RECURSION: if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { // if the node being considered has recursions: if (currentBuildSegmentList[i].recursionNumber < currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) { // if the current buildOrder's recursion number is less than the numRecursions there should be: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode; // request a segment to be built again based on the current sourceNode newSegmentInfo.recursionNumber = currentBuildSegmentList[i].recursionNumber + 1; // increment num recursions newSegmentInfo.isMirror = currentBuildSegmentList[i].isMirror; nextBuildSegmentList.Add(newSegmentInfo); //Debug.Log("newSegmentInfo recursion# " + newSegmentInfo.recursionNumber.ToString() + ", currentBuildList[i].recNum: " + currentBuildSegmentList[i].recursionNumber.ToString()); // If the node also has Symmetry: if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode; // uses same sourceNode, but tags as Mirror: newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.recursionNumber = newSegmentInfo.recursionNumber; // !!!!!!!!!!!!! HIGHLY SUSPECT!!!! nextBuildSegmentList.Add(newSegmentInfoMirror); } } else { // at the end of a recursion chain, so do not add any other pendingChild builds } } // Figure out how many unique Child nodes this built node has: int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList.Count; //Debug.Log("numberOfChildNodes: " + numberOfChildNodes.ToString() + "currentBuildSegmentList[i].sourceNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + ", i: " + i.ToString()); for (int c = 0; c < numberOfChildNodes; c++) { // if NO symmetry: // Check if Attaching to a recursion chain && if onlyattachToTail is active: int childID = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList[c]; if (CritterNodeList[childID].jointLink.onlyAttachToTailNode) { if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { if (currentBuildSegmentList[i].recursionNumber >= currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) { // Only build segment if it is on the end of a recursion chain: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; newSegmentInfo.isMirror = currentBuildSegmentList[i].isMirror; //newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original //newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // It only attaches to End nodes, but is parented to a Non-recursive segment, so proceed normally!!! BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; newSegmentInfo.isMirror = currentBuildSegmentList[i].isMirror; //newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original //newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // proceed normally: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; newSegmentInfo.isMirror = currentBuildSegmentList[i].isMirror; //newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original //newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } } // After all buildNodes have been built, and their subsequent childNodes Enqueued, copy pendingChildQueue into buildNodesQueue currentBuildSegmentList.Clear(); // SWAP LISTS: if (nextBuildSegmentList.Count > 0) { for (int j = 0; j < nextBuildSegmentList.Count; j++) { currentBuildSegmentList.Add(nextBuildSegmentList[j]); } nextBuildSegmentList.Clear(); // empty this list for next depth-round } else { isPendingChildren = false; } if (currentDepth >= maxDepth) { // SAFEGUARD!! prevents infinite loop in case I mess something up isPendingChildren = false; } currentDepth++; } for(int i = 0; i < inputNodeList.Count; i++) { newNodeList.Add(inputNodeList[i]); } for (int i = 0; i < outputNodeList.Count; i++) { newNodeList.Add(outputNodeList[i]); } for (int i = 0; i < newNodeList.Count; i++) { newNodeList[i].id = i; // Re-number nodes so that their list Index is always the same as their ID } return newNodeList; }
public int[] CalculateNumberOfSegmentsInputsOutputs() { int numSegments = 0; int numInputs = 0; int numOutputs = 0; int[] retVal = new int[3]; bool isPendingChildren = true; int currentDepth = 0; // start with RootNode int maxDepth = 20; // safeguard to prevent while loop lock int nextSegmentID = 0; List<BuildSegmentInfo> currentBuildSegmentList = new List<BuildSegmentInfo>(); // keeps track of all current-depth segment build-requests, and holds important metadata List<BuildSegmentInfo> nextBuildSegmentList = new List<BuildSegmentInfo>(); // used to keep track of next childSegments that need to be built // *********** Will attempt to traverse the Segments to be created, keeping track of where on each graph (nodes# & segment#) the current build is on. BuildSegmentInfo rootSegmentBuildInfo = new BuildSegmentInfo(); rootSegmentBuildInfo.sourceNode = CritterNodeList[0]; currentBuildSegmentList.Add(rootSegmentBuildInfo); // ROOT NODE IS SPECIAL! // Do a Breadth-first traversal?? while (isPendingChildren) { for (int i = 0; i < currentBuildSegmentList.Count; i++) { numSegments++; nextSegmentID++; #region INPUTS // PhysAttrs would be here, but it has no inputs/outputs if (currentBuildSegmentList[i].sourceNode.ID != 0) { // is NOT ROOT segment -- Look into doing Root build BEFORE for loop to avoid the need to do this check List<AddonJointAngleSensor> jointAngleSensorList = CheckForAddonJointAngleSensor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < jointAngleSensorList.Count; j++) { // HINGE X X X X X if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeX) { if (jointAngleSensorList[j].measureVel[0]) { // ALSO MEASURES ANGULAR VELOCITY: numInputs = numInputs + 2; } else { // Only Angle, no velocity: numInputs++; } } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeY) { if (jointAngleSensorList[j].measureVel[0]) { numInputs = numInputs + 2; } else { numInputs++; } } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeZ) { if (jointAngleSensorList[j].measureVel[0]) { numInputs = numInputs + 2; } else { numInputs++; } } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.DualXY) { if (jointAngleSensorList[j].measureVel[0]) { numInputs = numInputs + 4; } else { numInputs = numInputs + 2; } } } } List<AddonContactSensor> contactSensorList = CheckForAddonContactSensor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < contactSensorList.Count; j++) { numInputs++; } List<AddonRaycastSensor> raycastSensorList = CheckForAddonRaycastSensor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < raycastSensorList.Count; j++) { numInputs++; } List<AddonCompassSensor1D> compassSensor1DList = CheckForAddonCompassSensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < compassSensor1DList.Count; j++) { numInputs++; } List<AddonCompassSensor3D> compassSensor3DList = CheckForAddonCompassSensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < compassSensor3DList.Count; j++) { numInputs = numInputs + 3; } List<AddonPositionSensor1D> positionSensor1DList = CheckForAddonPositionSensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < positionSensor1DList.Count; j++) { numInputs++; } List<AddonPositionSensor3D> positionSensor3DList = CheckForAddonPositionSensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < positionSensor3DList.Count; j++) { numInputs = numInputs + 3; } List<AddonRotationSensor1D> rotationSensor1DList = CheckForAddonRotationSensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < rotationSensor1DList.Count; j++) { numInputs++; } List<AddonRotationSensor3D> rotationSensor3DList = CheckForAddonRotationSensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < rotationSensor3DList.Count; j++) { numInputs = numInputs + 3; } List<AddonVelocitySensor1D> velocitySensor1DList = CheckForAddonVelocitySensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < velocitySensor1DList.Count; j++) { numInputs++; } List<AddonVelocitySensor3D> velocitySensor3DList = CheckForAddonVelocitySensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < velocitySensor3DList.Count; j++) { numInputs = numInputs + 3; } List<AddonAltimeter> altimeterList = CheckForAddonAltimeter(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < altimeterList.Count; j++) { numInputs++; } List<AddonEarBasic> earBasicList = CheckForAddonEarBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < earBasicList.Count; j++) { numInputs++; } List<AddonGravitySensor> gravitySensorList = CheckForAddonGravitySensor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < gravitySensorList.Count; j++) { numInputs++; } List<AddonOscillatorInput> oscillatorInputList = CheckForAddonOscillatorInput(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < oscillatorInputList.Count; j++) { numInputs++; } List<AddonValueInput> valueInputList = CheckForAddonValueInput(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < valueInputList.Count; j++) { numInputs++; } List<AddonTimerInput> timerInputList = CheckForAddonTimerInput(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < timerInputList.Count; j++) { numInputs++; } #endregion #region OUTPUTS: if (currentBuildSegmentList[i].sourceNode.ID != 0) { // is NOT ROOT segment -- Look into doing Root build BEFORE for loop to avoid the need to do this check List<AddonJointMotor> jointMotorList = CheckForAddonJointMotor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < jointMotorList.Count; j++) { if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeX) { numOutputs++; } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeY) { numOutputs++; } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeZ) { numOutputs++; } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.DualXY) { numOutputs = numOutputs + 2; } } } List<AddonThrusterEffector1D> thrusterEffector1DList = CheckForAddonThrusterEffector1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < thrusterEffector1DList.Count; j++) { numOutputs++; } List<AddonThrusterEffector3D> thrusterEffector3DList = CheckForAddonThrusterEffector3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < thrusterEffector3DList.Count; j++) { numOutputs = numOutputs + 3; } List<AddonTorqueEffector1D> torqueEffector1DList = CheckForAddonTorqueEffector1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < torqueEffector1DList.Count; j++) { numOutputs++; } List<AddonTorqueEffector3D> torqueEffector3DList = CheckForAddonTorqueEffector3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < torqueEffector3DList.Count; j++) { numOutputs = numOutputs + 3; } List<AddonMouthBasic> mouthBasicList = CheckForAddonMouthBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < mouthBasicList.Count; j++) { // BLANK FOR NOW!!! } List<AddonNoiseMakerBasic> noiseMakerBasicList = CheckForAddonNoiseMakerBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < noiseMakerBasicList.Count; j++) { numOutputs++; } List<AddonSticky> stickyList = CheckForAddonSticky(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < stickyList.Count; j++) { numOutputs++; } List<AddonWeaponBasic> weaponBasicList = CheckForAddonWeaponBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < weaponBasicList.Count; j++) { numOutputs++; } #endregion // CHECK FOR RECURSION: if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { // if the node being considered has recursions: if(currentBuildSegmentList[i].recursionNumber < currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) { // if the current buildOrder's recursion number is less than the numRecursions there should be: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode; // request a segment to be built again based on the current sourceNode newSegmentInfo.recursionNumber = currentBuildSegmentList[i].recursionNumber + 1; // increment num recursions nextBuildSegmentList.Add(newSegmentInfo); //Debug.Log("newSegmentInfo recursion# " + newSegmentInfo.recursionNumber.ToString() + ", currentBuildList[i].recNum: " + currentBuildSegmentList[i].recursionNumber.ToString()); // If the node also has Symmetry: if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode; // uses same sourceNode, but tags as Mirror: newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.recursionNumber = newSegmentInfo.recursionNumber; // !!!!!!!!!!!!! HIGHLY SUSPECT!!!! nextBuildSegmentList.Add(newSegmentInfoMirror); } } else { // at the end of a recursion chain, so do not add any other pendingChild builds } } // Figure out how many unique Child nodes this built node has: int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList.Count; //Debug.Log("numberOfChildNodes: " + numberOfChildNodes.ToString() + "currentBuildSegmentList[i].sourceNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + ", i: " + i.ToString()); for (int c = 0; c < numberOfChildNodes; c++) { // if NO symmetry: // Check if Attaching to a recursion chain && if onlyattachToTail is active: int childID = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList[c]; if (CritterNodeList[childID].jointLink.onlyAttachToTailNode) { if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { if (currentBuildSegmentList[i].recursionNumber >= currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) { // Only build segment if it is on the end of a recursion chain: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; //newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original //newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // It only attaches to End nodes, but is parented to a Non-recursive segment, so proceed normally!!! BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; //newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original //newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // proceed normally: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; //newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original //newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } } // After all buildNodes have been built, and their subsequent childNodes Enqueued, copy pendingChildQueue into buildNodesQueue currentBuildSegmentList.Clear(); // SWAP LISTS: if (nextBuildSegmentList.Count > 0) { for (int j = 0; j < nextBuildSegmentList.Count; j++) { currentBuildSegmentList.Add(nextBuildSegmentList[j]); } nextBuildSegmentList.Clear(); // empty this list for next depth-round } else { isPendingChildren = false; } if (currentDepth >= maxDepth) { // SAFEGUARD!! prevents infinite loop in case I mess something up isPendingChildren = false; } currentDepth++; } retVal[0] = numSegments; retVal[1] = numInputs; retVal[2] = numOutputs; return retVal; }