Fish
The fish are essentially extra particles in the fluid dynamics simulation that do not get removed after some time. Their position is calculated by MSAFluid. The rotation uses the velocity of the particle. Let's look into more about how this was done.
Rotation
The first part on figuring this out was to determine the angle that the fish should be. By using the velocity vector and the atan2 function, we can get the angle.
fishAngle[i] = atan2(particleSystem.fishParticles[i].vy, particleSystem.fishParticles[i].vx);
This is great, now that we have the angle. But as for actually rotating the image, we have to apply some transformations. Here is the core of that code:
pushMatrix();
translate(width/2, height/2);
translate(-width/2+particleSystem.fishParticles[i].x, -height/2+particleSystem.fishParticles[i].y);
//rotate(radians(mouseY));
//rotate(counter*TWO_PI/360);
if(abs(particleSystem.fishParticles[i].vy) >= 1.0 || abs(particleSystem.fishParticles[i].vx) >= 1.0) {
fishAngle[i] = atan2(particleSystem.fishParticles[i].vy, particleSystem.fishParticles[i].vx);
}
rotate(fishAngle[i]);
image(fishImg[i],0,0);
translate(-fishImg[i].width/2, -fishImg[i].height/2);
popMatrix();
How does this work? Well,
pushMatrix() and
popMatrix are used so that the transformations that are applied in between them, do not effect the rest of the sketch. To read more about this, check out
this article.
We have to move the entire grid to the origin, and adjust for the image position as well. This way when we apply the rotate with the angle, the image will be rotated about the origin. If we did not do the transformations before the rotation, the rotation would not be about the right point- causing it to look like a 'wide turn'.
After the rotation occurs, we can draw the image, and translate the grid once more for some final adjustments. Then popMatrix will restore the grid back to its original position.
Near Tail
The next aspect of the fish to discuss is how we determine if they are near Botbait's tail or not. It's not exactly magic- we assume that Botbait's tail is positioned in the middle of the screen, and that there is a certain area extending from the middle where they would be near the tail.
This is how their position is checked:
void checkForFishies() {
int count = 0;
for(int i=0; i= 0.5-0.25 && fishNormX <= 0.5+0.25) {
count++;
}
}
if(count >= 0 && millis()-lastFishCountSend >= 1000) {
if(connected) sendSerial(fishNumSerial, count);
lastFishCountSend = millis();
}
}
We normalize the X position so that it is easier to check for on multiple screen dimensions. We only send the message to the Arduino every 1 second, to avoid spamming it.
---
That is about it for the fishes! There are so many more things that you can make the fish do... some ideas are: making them blink, change sizes, colours, even blow bubbles.