#### Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

# Codea is a perfect match for this...

Posts: 3,295

who wants to try this first?

Dave?

• edited January 2019 Posts: 7,949

@Jmv38 Nice little demo. I’ll watch the whole thing when I have more time.

• edited January 2019 Posts: 3,295

@dave1707 the video is not from me. And i have not written the code, i just noticed it is very easy to implement with Codea.

• Posts: 7,949

@Jmv38 After watching more of the video, I realized that it was a video by someone else. I’m kind of working on this, but I’m not sure what some the variable are in the formula do/dt=a+BNtsign(Rt-Lt). a is the angle, Nt is the number of objects within a radius of an object. sign(Rt-Lt) is the sign (+1 or -1) of the number of items to the right or left of an object depending on its orientation. I’m assuming do/dt is the angle change that gets added to the angle a. I’m not sure what B is. So far I have a bunch of circles moving around the screen based on their angle and I’m counting the number of circles within a distance of each circle. Next step is to determine how many objects are on the right or left of the circles orientation.

• Posts: 3,295

great!
I thought of using sensor and collisions to have fast built-in acces to close objects.

• Posts: 3,295

B is a constant that characterize the physics of this world. At the end of the video they show which couples of A,B values generate interesting worlds.

• edited January 2019 Posts: 7,949

@Jmv38 Here’s what I have so far. It doesn’t look like the video, but it does eventually start to clump. Apparently I’m not doing something right, but I not sure where and I’m tired of working on it for now. I don’t know if I need to do all the calculations before I change the positions of each point. Sort of like the game of life code. I’ll try that eventually.

PS. I modified the original code to make it faster, starts from random points, and color based on it distance to a nrighbor.

``````displayMode(FULLSCREEN)

function setup()
A1,B1=1,1
cnt=0
tab={}
for z=1,400 do
table.insert(tab,{x=math.random(80,WIDTH-80),y=math.random(80,HEIGHT-80),
ang=math.random(360),lft=0,rgt=0,col=color(0,0,0)} )
end
end

function draw()
background(40, 40, 50)
for a,b in pairs(tab) do
fill(b.col)
n=b.lft+b.rgt
s=sign(b.lft,b.rgt)
b.ang=(b.ang+(A1+B1*n*s)%360)%360
ellipse(b.x,b.y,6)
end
dist()
cnt=cnt+1
fill(255)
text(cnt,WIDTH/2,HEIGHT-25)
end

-- determine if the sign is positive of negative
function sign(l,r)
if r>l then return -1 end
if l>r then return 1 end
return 0
end

-- determine if a point is within the radius of another point
function dist()
for a,b in pairs(tab) do
b.lft,b.rgt=0,0
b.col=color(0,255,0)
end
for z=1,#tab do
v=vec2(tab[z].x,tab[z].y)
for y=z+1,#tab do
d=v:dist(vec2(tab[y].x,tab[y].y))
pos(tab[z],tab[y],z,y)
pos(tab[y],tab[z],z,y)
setColor(d,z,y)
end
end
end
end

function setColor(d,z,y)
tab[z].col=color(0,0,255)
tab[y].col=color(0,0,255)
tab[z].col=color(255,255,0)
tab[y].col=color(255,255,0)
tab[z].col=color(255,0,255)
tab[y].col=color(255,0,255)
else
tab[z].col=color(255,0,0)
tab[y].col=color(255,0,0)
end
end

-- determine how many points are on the right or left side of the point axis
function pos(orig,next)
ang1=math.deg(math.atan(next.y-orig.y,next.x-orig.x))
if ang1<0 then ang1=360+ang1 end
if orig.ang>=180 then
if ang1<orig.ang and ang1>orig.ang-180 then
orig.rgt=orig.rgt+1
else
orig.lft=orig.lft+1
end
else
if ang1>=orig.ang and ang1<orig.ang+180 then
orig.lft=orig.lft+1
else
orig.rgt=orig.rgt+1
end
end
end
``````
• Posts: 5,061

That's pretty cool, you end up with little neighbourhoods around step 250

• Posts: 7,949

@Simeon I modified the above code. It’s a little faster, starts with random points, and color based on it distance to a neighbor.

• Posts: 3,295

@dave1707 i’ve restarted from your project, here is my version.

``````--# Grid
Grid = class()
-- this is just a tool to find neighbours faster (improves fps)

local w,h,imax,jmax
local grid = {}
local floor = math.floor

function Grid:init(R)
w,h = WIDTH, HEIGHT
imax,jmax = self:get_ij(w,h)

for i=1,imax do
local col = {}
grid[i] = col
for j=1,jmax do
col[j] = {}
end
end
end

function Grid:update(a)
local i0,j0 = a.i,a.j
local i,j = Grid:get_ij(a.x,a.y)
if (i~=i0) or (j~=j0) then
self:reset(i0-1,j0-1,a)
self:reset(i0-1,j0  ,a)
self:reset(i0-1,j0+1,a)
self:reset(i0  ,j0-1,a)
self:reset(i0  ,j0  ,a)
self:reset(i0  ,j0+1,a)
self:reset(i0+1,j0-1,a)
self:reset(i0+1,j0  ,a)
self:reset(i0+1,j0+1,a)

self:set(i-1,j-1,a)
self:set(i-1,j  ,a)
self:set(i-1,j+1,a)
self:set(i  ,j-1,a)
self:set(i  ,j  ,a)
self:set(i  ,j+1,a)
self:set(i+1,j-1,a)
self:set(i+1,j  ,a)
self:set(i+1,j+1,a)

a.i,a.j = i,j
end
end
function Grid:neighbours(a)
local i,j = a.i, a.j
i = (i-1)%imax + 1
j = (j-1)%jmax + 1
return grid[i][j]
end
function Grid:set(i,j,a)
i = (i-1)%imax + 1
j = (j-1)%jmax + 1
grid[i][j][a] = a
end
function Grid:reset(i,j,a)
i = (i-1)%imax + 1
j = (j-1)%jmax + 1
grid[i][j][a] = nil
end

function Grid:get_ij(x,y)
return i,j
end

--# Object
Object = class()
-- these values completely defines the objects
local A1, B1, R, S = 180, 17, 30, 3
local A1, B1, R, S = 180, 17, 30, 2
local A1, B1, R, S = 180, 17, 30, 3
-- the number of objects / size of the initial ground are important too
nbrObjects = 500
size = 380

local grid = false
function Object:init(w,h)
if not grid then -- init the grid just once
grid = Grid(R)
end
-- random position and angle within specified bounds
self.x=math.random((WIDTH-w)/2,(WIDTH+w)/2)
self.y=math.random((HEIGHT-h)/2,(HEIGHT+h)/2)
self.i = 1
self.j = 1
self.ang=math.random(360)
-- init speed
self.speed = S

self.col=color(0,255,0)
end
local mod = math.fmod
local min = math.min

function Object:update()
-- move according current direction and speed
local x,y
x = self.x + self.dx
y = self.y + self.dy
-- make the world a torus
x = mod(x +WIDTH , WIDTH )
y = mod(y +HEIGHT, HEIGHT)
-- now update positions
self.x = x
self.y = y
grid:update(self)
-- manage neighbour impact
local A = vec2(self.x,self.y)
local nbClose = 0
local side = 0
local d,n,lft,rgt = 0,0,0,0
local B = vec2(0,0)
for b,b in pairs( grid:neighbours(self) ) do
if b~=self then
B.x, B.y = b.x, b.y
d = A:dist(B)
if d < self.colorRadius then nbClose = nbClose + 1 end
side = -self.dy*(b.x-self.x) + self.dx*(b.y-self.y)
if side > 0 then
lft = lft + 1
else
rgt = rgt + 1
end
end
end
end
-- turn according to neighbours
n = lft + rgt
local sgn = 0
if lft < rgt then sgn = -1 else sgn = 1 end
self.ang=(self.ang+(A1+B1*n*sgn))%360
-- define color according to nb of close neighbours
local col
if     nbClose < 1   then col = color(0,255,0)
elseif nbClose < 2 then col = color(0,92,255)
elseif nbClose < 4 then col = color(255,255,0)
elseif nbClose < 8 then col = color(255,0,255)
else col=color(255,0,0)
end
self.col=col
end

function Object:draw()
fill(self.col)
end

--# Main
displayMode(FULLSCREEN)

function setup()
cnt=0
tab={}
for z=1,nbrObjects do
table.insert(tab, Object(size,size) )
end
end

function draw()
background(40, 40, 50)
for a,b in pairs(tab) do
b:draw()
b:update()
end
cnt=cnt+1
fill(255)
text(cnt,WIDTH/2,HEIGHT-25)
end

``````
• Posts: 7,949

@Jmv38 You’re code is working the way it should. I’ll have to look thru it to see what I’m doing wrong in my code. Apparently I don’t understand what’s really happening.

• Posts: 3,295

i dont think you are doing anything wrong.
Starting from your code was simpler for me, thanks!
I just introduced a faster way to locate the neighbours via the ‘grid’.

• Posts: 3,295

a more interactive version

``````--# Object
Object = class()
-- these values completely defines the objects
local A1, B1, R, S = 180, 17, 30, 3
local A1, B1, R, S = 180, 17, 30, 2
local A1, B1, R, S = 180, 17, 35, 4
-- the number of objects / size of the initial ground are important too
nbrObjects = 700
size = 500

local grid = false
function Object:init(w,h,x,y)
if not grid then -- init the grid just once
grid = Grid(R)
end
-- random position and angle within specified bounds
if x == nil then
self.x=math.random((WIDTH-w)/2,(WIDTH+w)/2)
self.y=math.random((HEIGHT-h)/2,(HEIGHT+h)/2)
else
self.x = x
self.y = y
end

self.i = 1
self.j = 1
self.ang=math.random(360)
-- init speed
self.speed = S

self.col=color(0,255,0)
end
local mod = math.fmod
local min = math.min

function Object:update()
-- move according current direction and speed
local x,y
x = self.x + self.dx
y = self.y + self.dy
-- make the world a torus
x = mod(x +WIDTH , WIDTH )
y = mod(y +HEIGHT, HEIGHT)
-- now update positions
self.x = x
self.y = y
grid:update(self)
-- manage neighbour impact
local A = vec2(self.x,self.y)
local nbClose = 0
local side = 0
local d,n,lft,rgt = 0,0,0,0
local B = vec2(0,0)
for b,b in pairs( grid:neighbours(self) ) do
if b~=self then
B.x, B.y = b.x, b.y
d = A:dist(B)
if d < self.colorRadius then nbClose = nbClose + 1 end
side = -self.dy*(b.x-self.x) + self.dx*(b.y-self.y)
if side > 0 then
lft = lft + 1
else
rgt = rgt + 1
end
end
end
end
-- turn according to neighbours
n = lft + rgt
local sgn = 0
if lft < rgt then sgn = -1 else sgn = 1 end
self.ang=(self.ang+(A1+B1*n*sgn))%360
-- define color according to nb of close neighbours
local col
if     nbClose < 1   then col = color(0,255,0)
elseif nbClose < 8 then col = color(0,92,255)
elseif nbClose < 12 then col = color(255,255,0)
elseif nbClose < 16 then col = color(255,0,255)
else col=color(255,0,0)
end
self.col=col
end

function Object:draw()
fill(self.col)
end

--# Grid
Grid = class()
-- this is just a tool to find neighbours faster (improves fps)

local w,h,imax,jmax
local grid = {}
local floor = math.floor

function Grid:init(R)
w,h = WIDTH, HEIGHT
imax,jmax = self:get_ij(w,h)

for i=1,imax do
local col = {}
grid[i] = col
for j=1,jmax do
col[j] = {}
end
end
end

function Grid:update(a)
local i0,j0 = a.i,a.j
local i,j = Grid:get_ij(a.x,a.y)
if (i~=i0) or (j~=j0) then
for di =-1,1 do
for dj =-1,1 do
self:reset(i0+di,j0+dj,a)
end
end
for di =-1,1 do
for dj =-1,1 do
self:set(i+di,j+dj,a)
end
end
a.i,a.j = i,j
end
end
function Grid:neighbours(a)
local i,j = a.i, a.j
i = (i-1)%imax + 1
j = (j-1)%jmax + 1
return grid[i][j]
end
function Grid:set(i,j,a)
i = (i-1)%imax + 1
j = (j-1)%jmax + 1
grid[i][j][a] = a
end
function Grid:reset(i,j,a)
i = (i-1)%imax + 1
j = (j-1)%jmax + 1
grid[i][j][a] = nil
end

function Grid:get_ij(x,y)
return i,j
end

--# Main
displayMode(FULLSCREEN)
local t
function setup()
cnt=0
tab={}
t=0
for z=1,nbrObjects do
-- table.insert(tab, Object(size,size) )
end
showText = "swipe the screen to add objects"
end
floor = math.floor
function draw()
background(40, 40, 50)
for a,b in pairs(tab) do
b:draw()
b:update()
end
if false and floor(ElapsedTime) > t then
t = floor(ElapsedTime) +1
table.insert(tab, Object(size,size) )
end
if showText then
fill(255)
text(showText,WIDTH/2,HEIGHT/2)
else
cnt=cnt+1
fill(255)
text(cnt,WIDTH/2,HEIGHT-25)
end

end
function touched(touch)
showText = nil
table.insert(tab, Object(size,size,touch.x,touch.y) )
end
``````
• Posts: 7,949

@Jmv38 This new version works great. I made a slight change to it for myself. I added width and height parameters so I could squeeze the size of the working area. I would fill the screen with green dots and then start reducing the width and height. It was like I was increasing the pressure inside the area with more and more dots turning to red. I also found out what I was doing wrong with my code. When I changed A1 to 180 and B1 to 17, it starting acting right. I also wasn’t limiting the size of the working area. So it was just increasing in size off screen and not forcing the dots to interact that much.

• Posts: 10

Ha! That’s so great! Well done both!