public void Generate() { generation++; highestFitness = 0; for (int i = 0; i < population.Count; i++) { if (population[i].fitness > highestFitness) { highestFitness = population[i].fitness; } } CollectStats(); List <Car_Class> newPopulation = new List <Car_Class>(); for (int i = 0; i < population.Count; i++) { Car_Class partnerA = AcceptReject(); Car_Class partnerB = AcceptReject(); Car_Class child = partnerA.CrossOver(partnerB); child.Mutate(); newPopulation.Add(child); } tempPopulation = newPopulation; DestroyPreviousGeneration(); population = newPopulation; }
// This function will randomly combine the genes of two Car_Classes. public Car_Class CrossOver(Car_Class partner) { GameObject parent = new GameObject("ParentDel"); GameObject body = new GameObject("BodyDel"); parent.tag = "Delete"; body.tag = "Delete"; Car_Class child = new Car_Class( parent, // Parent GameObject body, // Reference to body object new Vector3(0.5f, 0.5f, 0), // Size of car new List <Wheel> { }, // Array of wheels new Engine(1000f, 10000f, 1000f), // Cars engine. Engine speed | Max torque | Rotation speed new Driver(0f, 0f) // Driver. CorrectionCone | AccelerationCone ); int midPoint = Random.Range(0, DNA.Count); for (int i = 0; i < DNA.Count; i++) { if (i > midPoint) { child.DNA[i] = DNA[i]; } else { child.DNA[i] = partner.DNA[i]; } } List <Wheel> wheels = (List <Wheel>)child.DNA[3]; List <object> temp = child.DNA; child = new Car_Class( (GameObject)child.DNA[0], // Parent GameObject (GameObject)child.DNA[1], // Reference to body object (Vector3)child.DNA[2], // Size of car wheels, // Array of wheels (Engine)child.DNA[4], // Cars engine. Engine speed | Max torque | Rotation speed (Driver)child.DNA[5] // Driver. CorrectionCone | AccelerationCone ); return(child); }
// This function will return a Car_Class, but it will disproportionally favor Car_Classes with higher fitness. // It means the best cars are more likely to have their genes make up the next generation of cars. private Car_Class AcceptReject() { int useProtection = 0; while (true) { int index = UnityEngine.Random.Range(0, population.Count - 1); float r = UnityEngine.Random.Range(0f, highestFitness); Car_Class partner = population[index]; if (r < partner.fitness) { return(partner); } useProtection++; if (useProtection > 10000) { print("HAD TO USE PROTECTIOn"); return(null); } } }
// This function is responsible for spawning a car based on a Car_Class input. It will return a Car_Class // with references to the spawned objects of that car. public Car_Class SpawnCar(Car_Class car) { // If wheel amount is not affected by evolution, make sure every car has 2 wheels if (!main.wheelAmountAffectedByEvolution) { car.Wheels = car.Wheels.GetRange(0, 2); for (int i = 0; i < 2; i++) { if (car.Wheels.Count <= 1) { car.Wheels.Add(new Wheel(new GameObject("Wheel WTF"), new Vector2(-1, -1), new Suspension(5, 0.5f), 1)); } } } // Create a parent object that all other objects can be listed under in the hierarchy string carParentName = car.CarParent.name; Destroy(car.CarParent); if (carParentName == "") { carParentName = "Car"; } car.CarParent = new GameObject(carParentName); car.DNA[0] = car.CarParent; // Create the car body Destroy(car.Body); car.Body = Instantiate(bodyPrefab, emptyVector3, emptyQuaternion, car.CarParent.transform); car.DNA[1] = car.Body; car.Body.transform.localScale = car.Size; // Make sure the body has a body tag, so we can exclude it from colliding with other cars. car.Body.layer = 8; // Determine the cars weight based on scale float mass = car.Size.x * car.Size.y * 100 * main.percentageOfCalculatedMass; if (mass < main.lowestMass) { mass = main.lowestMass; } car.Body.GetComponent <Rigidbody2D>().mass = mass; // Initialize the car controller component on the car body Car_Controller car_controller = car.Body.GetComponent <Car_Controller>(); // Setup the engine car_controller.EngineSpeed = car.Engine.EngineSpeed; car_controller.MaxMotorTorque = car.Engine.MaxMotorTorque; car_controller.CarRotationTorque = car.Engine.CarRotationTorque; // Prepare the car driver car_controller.CorrectionCone = car.Driver.CorrectionCone; car_controller.AccelerationCone = car.Driver.AccelerationCone; if (car.Driver.CorrectionCone != 0 || car.Driver.AccelerationCone != 0) { car_controller.hasDriver = true; } // Add the wheels float carLengthX = car.Body.GetComponent <SpriteRenderer>().bounds.size.x *(1 / car.Size.x) / 2; float carLengthY = car.Body.GetComponent <SpriteRenderer>().bounds.size.y *(1 / car.Size.y) / 2; foreach (Wheel wheel in car.Wheels) { // Get the position and instantiate the wheel object Vector3 wheelPos = new Vector3(Map(wheel.Position.x, -1, 1, carLengthX * -1, carLengthX), Map(wheel.Position.y, -1, 1, carLengthY * -1, carLengthY), 0); wheel.WheelGO = Instantiate(wheelPrefab, wheelPos, emptyQuaternion, car.CarParent.transform); // Add the wheel join WheelJoint2D wheelJoint = car.Body.AddComponent <WheelJoint2D>(); wheelJoint.connectedBody = wheel.WheelGO.GetComponent <Rigidbody2D>(); wheelJoint.anchor = wheelPos; // Set wheels graphical size wheel.WheelGO.GetComponent <SpriteRenderer>().size = new Vector3(wheel.SizeX, wheel.SizeX); // Add wheel to the car tag, to avoid cars colliding with each other wheel.WheelGO.layer = 8; // Setup the suspension wheelJoint.suspension = new JointSuspension2D { frequency = wheel.Suspension.Stiffness, dampingRatio = wheel.Suspension.DampingRatio, angle = 90 }; } car.Body.GetComponent <Car_Controller>().wheels = car.Body.GetComponents <WheelJoint2D>(); car.DNA[3] = car.Wheels; return(car); }