Attracting particles (ionic bonding?)

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  

@Tmon I found this very interesting. I’ll have to look thru your code when I have some time to see what’s actually happening. Good job and I’m looking forward to seeing more code from you.

@Tmon this is good keep it up! I had loads of fun getting different shapes on the go.

Cool. I’ll look closer at it when I have time.

Thanks for the positive thoughts! I’m a novice at this but am enjoying finding out how Lua and Codea work.

@Tmon When I was watching this, some of the objects were showing an orbital motion around each other. That reminded me of the code I posted long ago showing 2 and 3 body orbits.

Yes - it’s nice the way orbital attraction comes naturally out of combining velocity with another vector. I’m not sure I like the way clusters spin faster and faster at times until they separate and a bit of angularDamping may make it more ‘realistic’. Fun to watch though!

I always like how a simple set of rules can make a complex system, just like Conway’s Game of Life.