In response to the request here: https://mathematica.stackexchange.com/q/312395
Extends Simon Woods' Boids model with 3D spatial dynamics, velocity-color mapping (Rainbow gradients), inertia-driven coordination (velocity averaging for flock coherence), and universal friend/foe hierarchies enabling emergent leader-follower behavior.
Extends Simon Woods' Boids model with 3D spatial dynamics, velocity-color mapping (Rainbow gradients), inertia-driven coordination (velocity averaging for flock coherence), and universal friend/foe hierarchies enabling emergent leader-follower behavior.
See other parts to this post here:
Boids 2: spherical projection with dynamic viewpoint tracking
Boids 3: periodic domain eliminates edge effects via rectangular lattice projections
Boids 2: spherical projection with dynamic viewpoint tracking
Boids 3: periodic domain eliminates edge effects via rectangular lattice projections
Simon Woods’ original code
Simon Woods’ original code
This is nice and efficient and illustrates how changing a value within a Dynamic creates a loop implicitly.
I’ve renamed the variables to make it easier for readers to see what is going on.
I’ve renamed the variables to make it easier for readers to see what is going on.
In[]:=
numberBoids=1000;randomBoid:=RandomInteger[{1,numberBoids}];boidForceTerm:=(#/(.01+Sqrt[#.#]))&/@(boidLocations[[#]]-boidLocations)&;switchFriendsEnemies:=With[{rb=randomBoid},friend[[rb]]=randomBoid;enemy[[rb]]=randomBoid];boidLocations=RandomReal[{-1,1},{numberBoids,2}];{friend,enemy}=RandomInteger[{1,numberBoids},{2,numberBoids}];
In[]:=
Graphics[{PointSize[0.007],Dynamic[If[randomBoid<100,switchFriendsEnemies];Point[boidLocations=0.995boidLocations+0.02boidForceTerm[friend]-0.01boidForceTerm[enemy]]]},PlotRange->2]
Out[]=
Original code in three dimensions
Original code in three dimensions
It just a simple change of the dimensions of the initial locations:
boidLocations → RandomReal[{-1, 1}, {numberBoids, 3}]
and
Graphics → Graphics3D
boidLocations → RandomReal[{-1, 1}, {numberBoids, 3}]
and
Graphics → Graphics3D
In[]:=
numberBoids=1000;randomBoid:=RandomInteger[{1,numberBoids}];boidForceTerm:=(#/(.01+Sqrt[#.#]))&/@(boidLocations[[#]]-boidLocations)&;switchFriendsEnemies:=With[{rb=randomBoid},friend[[rb]]=randomBoid;enemy[[rb]]=randomBoid];boidLocations=RandomReal[{-1,1},{numberBoids,3}];{friend,enemy}=RandomInteger[{1,numberBoids},{2,numberBoids}];
In[]:=
Graphics3D[{PointSize[0.007],Dynamic[If[randomBoid<100,switchFriendsEnemies];Point[boidLocations=0.995boidLocations+0.02boidForceTerm[friend]-0.01boidForceTerm[enemy]]]},PlotRange->2]
Out[]=
Some additions color the boids and make videos
Some additions color the boids and make videos
A function to draw the boids with colors corresponding to their velocity
In[]:=
boxGraphic=;
Options[drawBoid]={"Velocity Range"->{0.001,0.01},ImageSize->500,PlotRange->2};drawBoid[position_,velocity_,OptionsPattern[]]:=With{colors=ColorData["Rainbow"][Clip[Rescale[#,OptionValue["Velocity Range"]]]]&/@(Norm/@velocity)},Graphics3D{boxGraphic,MapThread[{#1,Sphere[#2,.015]}&,{colors,position}]},
Initialize in a single step and introduce a velocity (to be used later)
In[]:=
Options[initialize]={"Initial Locations"->"Square"};initialize[n_,OptionsPattern[]]:=Module[{},numberBoids=n;boidLocations=Which[OptionValue["Initial Locations"]==="Ball",RandomPoint[Ball[],n],OptionValue["Initial Locations"]==="Sphere",RandomPoint[Sphere[],n],True,RandomReal[{-1,1},{n,3}]];randomBoid:=RandomInteger[{1,n}];{friend,enemy}=RandomInteger[{1,n},{2,n}];boidVelocity=ConstantArray[{0,0,0},n]]
In[]:=
$HistoryLength=1;(*videosarelarge,doingsomememorymanagement*)
Adding colors associated with velocity and making a video from the frames
In[]:=
initialize[1000];Dynamic[If[randomBoid<100,switchFriendsEnemies];drawBoid[boidLocations=0.995boidLocations+0.02boidForceTerm[friend]-0.01boidForceTerm[enemy],boidVelocity,PlotRange->1]]
Out[]=
Notice that the use of the function drawBoid slows down the code compared to Woods’. This is probably from passing variables to the function.
To make animations, I decided to use a loop with Reap/Sow.
Using export is faster than FrameListVideo
You can get the mp4 video here:
Variations on boids
Variations on boids
Making an inertia-like term for the boids motion and using colors to indicate velocity
Making an inertia-like term for the boids motion and using colors to indicate velocity
inertia is simulated by averaging the current and previous velocities :
vMean = 0.5 (vLast + boidVelocity)
The weighting of the averaging gives different effects
vMean = 0.5 (vLast + boidVelocity)
The weighting of the averaging gives different effects
To my eye, the flocks seem to flow in a more coordinated fashion. When the flock stretches out, it seems to be longer and move in a more coordinated fashion.
You can get the mp4 video here:
Adding everyone’s friend
Adding everyone’s friend
One boid is identified as everyone’s friend.
Also, repositioning to put mean position at center of graphic
Also, repositioning to put mean position at center of graphic
more frames... about 5 minutes to make the video
The flock motion has more correlation.
You can get the mp4 video here:
Some variations on this would be to select several “universal friends”
Some variations on this would be to select several “universal friends”
This is a trivial extension of the code. Create n lists of universal friends and then for the motion associated with them:
Total[boidForceTerm /@ everyonesFriend]
Total[boidForceTerm /@ everyonesFriend]
You can get the mp4 video here:
CITE THIS NOTEBOOK
CITE THIS NOTEBOOK
Boids 1: 3D dynamics, velocity-color mapping, and inertia-driven coordination
by W. Craig Carter
Wolfram Community, STAFF PICKS, June 24, 2025
https://community.wolfram.com/groups/-/m/t/3485008
by W. Craig Carter
Wolfram Community, STAFF PICKS, June 24, 2025
https://community.wolfram.com/groups/-/m/t/3485008