6.1 Moth Simulator
Using Object Oriented Programming, we can represent real-world objects and their interactions as program code. And what could be more realistic than moths? We will now develop a simulation containing thousands of Moths and several Lamps to fly towards. While Lamps will be stationary objects, Moths will fly around and we need to simulate their behavior for each time step.
To encapsulate the entire simulation, the class MothSimulation is already given. It contains arrays of all the Moths and all the Lamps in existence. To draw the current state of the MothSimulation, we use the class MothSimulationCanvas. It also allows users to interactively place additional Moths and Lamps.
6.1.1 Understand the Given Tasks and Code (priceless)
Have a thorough look at the entire exersice sheet and the given given code before you start programming anything yourself. Make sure you understand how the different classes interact with each other. If anything remains unclear, ask. Do not skip this step!
MothSimulationCanvas, is only used to draw the current simulation state and to allow you to add more objects. As you implement the classes required by the following tasks, you will have to uncomment some code in Task_6_1.java, Moth.java and MothSimulationCanvas.java to see something. Note that the GUI is only there for your enjoyment and will not be tested or graded :).
6.1.2 Set up the Simulation (5 P)
All simulated objects are contained by the class MothSimulation. Finish its implementation by implementing the following functions:
a) A getter for the moths array with name getMoths() and public visibility.
b) A getter for the lamps array with name getLamps() and public visibility.
The remaining parts of this class are already implemented and should not be modified to ensure that everything runs smoothly. (The GUI code runs in parallel and requires a consistent state at all times.)
After implementing the getters, you can start uncommenting some code in Moth.java and MothSimulationCanvas.java. (See the // TODO comments in the code.)
6.1.3 Light up the Scene (14 + 16 P)
(a) StaticLamp (b) PulsatingLamp (c) FlickeringLamp
Figure 1: The types of Lamps, we wish to simulate.
To get some variety in our simulation, we use three types of Lamps (see Figure 1). The shared logic of all Lamps such as their ability to attract Mohts with a certain force is already implemented. The function
public final Vec2D computeAttraction(Moth m)
determines the attraction force that the given Lamp inflicts on the given Moth. The getColor() function determines the color in which the lamp will be drawn on the screen and the abstract getBrightness() function needs to be implemented by each derived class to determine how bright the Lamp shines at every single moment. The default for this should be the defaultBrightness
a) Implement the three Lamp classes, where each class shall be public, each class extends the Lamp class, and each class implements a public constructor which takes the parameters float x and float y for the Lamp’s position and passes them through to the super class’s constructor
Lamp(float x, float y).
For the FlickeringLamp, add a private instance of the Flickerer class: private final Flickerer flickerer; and initialize it in your constructor using the Lamp’s position.
b) Implement the public float getBrightness() function for all three classes.
The StaticLamp shines with a constant brightness:
Simply return the defaultBrightness shared by all Lamps.
The PulsatingLamp smoothly goes up and down in brightness:
Call the protected function pulseStrength() of the class Lamp and use the result to scale the defaultBrightness. return the result of their product.
The FlickeringLamp turns on and off at seemingly random times:
Ask your flickerer instance if the Lamp isOn() and return the defaultBrightness or 0 based on the result.
You can now uncomment some code in MothSimulationCanvas.java (search for // TODO), to enable placing new Lamps into the simulation with the buttons provided by the GUI.
6.1.4 Become Moth (10 + 5 + 5 + 10 + 15 P)
We wish to simulate several types of Moths, as shown in Figure 2.
Again, the abstract base class shared by all types of Moths is given. In addition to an x and y position contained in the Vec2D it derives from, it contains its flying direction (describing the rotation in radians where 0 is flying upwards) and speed. For the animation of flapping wings, it also contains a flapCounter, which you don’t need to bother with.
As each Moth is unique, its constructor only takes two floats describing its position in the 2D space and initializes all other class members randomly, including the maxSpeed and maxAcceleration. The maximum
speed and acceleration are constant per Moth and enforced by the given final updatePosition()
function.
Since Moths are also aware of their surroundings, they have the option to search for neighboring Moths using the lookupAccelerator. By default, only a simple brute-force search is performed, which computes the distance to all other Moths in existence. For now, we are satisfied with that and we will look at a better performing alternative in the following task.
a) Implement the three Moth classes. For now, implement the public constructor, passing through the x and y coordinates to the Moth constructor. Also implement the updateForces function as an empty function (for now). We will deal with the specifics of each Moth type shortly.
b) @Override the getColor() function to Color the DeadMoth GRAY and the LampMoth ORANGE, so we can distinguish them more easily. The BoidMoth should already be BLACK by default.
c) Make sure that the DeadMoth does not fly, i.e., it does not move at all. Only modify the DeadMoth class to achieve this.
d) The LampMoth flies towards the Lamp with the strongest attraction force. In the updateForces function, compute the attraction of each Lamp on the LampMoth (use public final Vec2D
Lamp.computeAttraction(Moth m)) and set the LampMoth’s acceleration to the strongest attraction force (the one with the maximum lengthSquared()). If there are no Lamps, there should be no acceleration.
e) The BoidMoth uses Reynold’s Algorithm [?] to simulate swarm behavior as in a flock of birds.
We consider thee forces:
cohesion makes the BoidMoth fly towards nearby Moths.
alignment makes the BoidMoth fly into the same direction as nearby Moths.
separation makes the BoidMoth fly away from other Moths which are too close.
All forces apply only within a limited search radius. The separation force applies within a much smaller search radius. Moths within this radius do not influence the cohesion and alignment forces.
Use the protected function computeBoidForces to compute these forces and also add the attraction
force of every Lamp in the simulation to compute the acceleration of the BoidMoth. (Make sure to check how the functions of the Vec2D class are implemented.)
You can now uncomment some code in MothSimulationCanvas.java (search for // TODO), to enable
placing new Moths into the simulation with the buttons provided by the GUI.