Can anyone explain what I’m doing wrong or why this isn’t working. With a real Newtons cradle, only the left and right balls should be moving. The 3 middle balls should remain stationary. I can’t figure out why 4 balls are moving and what I need to adjust.

``````
--# Main

function setup()
supportedOrientations(LANDSCAPE_LEFT)
displayMode(FULLSCREEN)

-- create 5 hanger points, a1-a5
a1=physics.body(CIRCLE,0)
a1.type=STATIC
a1.x=WIDTH/2-200
a1.y=700

a2=physics.body(CIRCLE,0)
a2.type=STATIC
a2.x=WIDTH/2-100
a2.y=700

a3=physics.body(CIRCLE,0)
a3.type=STATIC
a3.x=WIDTH/2
a3.y=700

a4=physics.body(CIRCLE,0)
a4.type=STATIC
a4.x=WIDTH/2+100
a4.y=700

a5=physics.body(CIRCLE,0)
a5.type=STATIC
a5.x=WIDTH/2+200
a5.y=700

-- create 5 balls, c1-c5
c1=physics.body(CIRCLE,50)
c1.type=DYNAMIC
c1.restitution=1
c1.x=WIDTH/2-200
c1.y=200

-- give the left ball a velocity to the left
c1.linearVelocity=vec2(-200,0)

c2=physics.body(CIRCLE,50)
c2.type=DYNAMIC
c2.restitution=1
c2.x=WIDTH/2-100
c2.y=200

c3=physics.body(CIRCLE,50)
c3.type=DYNAMIC
c3.restitution=1
c3.x=WIDTH/2
c3.y=200

c4=physics.body(CIRCLE,50)
c4.type=DYNAMIC
c4.restitution=1
c4.x=WIDTH/2+100
c4.y=200

c5=physics.body(CIRCLE,50)
c5.type=DYNAMIC
c5.restitution=1
c5.x=WIDTH/2+200
c5.y=200

-- create a joint for each ball and hanger
physics.joint(REVOLUTE,c1,a1,a1.position)
physics.joint(REVOLUTE,c2,a2,a2.position)
physics.joint(REVOLUTE,c3,a3,a3.position)
physics.joint(REVOLUTE,c4,a4,a4.position)
physics.joint(REVOLUTE,c5,a5,a5.position)
end

function draw()
background(40, 40, 50)

-- draw each ball
fill(255)

-- draw a line from each hanger to each ball
stroke(255, 255, 255)
strokeWidth(3)
line(c1.x,c1.y,a1.x,a1.y)
line(c2.x,c2.y,a2.x,a2.y)
line(c3.x,c3.y,a3.x,a3.y)
line(c4.x,c4.y,a4.x,a4.y)
line(c5.x,c5.y,a5.x,a5.y)
end

``````

Hi @dave1707,

It will give you perhaps an idea.

Hi @dave1707,

That’s interesting, I coded a similar example yesterday with the same result as you. But following the link provided by @quezadav was very helpful (thanks!).
@Herwig mentioned there that he had to put some extra space between the balls. So I tried this with your example, and it almost worked. Adjusting the restitiution of the balls from 1 to .95 further improved the simulation.

``````--# Main

function setup()
supportedOrientations(LANDSCAPE_LEFT)
displayMode(FULLSCREEN)

-- create 5 hanger points, a1-a5
a1=physics.body(CIRCLE,0)
a1.type=STATIC
a1.x=WIDTH/2-202
a1.y=700

a2=physics.body(CIRCLE,0)
a2.type=STATIC
a2.x=WIDTH/2-101
a2.y=700

a3=physics.body(CIRCLE,0)
a3.type=STATIC
a3.x=WIDTH/2
a3.y=700

a4=physics.body(CIRCLE,0)
a4.type=STATIC
a4.x=WIDTH/2+101
a4.y=700

a5=physics.body(CIRCLE,0)
a5.type=STATIC
a5.x=WIDTH/2+202
a5.y=700

-- create 5 balls, c1-c5
c1=physics.body(CIRCLE,50)
c1.type=DYNAMIC
c1.restitution=.95
c1.x=WIDTH/2-202
c1.y=200

-- give the left ball a velocity to the left
c1.linearVelocity=vec2(-200,0)

c2=physics.body(CIRCLE,50)
c2.type=DYNAMIC
c2.restitution=.95
c2.x=WIDTH/2-101
c2.y=200

c3=physics.body(CIRCLE,50)
c3.type=DYNAMIC
c3.restitution=.95
c3.x=WIDTH/2
c3.y=200

c4=physics.body(CIRCLE,50)
c4.type=DYNAMIC
c4.restitution=.95
c4.x=WIDTH/2+101
c4.y=200

c5=physics.body(CIRCLE,50)
c5.type=DYNAMIC
c5.restitution=.95
c5.x=WIDTH/2+202
c5.y=200

-- create a joint for each ball and hanger
physics.joint(REVOLUTE,c1,a1,a1.position)
physics.joint(REVOLUTE,c2,a2,a2.position)
physics.joint(REVOLUTE,c3,a3,a3.position)
physics.joint(REVOLUTE,c4,a4,a4.position)
physics.joint(REVOLUTE,c5,a5,a5.position)
end

function draw()
background(40, 40, 50)

-- draw each ball
fill(255)

-- draw a line from each hanger to each ball
stroke(255, 255, 255)
strokeWidth(3)
line(c1.x,c1.y,a1.x,a1.y)
line(c2.x,c2.y,a2.x,a2.y)
line(c3.x,c3.y,a3.x,a3.y)
line(c4.x,c4.y,a4.x,a4.y)
line(c5.x,c5.y,a5.x,a5.y)
end
``````

I have been working through (a copy of) the Physics Lab example project. Below is the same idea, expressed as a new ‘Test 10’, but using a DISTANCE joint:

``````
Test10 = class()

function Test10:init()
self.size = 50  -- Change this to change the size of the balls
end

function Test10:setup()
local s = self.size
for i = 1, 5 do
local a = createCircle(WIDTH/2 + (i - 3) * s * 2, 700, 5)
a.type = STATIC

local c = createCircle(WIDTH/2 + (i - 3) * s * 2, 200, s * 0.99)
c.restitution = 0.95
c.friction = 0
if i == 1 then c.linearVelocity = vec2(-200, 0) end

local top = c.position + vec2(0, c.radius)

local j = physics.joint(DISTANCE, a, c, a.position, top)
end
end

function Test10:draw()
end

function Test10:touched(touch)
end

``````

Here is my updated version of Newtons cradle. Thanks to all who explained why the other one wasn’t working correctly. This one also has problems, but that’s kind of beyond our control. Is the problem because Codea is using single precision instead of double precision, I don’t know. I allow the ball count to range from 2 to 50. I also allow the number of pulled balls to be from 1 to ball count -1. I originally wrote this to play around with the physics.joint function.

``````
--# Main

function setup()
supportedOrientations(LANDSCAPE_LEFT)
iparameter("balls",2,50,5)
iparameter("number",1,20,1)
tab1={}    -- table for objects
prevBalls=0
prevNumber=0
getOffset()
create()
end

function draw()
background(40, 40, 50)

-- balls or number were changed with iparameters
if prevBalls ~= balls or prevNumber ~= number then
create()
end

-- draw the balls and lines
for z=1,balls do
-- draw the balls
fill(255)
ball=tab1[z].bodyA

-- draw line from hanger to ball
stroke(255, 255, 255)
strokeWidth(3)
hanger=tab1[z].bodyB
line(hanger.x,hanger.y,ball.x,ball.y)
end
end

function create()
-- remove previous objects
if prevBalls ~= balls or prevNumber ~= number then
for z=1,prevBalls do
tab1[z].bodyA:destroy()
tab1[z]:destroy()
tab1[z]=nil
end

-- limit number to less than balls
if number > balls-1 then
number = balls-1
end

prevBalls=balls
prevNumber=number
getOffset()
end

-- create new objects
for z=1,balls do
hanger=physics.body(CIRCLE,0)
hanger.type=STATIC
hanger.x=z*r2+offset
hanger.y=700
ball.restitution=1
ball.x=z*r2+offset
ball.y=200

-- give number of balls a velocity
if z<=number then
ball.linearVelocity=vec2(-300,0)
end

-- join the balls and the hangers
tab1[z]=physics.joint(REVOLUTE,ball,hanger,hanger.position)
end
end

function getOffset()
-- calculate offset to keep display centered