Here’s a short model for ionic bonding, with thanks to all the people offering ideas and help on the forum.
I’m sure this could be improved by someone, but it was interesting to write and I was delighted when it suddenly worked. There are a lot of distances and vectors being worked out and I’m sure that there are many ways of making it more efficient but this is what I managed.
To make the particles bond, lower the restitution and increase the attraction constant. A bit of gravity helps them to come together quicker.
--multiple collision:(parameterised)
--Unlike particles attract, like particles repel - IONIC BONDING MODEL
function setup()
--displayMode(FULLSCREEN)
physics.iterations(8,8)
--set up walls in the setup function
w1 = physics.body(EDGE,vec2(0,0),vec2(WIDTH,0),1)
w2 = physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT),1)
w3 = physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT),1)
w4 = physics.body(EDGE,vec2(0,HEIGHT),vec2(WIDTH,HEIGHT),1)
--The functions below make 'sliders' to control variables
parameter.number("restitution",0,1,1)
parameter.number('friction',0,10,0)
parameter.number("gravity_sensitivity",0,0.5,0)
parameter.number("attraction_constant",0,30,0)
parameter.color("CircleColor1", color(95,63,31,255))
parameter.color("CircleColor2", color(165,165,24,255))
parameter.color("CircleColor3", color(30,130,43,255))
-- the next two lines set up empty tables for the three sets of balls
p_ball={} --first type
p_ball2={} --second type
p_ball3={} --third, touch, type
--below are the parameters for the ball types
loop=20--number of p_balls
ball_diam=15
lv=-100 --lower velocity
uv=100 --upper velocity
loop2 =20 --number of p_ball2s
loop3 = 0 --loop3 sets the initial number of touches to 0
--the loop below makes each p_ball an (invisible) physics object then ascribes various parameters to each item 'i' in the p_ball table
for i=1,loop do
p_ball[i]=physics.body(CIRCLE, ball_diam/2)
p_ball[i].interpolate=true
p_ball[i].x=math.random(ball_diam, WIDTH-ball_diam)
p_ball[i].y=math.random(ball_diam ,HEIGHT-ball_diam)
p_ball[i].linearVelocity=vec2(math.random(lv,uv),(math.random(lv,uv)))
end
--the loop2 below makes each p_ball2 an (invisible) physics object then ascribes various parameters to each item 'j' in the p_ball2 table
for j=1,loop2 do
p_ball2[j]=physics.body(CIRCLE,ball_diam/2)
p_ball2[j].interpolate=true
p_ball2[j].x=math.random(ball_diam, WIDTH-ball_diam)
p_ball2[j].y=math.random(ball_diam, HEIGHT-ball_diam)
p_ball2[j].linearVelocity=vec2(math.random(lv,uv),(math.random(lv,uv)))
end
end -- ends setup function
--The function below is called every time a touch occurs. It adds the touch to the p_ball3 table, containing all circles created by touches
function touched(touch)
if touch.state == ENDED then
loop3 = loop3 + 1
p_ball3[loop3]=physics.body(CIRCLE,ball_diam/2)
p_ball3[loop3].interpolate=true
p_ball3[loop3].x=touch.x
p_ball3[loop3].y=touch.y
p_ball3[loop3].linearVelocity=vec2(80*touch.deltaX,80*touch.deltaY)
table.insert(p_ball3,p_ball[loop3]) --adds this ball to the table p_ball3
end -- of if statement
end -- of touched
function draw()
physics.gravity(Gravity) -- sets and updates ipad gravity vectors
background(255, 255, 255, 0)
pushStyle() -- this block draws a visible circle onto the first invisible p_ball physics object
for i=1,loop do
p_ball[i].restitution=restitution
p_ball[i].friction=friction
p_ball[i].gravityScale=gravity_sensitivity
fill(CircleColor1) -- CircleColor variable comes from the parameter slider
ellipse(p_ball[i].x,p_ball[i].y,ball_diam) end
popStyle()
pushStyle() -- this draws the second ball type, p_ball2
fill(CircleColor2)
for j=1,loop2 do
p_ball2[j].gravityScale=gravity_sensitivity
p_ball2[j].restitution=restitution
p_ball2[j].friction=friction
ellipse(p_ball2[j].x,p_ball2[j].y,ball_diam) end
popStyle()
pushStyle() -- this block draws the last touched p_ball3 physics object
for k=1,loop3 do
p_ball3[k].restitution=restitution
p_ball3[k].friction=friction
p_ball3[k].gravityScale=gravity_sensitivity
fill(CircleColor3)
ellipse(p_ball3[k].x,p_ball3[k].y,ball_diam)
popStyle()
end
--attraction code p_ball to p_ball2
for j=1,loop do
for k=1,loop2 do
--'pointer' below works out the vector from pball to pball2
pointer=vec2((p_ball[j].x-p_ball2[k].x),(p_ball[j].y-p_ball2[k].y))
--'FVector' divides the value of 'pointer' by the squared distance between the balls
FVector=-(pointer/(pointer:len()^2))
--then we apply Fvector to p_ball
p_ball[j]:applyForce(FVector*attraction_constant*ball_diam)
-- so -FVector gives the attraction vector form pball2 to pball
p_ball2[k]:applyForce(-FVector*attraction_constant*ball_diam)
end --of for k=
end --of for j=
--repulsion code for p_ball to p_ball
--deals with 'ball to itself' distances by saying any vector less than one diameter=0
for t=1,loop do
for u=1,loop do
pointer2=vec2((p_ball[t].x-p_ball[u].x),(p_ball[t].y-p_ball[u].y))
if pointer2:len()<ball_diam then pointer2=vec2(0,0)
else pointer2=vec2((p_ball[t].x-p_ball[u].x),(p_ball[t].y-p_ball[u].y))
FVector2=(pointer2/pointer2:len()^2)
p_ball[t]:applyForce(FVector2*attraction_constant*ball_diam) end
end --of for u=
end --of for t=
--repulsion code for p_ball2 to p_ball2
for v=1,loop2 do
for w=1,loop2 do
pointer3=vec2((p_ball2[v].x-p_ball2[w].x),(p_ball2[v].y-p_ball2[w].y))
if pointer3:len()<ball_diam then pointer3=vec2(0,0)
else pointer3=vec2((p_ball2[v].x-p_ball2[w].x),(p_ball2[v].y-p_ball2[w].y))
FVector3=(pointer3/pointer3:len()^2)
p_ball2[v]:applyForce(FVector3*attraction_constant*ball_diam) end
end --of for w=
end --of for v=
end