public static BasicObstaclesGenome BirthNewGenome(BasicObstaclesGenome parentGenome, float mutationRate, float mutationDriftAmount, EnvironmentGenome envGenomeRef)
    {
        // OBSTACLES:
        // NEED TO COPY ALL ATTRIBUTES HERE unless I switch mutation process to go: full-copy, then re-traverse and mutate on a second sweep...
        BasicObstaclesGenome newGenome = new BasicObstaclesGenome();

        newGenome.numObstacles    = parentGenome.numObstacles;
        newGenome.minObstacleSize = parentGenome.minObstacleSize;
        newGenome.maxObstacleSize = parentGenome.maxObstacleSize;
        newGenome.randomSeed      = parentGenome.randomSeed;
        float rand = UnityEngine.Random.Range(0f, 1f);

        if (rand < mutationRate)
        {
            int newVal = UnityEngine.Random.Range(0, 99999);
            newGenome.randomSeed = newVal;
        }

        newGenome.obstaclePositions = new Vector2[newGenome.numObstacles];
        newGenome.obstacleScales    = new float[newGenome.numObstacles];
        for (int i = 0; i < parentGenome.obstaclePositions.Length; i++)
        {
            newGenome.obstaclePositions[i] = new Vector2(parentGenome.obstaclePositions[i].x, parentGenome.obstaclePositions[i].y);
            newGenome.obstacleScales[i]    = parentGenome.obstacleScales[i];
            rand = UnityEngine.Random.Range(0f, 1f);
            if (rand < mutationRate)
            {
                float newPosX = UnityEngine.Random.Range(0f, 1f);
                newGenome.obstaclePositions[i].x = Mathf.Lerp(newGenome.obstaclePositions[i].x, newPosX, mutationDriftAmount);
            }
            if (rand < mutationRate)
            {
                float newPosZ = UnityEngine.Random.Range(0f, 1f);
                newGenome.obstaclePositions[i].y = Mathf.Lerp(newGenome.obstaclePositions[i].y, newPosZ, mutationDriftAmount);
            }
            // Check for intersection with Agent Start Position:
            Vector2 startCoords = new Vector2(envGenomeRef.agentStartPositionsList[0].agentStartPosition.x / 40f + 0.5f, envGenomeRef.agentStartPositionsList[0].agentStartPosition.z / 40f + 0.5f);
            if ((newGenome.obstaclePositions[i] - startCoords).magnitude < 0.15f)
            {
                newGenome.obstaclePositions[i] = startCoords + (newGenome.obstaclePositions[i] - startCoords) * 0.15f / (newGenome.obstaclePositions[i] - startCoords).magnitude;
            }
            // Check for intersection with Target Position:
            // will need to do this as env is being created since target pos is random

            /*if(envGenomeRef.useTargetColumn) {
             *  Vector2 targetCoords = new Vector2(envGenomeRef.targetColumnGenome..agentStartPosition.x / 40f + 0.5f, envGenomeRef.agentStartPositionsList[0].agentStartPosition.z / 40f + 0.5f);
             *  if ((newGenome.obstaclePositions[i] - startCoords).magnitude < 0.15f) {
             *      newGenome.obstaclePositions[i] = startCoords + (newGenome.obstaclePositions[i] - startCoords) * 0.15f / (newGenome.obstaclePositions[i] - startCoords).magnitude;
             *  }
             *  //
             * }*/

            if (rand < mutationRate)
            {
                float newScale = UnityEngine.Random.Range(newGenome.minObstacleSize, newGenome.maxObstacleSize);
                newGenome.obstacleScales[i] = Mathf.Lerp(newGenome.obstacleScales[i], newScale, mutationDriftAmount);
            }
        }
        return(newGenome);
    }
    public BasicObstaclesGenome(BasicObstaclesGenome templateGenome, EnvironmentGenome envGenomeRef)
    {
        numObstacles    = templateGenome.numObstacles;
        minObstacleSize = templateGenome.minObstacleSize;
        maxObstacleSize = templateGenome.maxObstacleSize;

        obstaclePositions = new Vector2[numObstacles];
        obstacleScales    = new float[numObstacles];
        for (int i = 0; i < obstaclePositions.Length; i++)
        {
            if (i < templateGenome.obstaclePositions.Length)    // when changing numOctaves, doesn't immediately change parentgenome terrainWaves array
            //terrainWaves[i] = new Vector3(templateGenome.terrainWaves[i].x, templateGenome.terrainWaves[i].y, templateGenome.terrainWaves[i].z);
            //Debug.Log("Copy Terrain Genome: " + terrainWaves[i].ToString());
            {
                obstaclePositions[i] = new Vector2(templateGenome.obstaclePositions[i].x, templateGenome.obstaclePositions[i].y);
                obstacleScales[i]    = templateGenome.obstacleScales[i];
                // = size;
            }
            else
            {
                obstaclePositions[i] = new Vector2(UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f));
                // Revisit this for prepping agentStartPositions!!!!
                Vector2 startCoords = new Vector2(envGenomeRef.agentStartPositionsList[0].agentStartPosition.x / 40f + 0.5f, envGenomeRef.agentStartPositionsList[0].agentStartPosition.z / 40f + 0.5f);
                if ((obstaclePositions[i] - startCoords).magnitude < 0.15f)
                {
                    obstaclePositions[i] = startCoords + (obstaclePositions[i] - startCoords) * 0.15f / (obstaclePositions[i] - startCoords).magnitude;
                }
                obstacleScales[i] = UnityEngine.Random.Range(1f, 1f);
            }
        }
    }
    public void CopyGenomeFromTemplate(EnvironmentGenome templateGenome)
    {
        //Debug.Log("CopyGenomeFromTemplate BEFORE startPosCount: " + templateGenome.agentStartPositionsList.Count.ToString());
        // This method creates a clone of the provided ScriptableObject Genome - should have no shared references!!!
        this.challengeType = templateGenome.challengeType;
        arenaBounds        = new Vector3(templateGenome.arenaBounds.x, templateGenome.arenaBounds.y, templateGenome.arenaBounds.z);

        agentStartPositionsList = new List <StartPositionGenome>();
        for (int i = 0; i < templateGenome.agentStartPositionsList.Count; i++)
        {
            //Debug.Log("CopyGenomeFromTemplate DURING i: " + i.ToString());
            StartPositionGenome genomeCopy = new StartPositionGenome(templateGenome.agentStartPositionsList[i]);
            agentStartPositionsList.Add(genomeCopy);
        }
        //Debug.Log("CopyGenomeFromTemplate AFTER startPosCount: " + agentStartPositionsList.Count.ToString());

        useTerrain = templateGenome.useTerrain;
        if (useTerrain)
        {
            terrainGenome = new TerrainGenome(templateGenome.terrainGenome);
            //terrainGenome.InitializeRandomGenome();
        }
        useBasicObstacles = templateGenome.useBasicObstacles;
        if (useBasicObstacles)
        {
            basicObstaclesGenome = new BasicObstaclesGenome(templateGenome.basicObstaclesGenome, this);
            //basicObstaclesGenome.InitializeRandomGenome();
        }
        useTargetColumn = templateGenome.useTargetColumn;
        if (useTargetColumn)
        {
            targetColumnGenome = new TargetColumnGenome();
            //targetColumnGenome.InitializeRandomGenome();
        }
        useAtmosphere = templateGenome.useAtmosphere;
        if (useAtmosphere)
        {
            atmosphereGenome = new AtmosphereGenome(templateGenome.atmosphereGenome);
            //basicObstaclesGenome.InitializeRandomGenome();
        }
        useMeteorites = templateGenome.useMeteorites;
        if (useMeteorites)
        {
            meteoritesGenome = new MeteoritesGenome(templateGenome.meteoritesGenome);
            //basicObstaclesGenome.InitializeRandomGenome();
        }

        // For now this is fine -- but eventually might want to copy brainGenome from saved asset!
        //brainGenome = new BrainGenome();  // creates neuron and axonLists
        //InitializeRandomBrainGenome();
    }
    public EnvironmentGenome BirthNewGenome(EnvironmentGenome parentGenome, int index, Challenge.Type challengeType, float mutationRate, float mutationDriftAmount)
    {
        EnvironmentGenome newGenome = new EnvironmentGenome(index);

        newGenome.challengeType = parentGenome.challengeType;
        newGenome.arenaBounds   = new Vector3(parentGenome.arenaBounds.x, parentGenome.arenaBounds.y, parentGenome.arenaBounds.z);

        newGenome.useTerrain = parentGenome.useTerrain;
        if (parentGenome.useTerrain)
        {
            newGenome.terrainGenome = TerrainGenome.BirthNewGenome(parentGenome.terrainGenome, mutationRate, mutationDriftAmount);
        }
        newGenome.useBasicObstacles = parentGenome.useBasicObstacles;
        if (parentGenome.useBasicObstacles)
        {
            newGenome.basicObstaclesGenome = BasicObstaclesGenome.BirthNewGenome(parentGenome.basicObstaclesGenome, mutationRate, mutationDriftAmount, this);
        }
        newGenome.useTargetColumn = parentGenome.useTargetColumn;
        if (parentGenome.useTargetColumn)
        {
            newGenome.targetColumnGenome = TargetColumnGenome.BirthNewGenome(parentGenome.targetColumnGenome, mutationRate, mutationDriftAmount);
        }
        newGenome.useAtmosphere = parentGenome.useAtmosphere;
        if (parentGenome.useAtmosphere)
        {
            newGenome.atmosphereGenome = AtmosphereGenome.BirthNewGenome(parentGenome.atmosphereGenome, mutationRate, mutationDriftAmount);
        }
        newGenome.useMeteorites = parentGenome.useMeteorites;
        if (parentGenome.useMeteorites)
        {
            newGenome.meteoritesGenome = MeteoritesGenome.BirthNewGenome(parentGenome.meteoritesGenome, mutationRate, mutationDriftAmount);
        }

        // StartPositions:
        // HACKY! DOES NOT SUPPORT EVOLVING START POSITIONS! ALL THE SAME!!!!
        newGenome.agentStartPositionsList = parentGenome.agentStartPositionsList;

        /*newGenome.agentStartPositionsList = new List<Vector3>();
         * //Debug.Log("(parentGenome.agentStartPositionsList.Count" + parentGenome.agentStartPositionsList.Count.ToString());
         * for (int i = 0; i < parentGenome.agentStartPositionsList.Count; i++) {
         *  newGenome.agentStartPositionsList.Add(new Vector3(parentGenome.agentStartPositionsList[i].x, parentGenome.agentStartPositionsList[i].y, parentGenome.agentStartPositionsList[i].z));
         * }
         * newGenome.agentStartRotationsList = new List<Quaternion>();
         * for (int i = 0; i < parentGenome.agentStartRotationsList.Count; i++) {
         *  newGenome.agentStartRotationsList.Add(new Quaternion(parentGenome.agentStartRotationsList[i].x, parentGenome.agentStartRotationsList[i].y, parentGenome.agentStartRotationsList[i].z, parentGenome.agentStartRotationsList[i].w));
         * }*/

        return(newGenome);
    }