# Need help with how to reference individual Boid

Hi, everyone!

Let me first introduce myself.
Im currently pursuing my cs degree. My Java skills are still on amateur level.
I kinda know OOP and some of the basic stuff. Basically I can read and write code if its not too complex.
Through the task that was assigned to me, I stumbled upon JMonkeyEngine and I think its great.
Therefore I want to make my own little game with JMonkeyEngine to practice and contribute here.
Unfortunately I need some more english lessons but I will try my hardest to be precise.

Now to the task:
We need to implement a â€śsimpleâ€ť swarm algorithm with the following rules in JMonkeyEngine:

1. Alignment
2. Separation
3. Cohesion

We know some vector math but we dont know how to reference one SINGLE Boid to atleast implement a separation.

After several hours researching, trial and error I have to admit, I am lost.

Q: How do I reference 1 individual Boid if I want to separate two Boids ?

What I tried:

1. Convert the rules of this Javascript code to Java but didnt worked. : /
Flocking / Examples / Processing.org

2. I Rewrote the code several times to get a grasps on how to reference the boids individually. Didnt succeed. Heres the coded of one of the attempts.

/**
* The update method should be called once per frame
*
* @param dtime determines the elapsed time in seconds (floating-point)
* between two consecutive frames
*/
public void update(float dtime) {

for (Boid boid : boids) {

Vector3f netAccelarationForBoid = boid.position.negate();

Vector3f Boid1 = new Vector3f(boid.position.x, boid.position.y, boid.position.z);
Vector3f Boid2 = new Vector3f(boid.position.x, boid.position.y, boid.position.z);

float boid1Length = Boid1.length();
float boid2Length = Boid2.length();

Vector3f distanceOrigin = Boid1.subtract(Boid2);

System.out.println("angle from Boid1 to Boid2 = " + Boidrad);
System.out.println("distance from Boid1 to Boid2 = " + distanceOrigin);

if(boid != boids && Boidrad > 45){
System.out.println("test");
}

boid.update(netAccelarationForBoid, dtime);
}
}

Of all of the millions of interpretations of that phrase, which one applies in your case?

ie: What do you mean by â€śdidnâ€™t succeedâ€ť? Computer exploded? Program crashed? Boids flew out of the screen and into the sky? Didnâ€™t compile?

My attempt to convert the code from javascript to Java didnt work.

Yeah, thatâ€™s probably a big job for someone just learning Java.

Why not keep it in Javascript for your assignment and then work your way up to Java on your own time?

Because we have to use Java and JMonkeyEngine for this task specificaly.
We are not allowed to use other languages.

In the worst case, I will fail the deadline(10 days left) but I will solve the problem somehow anyway.
I will provide the solution here afterwards.

Thats still a little unclear. Do you mean it didnâ€™t compile? Or compiled but didnâ€™t work as expected. If so how?

(Looking at your example though i wouldnt expect it to work as netAccelarationForBoid seems to be exclusively the reverse of the position, ignoring all your distance calculations).

I think we may need to see more of the code as well. I have too many questions as it stands

Processing uses Java, not javascript.

From wikipedia:

@richtea

Thats still a little unclear. Do you mean it didnâ€™t compile?
Or compiled but didnâ€™t work as expected. If so how? (Looking at your example though i wouldnt expect it to work as netAccelarationForBoid seems to be exclusively the reverse of the position, ignoring all your distance calculations).
I think we may need to see more of the code as well. I have too many questions as it stands

Thank you richtea for reaching out!

Heres the vanilla code:

Main.java

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Mesh;
import com.jme3.scene.shape.Box;

/**
* This is the Main Class of your Game. You should only do initialization here.
*/

public class Main extends SimpleApplication {

private Flock flock;
private final int boidCount = 1;

public static void main(String[] args) {
Main app = new Main();
app.start();
}

@Override
public void simpleInitApp() {

Mesh mesh = new Box(0.01f, 0.01f, 0.03f); // the geometric model of one boid. Here a cube of size=(x:0.01,y:0.01,z:0.03)

Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); // the surface material for the geometric boid model.
mat.setColor("Color", ColorRGBA.Green);

// instantiation of the flock
flock = new Flock(rootNode, boidCount, mesh, mat );

// camera rotation is controlled via mouse movement while the position is controlled via wasd-keys
flyCam.setEnabled(true);
flyCam.setMoveSpeed(20);
}

@Override
public void simpleUpdate(float tpf) {
flock.update(tpf); // called once per frame
}

@Override
public void simpleRender(RenderManager rm) {
// add here custom rendering stuff if needed
}
}

Flock.java

/*
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mygame;

import com.jme3.math.FastMath;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.instancing.InstancedNode;
import java.util.ArrayList;
import java.util.List;

/**
* This class controls and manages all boids within a flock (swarm)
*/
public class Flock {

private Material boidMaterial;
private Mesh boidMesh;
private Node scene;
private InstancedNode instancedNode;
private List<Boid> boids;

/**
*
* @param scene a reference to the root node of the scene graph (e. g.
* rootNode from SimpleApplication).
* @param boidCount number of boids to create.
* @param boidMesh reference mesh (geometric model) which should be used for
* a single boid.
* @param boidMaterial the material controls the visual appearance (e. g.
* color or reflective behavior) of the surface of the boid model.
*/
public Flock(Node scene, int boidCount, Mesh boidMesh, Material boidMaterial) {

this.boidMesh = boidMesh;
this.boidMaterial = boidMaterial;
this.scene = scene;

this.boidMaterial.setBoolean("UseInstancing", true);
this.instancedNode = new InstancedNode("instanced_node");
this.scene.attachChild(instancedNode);

boids = createBoids(boidCount);

instancedNode.instance();

}

/**
* The update method should be called once per frame
*
* @param dtime determines the elapsed time in seconds (floating-point)
* between two consecutive frames
*/
public void update(float dtime) {

for (Boid boid : boids) {

// netAccelaration should be a linear combination of
// separation,
// alignment,
// cohesion, and
// further forces..
// accelaration=boid.position.negate()) means that there is a permanent acceleration towards the origin of the coordinate system (0,0,0) which decreases if the distance of the boid to origin decreases.

Vector3f netAccelarationForBoid = boid.position.negate();

boid.update(netAccelarationForBoid, dtime);

}
}

/**
* Creates a list of Boid objects and adds corresponding instanced models
* (based on boidMesh) to the scene graph
*
* @param boidCount The number of boids to create
* @return A list of Boid objects. For each object a corresponding instanced
* geometry is added to the scene graph (Boid.geometry)
*/
private List<Boid> createBoids(int boidCount) {
List<Boid> boidList = new ArrayList<Boid>();

for (int i = 0; i < boidCount; i++) {
Boid newBoid = new Boid(createInstance());

}
return boidList;
}

/**
* Creates an instanced copy of boidMesh using boidMaterial with individual
* geometric transform
*
* @return The instanced geometry attached to the scene graph
*/
private Geometry createInstance() {
Geometry geometry = new Geometry("boid", boidMesh);
geometry.setMaterial(boidMaterial);
instancedNode.attachChild(geometry);
return geometry;
}

}

Boid.java

/*
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mygame;

import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;

/**
* Boid represents one individual boid in the flock.
* It's motion is integrated within the update method, which should be called once per frame.
*/
public class Boid {
public static float spawnVolumeSize = 5.0f;
public Vector3f position;
public Vector3f velocity;
private Geometry geometry;

/**
* The constructor instantiates a Boid a random position p within -spawnVolumeSize/2 <= p <= spawnVolumeSize/2.
* The initial velocity is set to random 3D-vector with a magnitude of one.
* @param geom corresponds to a geometry object within the scene graph and has to exist.
*/
public Boid(Geometry geom) {
this.geometry = geom;
velocity = new Vector3f();
position = new Vector3f();
position.x = (FastMath.nextRandomFloat() -0.5f) * spawnVolumeSize;
position.y = (FastMath.nextRandomFloat() -0.5f) * spawnVolumeSize;
position.z = (FastMath.nextRandomFloat() -0.5f) * spawnVolumeSize;

velocity.x = (FastMath.nextRandomFloat() -0.5f);
velocity.y = (FastMath.nextRandomFloat() -0.5f);
velocity.z = (FastMath.nextRandomFloat() -0.5f);
velocity.normalizeLocal();

}

/**
* update calculates the new position of the Boid based on its current position and velocity influenced by accelaration. update should be called once per frame
* @param accelaration The net accelaration of all forces that influence the boid
* @param dtime The elapsed time in seconds between two consecutive frames
*/
public void update(Vector3f accelaration, float dtime)
{
//integrate velocity: v = v + a*dt; keep in mind: [m/s^2 * s = m/s]
//integrate position: p = p + v*dt; keep in mind: [m/s * s = m]

//update scene instance
geometry.setLocalTranslation(position);
}
}

MODIFIED CODE
Only Flock.java been modified

Idea 1

/*
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mygame;

import com.jme3.math.FastMath;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.instancing.InstancedNode;
import java.util.ArrayList;
import java.util.List;

/**
* This class controls and manages all boids within a flock (swarm)
*
*/
public class Flock {

private Material boidMaterial;
private Mesh boidMesh;
private Node scene;
private InstancedNode instancedNode;
private List<Boid> boids;

/**
*
* @param scene a reference to the root node of the scene graph (e. g.
* rootNode from SimpleApplication).
* @param boidCount number of boids to create.
* @param boidMesh reference mesh (geometric model) which should be used for
* a single boid.
* @param boidMaterial the material controls the visual appearance (e. g.
* color or reflective behavior) of the surface of the boid model.
*/
public Flock(Node scene, int boidCount, Mesh boidMesh, Material boidMaterial) {

this.boidMesh = boidMesh;
this.boidMaterial = boidMaterial;
this.scene = scene;

this.boidMaterial.setBoolean("UseInstancing", true);
this.instancedNode = new InstancedNode("instanced_node");
this.scene.attachChild(instancedNode);

boids = createBoids(boidCount);

instancedNode.instance();

}

/**
* The update method should be called once per frame
*
* @param dtime determines the elapsed time in seconds (floating-point)
* between two consecutive frames
*/
public void update(float dtime) {

for (Boid boid : boids) {

// netAccelaration should be a linear combination of
// separation,
// alignment,
// cohesion, and
// further forces..
// accelaration=boid.position.negate()) means that there is a permanent acceleration towards the origin of the coordinate system (0,0,0) which decreases if the distance of the boid to origin decreases.

Vector3f netAccelarationForBoid = boid.position.add(boid.position.x, boid.position.y,boid.position.z).negate(); // accelaration=boid.position.negate()) means that there is a permanent acceleration towards the origin of the coordinate system (0,0,0) which decreases if the distance of the boid to origin decreases.
float lengthOfAccel = netAccelarationForBoid.add(netAccelarationForBoid).length();

Vector3f Vector1 = boid.position.add(boid.position.x, boid.position.y,boid.position.z);
float lengthOfVec1 = Vector1.add(Vector1).length();

Vector3f Vector2 = boid.position.add(boid.position.x, boid.position.y,boid.position.z);
float lengthOfVec2 = Vector2.add(Vector2).length();

float DistanceBetweenVec1AndAccel = Vector1.distance(netAccelarationForBoid);
float DistanceBetweenAccelAndVec1 = netAccelarationForBoid.distance(Vector1);

float radiant1 = boid.position.angleBetween(netAccelarationForBoid);
float radiant2 = boid.position.angleBetween(Vector2);

Vector3f accelInterpol = netAccelarationForBoid.interpolateLocal(netAccelarationForBoid, Vector1, 0.03f);

if(boid != boids && DistanceBetweenVec1AndAccel <= radiantResult && DistanceBetweenAccelAndVec1 <= radiantResult){

boid.position.subtract(netAccelarationForBoid, Vector2);

}

boid.update(netAccelarationForBoid, dtime);

}
}

/**
* Creates a list of Boid objects and adds corresponding instanced models
* (based on boidMesh) to the scene graph
*
* @param boidCount The number of boids to create
* @return A list of Boid objects. For each object a corresponding instanced
* geometry is added to the scene graph (Boid.geometry)
*/
private List<Boid> createBoids(int boidCount) {
List<Boid> boidList = new ArrayList<Boid>();

for (int i = 0; i < boidCount; i++) {
Boid newBoid = new Boid(createInstance());

}

return boidList;

}

/**
* Creates an instanced copy of boidMesh using boidMaterial with individual
* geometric transform
*
* @return The instanced geometry attached to the scene graph
*/
private Geometry createInstance() {
Geometry geometry = new Geometry("boid", boidMesh);
geometry.setMaterial(boidMaterial);
instancedNode.attachChild(geometry);
return geometry;
}

}

Idea 2
Here I tried to rewrite the code on processing.org

/*
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mygame;

import com.jme3.math.FastMath;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.instancing.InstancedNode;
import java.util.ArrayList;
import java.util.List;

/**
* This class controls and manages all boids within a flock (swarm)
*
*/
public class Flock {

private Material boidMaterial;
private Mesh boidMesh;
private Node scene;
private InstancedNode instancedNode;
private List<Boid> boids;

/**
*
* @param scene a reference to the root node of the scene graph (e. g.
* rootNode from SimpleApplication).
* @param boidCount number of boids to create.
* @param boidMesh reference mesh (geometric model) which should be used for
* a single boid.
* @param boidMaterial the material controls the visual appearance (e. g.
* color or reflective behavior) of the surface of the boid model.
*/
public Flock(Node scene, int boidCount, Mesh boidMesh, Material boidMaterial) {

this.boidMesh = boidMesh;
this.boidMaterial = boidMaterial;
this.scene = scene;

this.boidMaterial.setBoolean("UseInstancing", true);
this.instancedNode = new InstancedNode("instanced_node");
this.scene.attachChild(instancedNode);

boids = createBoids(boidCount);

instancedNode.instance();

}

/**
* The update method should be called once per frame
*
* @param dtime determines the elapsed time in seconds (floating-point)
* between two consecutive frames
*/
public void update(float dtime) {

for (Boid boid : boids) {

// netAccelaration should be a linear combination of
// separation,
// alignment,
// cohesion, and
// further forces..
// accelaration=boid.position.negate()) means that there is a permanent acceleration towards the origin of the coordinate system (0,0,0) which decreases if the distance of the boid to origin decreases.

Vector3f netAccelarationForBoid = boid.position.add(boid.position.x, boid.position.y,boid.position.z).negate();

Vector3f BoidPositionVector = boid.position.add(boid.position.x, boid.position.y,boid.position.z);
float lengthOfBoidPositionVector = BoidPositionVector.length();

float subtractionOfBoidPosVectorAndAccelVector = BoidPositionVector.subtract(netAccelarationForBoid).length();

float distanceBetweenVector1AndNetAccel = BoidPositionVector.distance(netAccelarationForBoid);

float radiant = boid.position.angleBetween(netAccelarationForBoid);

if(boid != boids && subtractionOfBoidPosVectorAndAccelVector < radiant){
Vector3f diff = boid.position.subtract(netAccelarationForBoid, BoidPositionVector);
}

boid.update(netAccelarationForBoid, dtime);

}
}

/**
* Creates a list of Boid objects and adds corresponding instanced models
* (based on boidMesh) to the scene graph
*
* @param boidCount The number of boids to create
* @return A list of Boid objects. For each object a corresponding instanced
* geometry is added to the scene graph (Boid.geometry)
*/
private List<Boid> createBoids(int boidCount) {
List<Boid> boidList = new ArrayList<Boid>();

for (int i = 0; i < boidCount; i++) {
Boid newBoid = new Boid(createInstance());

}

return boidList;

}

/**
* Creates an instanced copy of boidMesh using boidMaterial with individual
* geometric transform
*
* @return The instanced geometry attached to the scene graph
*/
private Geometry createInstance() {
Geometry geometry = new Geometry("boid", boidMesh);
geometry.setMaterial(boidMaterial);
instancedNode.attachChild(geometry);
return geometry;
}

}

Idea 3
Here I tried to rewrite the code on processing.org

/*
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mygame;

import static mygame.Boid.spawnVolumeSize;
import com.jme3.math.FastMath;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.instancing.InstancedNode;
import java.util.ArrayList;
import java.util.List;

/**
* This class controls and manages all boids within a flock (swarm)
*
*/
public class Flock {

private Material boidMaterial;
private Mesh boidMesh;
private Node scene;
private InstancedNode instancedNode;
private List<Boid> boids;
private Vector3f position;
private Vector3f velocity;

/**
*
* @param scene a reference to the root node of the scene graph (e. g.
* rootNode from SimpleApplication).
* @param boidCount number of boids to create.
* @param boidMesh reference mesh (geometric model) which should be used for
* a single boid.
* @param boidMaterial the material controls the visual appearance (e. g.
* color or reflective behavior) of the surface of the boid model.
*/
public Flock(Node scene, int boidCount, Mesh boidMesh, Material boidMaterial) {

this.boidMesh = boidMesh;
this.boidMaterial = boidMaterial;
this.scene = scene;

this.boidMaterial.setBoolean("UseInstancing", true);
this.instancedNode = new InstancedNode("instanced_node");
this.scene.attachChild(instancedNode);

position = new Vector3f();
position.x = (FastMath.nextRandomFloat() - 0.5f) * spawnVolumeSize;
position.y = (FastMath.nextRandomFloat() - 0.5f) * spawnVolumeSize;
position.z = (FastMath.nextRandomFloat() - 0.5f) * spawnVolumeSize;

boids = createBoids(boidCount);

instancedNode.instance();

}

Vector3f seek(Vector3f target) {
float maxspeed = 50.5f;

for (Boid boid : boids) {

Vector3f desired = boid.position.subtract(target, position);
desired.normalize();
desired.mult(maxspeed);

boid.position.subtract(desired, velocity);
//System.out.println("test = " + steer);

}
return target;
}

Vector3f separation(Vector3f v) {
float maxspeed = 2.5f;
float prefSeperation = 2.0f;
Vector3f steer = new Vector3f(0, 0, 0);
int boidsCountNearby = 0;

for (Boid other : boids) {
Vector3f boidVector = other.position.add(6, 6, 4);
float distanceVector = other.position.distance(boidVector);
//System.out.println("testDISTANCE =" + distanceVector);
//System.out.println("testPREF =" + prefSeperation);
//System.out.println("testDISVECTOR =" + distanceVector);

if ((distanceVector > 0) && (distanceVector > prefSeperation)) {
Vector3f difference = other.position.add(other.position.x, other.position.y, other.position.z).subtract(position.x, position.y, position.z);
Vector3f normalizedDiff = boidVector.normalize();
boidVector.divide(distanceVector);
boidsCountNearby++;
//System.out.println("testBOIDCOUNT =" + boidsCountNearby);
}

}

if (boidsCountNearby > 0) {
steer.divide((float) boidsCountNearby);

}

if (steer.length() > 0) {
steer.normalize();
steer.subtract(velocity);
steer.mult(maxspeed);

}

return steer;

}

Vector3f cohesion(Vector3f v) {
float neighbordist = 2;
Vector3f sum = new Vector3f(0, 0, 0);
int count = 0;

for (Boid other : boids) {
Vector3f boidVector = other.position.add(20, 50, 40);
float distanceVector = other.position.distance(boidVector);

if ((distanceVector > 0) && (distanceVector > neighbordist)) {
count++;
}
}

if (count > 0) {
sum.divide(count);
return seek(sum);
} else
{
return new Vector3f(0, 0, 0);

}
}

/**
* The update method should be called once per frame
*
* @param dtime determines the elapsed time in seconds (floating-point)
* between two consecutive frames
*/
public void update(float dtime) {

for (Boid boid : boids) {

// netAccelaration should be a linear combination of
// separation,
// alignment,
// cohesion, and
// further forces..
// accelaration=boid.position.negate()) means that there is a permanent acceleration towards the origin of the coordinate system (0,0,0) which decreases if the distance of the boid to origin decreases.

Vector3f netAccelarationForBoid = boid.position.negate();
separation(netAccelarationForBoid);
cohesion(netAccelarationForBoid);

boid.update(netAccelarationForBoid, dtime);

}
}

/**
* Creates a list of Boid objects and adds corresponding instanced models
* (based on boidMesh) to the scene graph
*
* @param boidCount The number of boids to create
* @return A list of Boid objects. For each object a corresponding instanced
* geometry is added to the scene graph (Boid.geometry)
*/
private List<Boid> createBoids(int boidCount) {
List<Boid> boidList = new ArrayList<Boid>();

for (int i = 0; i < boidCount; i++) {
Boid newBoid = new Boid(createInstance());

}

return boidList;

}

/**
* Creates an instanced copy of boidMesh using boidMaterial with individual
* geometric transform
*
* @return The instanced geometry attached to the scene graph
*/
private Geometry createInstance() {
Geometry geometry = new Geometry("boid", boidMesh);
geometry.setMaterial(boidMaterial);
instancedNode.attachChild(geometry);
return geometry;
}

}

@xuan Oh, thanks alot! I was overworked and didnt realized that.
I will look into Processing after my Boid task! It looks interesting!

Note: it seems like you are only paying attention to one Boid at a time.

All of separation, alignment, and cohesion require looking at the rest of the flock to calculate.

Additionally, itâ€™s been a long time since Iâ€™ve done a Boids simulation but I remember â€śsteeringâ€ť being critical to making the simulation look natural. ie: the boids linear velocity is pretty much constant and the separation, alignment, and so on only affect the rotation.

I do not know what you started with and what you are required to do yourself so I donâ€™t want to provide too many more details at risk of doing your homework for you. But those should be some hints at least.

For each Boid, the rest of the flock will influence its steering direction.

1 Like

Thank you very much for your fast reply, @pspeed !

I want to solve this with my team or for my team.

My Question was

and not to explain concepts we already know.
If somebody explained to me how to reference a single boid it would be enough and we still had to do the main calculations ourselves. I gave you guys context but didnt asked to solve the whole thing.
Why ask something in the first place if everybody assumes the questioner dont want to work ? Thats why some peers and me hesitate to ask on forums btw. but thats a different topic.

If that is true and I understand you correctly, maybe I know how to solve this and I didnt understood that I already referenced one Boid and not the whole flock. Thats what I wanted.
Can you post my code snipped or where you got your idea from ?

Do you now know what a for loop does?

for (Boid boid : boids) {

executes everything in the { block once for every single individual Boid in the boids list.

So each pass of the loop is addressing just one Boid.

Itâ€™s the same as if you did:

for( int i = 0; i < boids.size(); i++ ) {
Boid boid = boids.get(i);
}

But maybe Iâ€™m still misunderstanding you because thatâ€™s super beginner Java stuff.

2 Likes

Looking at the flocking boids algorithm it looks like each boid is affected by every other boid. So Iâ€™d expect something like this

for (Boid boidBeingAffected: boids) {
}

Here you can see each individual single boid being referenced individually in turn (loaded into variable boidBeingAffected. Then the boid is being asked to update its heading based on the entire flocks position (inside updateHeadingBasedOnFlock there will likely be another loop over all boids).

I think youâ€™re struggling with some concepts I struggled with myself early doors. There isnâ€™t some variable for boid number 1 and boid number 2 etc. There are just a list of boids and you can ask for the first one and temporarily load it into a variable, then ask for the second one and load that into the same variable. If you want to reference two boids at the same time you need two variables. E.g.

for (Boid boidBeingAffected: boids) {
for (Boid boidCausingAffect: boids) {
//boidCausingAffect affects boidBeingAffected
}
}

However I donâ€™t think the flocking boids algorithm works like that exactly so donâ€™t use that loop within a loop too literally for this exercise

1 Like