Genuary 2022: trade styles with a friend​
​by Sander Huisman
Each year there are several challenges for generative arts in the month January called “Genuary” ( https://genuary.art/prompts ). For this #genuary 2022, I envisioned a box of balls colliding, at each collision swap some style element of the ball.
We define the size and the force that the wall exerts:
SetDirectory[NotebookDirectory[]];​​size=600;​​ClearAll[ForceWall,DoStep,BounceBall,ShowScene]​​ForceWall[z_,r_]:=20If[Abs[z]>1-r,(1-Abs[z]-r)Sign[z],0]
Define what to do in each step:
DoStep[state_List,δt_]:=Module[{new,a,len,overlapbefore,overlapafter,poss,styles,ri},​​overlapbefore=Table[Boole[Norm[s["p"]-r["p"]]-s["r"]-r["r"]<0],{s,state},{r,state}];​​new=state;​​len=Length[new];​​new[[All,"p"]]+=new[[All,"v"]]δt;​​a=ConstantArray[{0,0},Length[state]];​​a=Table[ForceWall[#,n[["r"]]]&/@n[["p"]],{n,new}];​​a+=Table[Total@Table[BounceBall[new[[s1i]],new[[s2i]]],{s2i,DeleteCases[Range[len],s1i]}],{s1i,len}];​​new[[All,"v"]]+=aδt;​​(*Allthisstuffistocheckifitchangesfromnon-overlappingtooverlapping,andifsoswapsomestyleelement*)​​overlapafter=Table[Boole[Norm[s["p"]-r["p"]]-s["r"]-r["r"]<0],{s,new},{r,new}];​​overlapafter-=overlapbefore;​​overlapafter//=Abs;​​overlapafter//=UpperTriangularize[#,1]&;​​poss=Position[overlapafter,1,{2}];​​Do[​​styles=new[[p,"style"]];​​styles//=Transpose;​​ri=RandomInteger[{1,2}];​​styles[[ri]]//=Reverse;​​styles//=Transpose;​​new[[p,"style"]]=styles;​​,​​{p,poss}​​];​​new​​]
Define the force that ball 1 receives in the presence of ball 2 (nothing if the distance is too large)
BounceBall[s1_Association,s2_Association]:=Module[{diff,d},​​diff=s1["p"]-s2["p"];​​d=Norm[diff]-s1["r"]-s2["r"];​​If[d<0,​​-5Normalize[diff]d​​,​​{0,0}​​]​​]
Draw the scene and rasterize is:
ShowScene[state_]:=Module[{g},​​g=Graphics[{​​Style[Disk[#["p"],#["r"]],#["style"]]&/@state,​​FaceForm[],EdgeForm[White],​​Rectangle[{-1,-1},{1,1}]},​​PlotRange1.2,​​ImageSize2size,​​BackgroundRGBColor[0.,0.21,0.46]​​];​​Rasterize[g,"Image",RasterSizesize,ImageSizesize]​​]
Create some random state, iterate it, and save some of the images
SeedRandom[1234];​​state=Table[<|​​"p"->RandomReal[{-0.5,0.5},2],​​"v"->RandomReal[{-0.1,0.1},2],​​"r"->0.1,​​"style"->{EdgeForm[{AbsoluteThickness[3],RandomColor[]}],FaceForm[RandomColor[]]}​​|>,​​{15}​​];​​imgs=Table[state=DoStep[state,0.05];If[Mod[i,3]==0,ShowScene[state],{}],{i,600}];​​imgs=imgs[[3;;;;3]];
Export the images to a gif:
In[]:=
Export["2022_6.gif",imgs,"DisplayDurations"->1/60]
Out[]=
2022_6.gif