# Randomly spawning physics bodies that are influenced by gravity

Hi,
I’m trying to randomly spawn ellipses at the top of the screen and have them drop, influenced by gravity. I have a physics.body shown with an image on the bottom of the screen that I can drag along an x-axis. When the ellipses fall, I would like to be able to “catch” them. Eventually, I would like to have them spawn faster based on how long you survive (you have to catch all the ellipses). So far I’ve been able to spawn an ellipse at random x values, but for some reason they are not dropping even though I have set gravityScale to 1. Sorry for my ignorance on the topic. I’ve just begun using Codea. I’ve posted my code below and replaced any images with images that come default with Codea in case you wanted to test my code. Warning, it is very basic.

Thanks!

``````

--# Main

-- Use this function to perform your initial setup
function setup()
print("Hello World!")
bmaWidth = 100
bmaHeight = 100
inTouch = false
bma = physics.body(POLYGON,
vec2(-bmaWidth/2,-bmaHeight/2),
vec2(-bmaWidth/2,bmaHeight/2),
vec2(bmaWidth/2, bmaHeight/2),
vec2(bmaWidth/2, -bmaHeight/2))
bma.x = WIDTH/2
bma.y = 100
bma.gravityScale = 0
box = DragMe()
b1 = Ball(100,50,300,color(128,128,128))
timer = 0
b = physics.body(CIRCLE,50)
end

-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)

-- This sets the line thickness
strokeWidth(3)

-- Do your drawing here
timer = timer + 1
text("Score:0",WIDTH-100,HEIGHT-50)
box:draw()
b1:draw()
end

function touched(t)
box:touched(t)
end

--# DragMe
DragMe = class()

function DragMe:init()
-- you can accept and set parameters here
self.pos = vec2(bma.x,bma.y)
self.size = 100
end

function DragMe:draw()
-- Codea does not automatically call this method
pushStyle()
fill(0, 33, 255, 255)
rectMode(CENTER)
sprite("Cargo Bot:Crate Blue 1",self.pos.x,self.pos.y,self.size,self.size)
popStyle()

end
function DragMe:hit(point)
if point.x > (self.pos.x - self.size/2) and
point.x < (self.pos.x + self.size/2) and
point.y > (self.pos.y - self.size/2) and
point.y < (self.pos.y + self.size/2) then
return true
end

return false
end
function DragMe:touched(t)
-- Codea does not automatically call this method
if self:hit(vec2(t.x,t.y)) and
t.state ==  MOVING then
self.pos = self.pos + vec2(t.deltaX, 0)
end
end

--# Ball
Ball = class()

function Ball:init()
-- you can accept and set parameters
self.pos = vec2(math.random(WIDTH),HEIGHT-100)
gravityScale = 1
end

function Ball:draw()
-- Codea does not automatically call this method
pb = physics.body(CIRCLE,50)
pb.x = self.pos.x
pb.y = self.pos.y
pb.gravityScale = 1
ellipse(pb.x,pb.y,50)
fill(0, 46, 255, 255)
end

function Ball:touched(touch)
-- Codea does not automatically call this method
end

``````

Unless you have a special reason for using physics(such as wanting the circles to bounce around in the bucket) what you are trying to do doesn’t really need a physics engine

You are defining the ball physics body every frame so that will eat up memory and make it crash. Also I don’t think that you are actually moving the physics box, just the image of the crate.

Here is some code to start you off

``````
--# Main
-- Catch2
displayMode(FULLSCREEN)
displayMode(OVERLAY)
-- Use this function to perform your initial setup
function setup()
physics.gravity(0,-100)--set the gravity for the physics world

w,h=200,50--the width&height of the box
box=physics.body(POLYGON, vec2(-w/2,-h/2),vec2(-w/2,h/2),vec2(w/2,h/2),vec2(w/2,-h/2))
--define the box with a type and list of certices
box.x=WIDTH/2
box.y=200
box.type=KINEMATIC--it doesnt react to collisions
box.linearVelocity=vec2(0,0)--not moving yet

balls={}--table to hold the physics balls
parameter.action("spawn-ball",function()--button that spawns a ball
table.insert(balls,
createBall(math.random(100,WIDTH-100),HEIGHT))--create a ball and add it to our table
end)
end

-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)

fill(255)
rectMode(CENTER)
rect(box.x,box.y,w,h)--draw the box

for i=1,#balls do--draw the balls
ellipse(balls[i].x,balls[i].y,50,50)
end
for i=#balls,1,-1 do
if balls[i].y<-60 then--is the ball offscreen?
balls[i]:destroy()--then destroy it and remove it from our table
table.remove(balls,i)
end
end
end

function touched(t)--when you tap the screen
if t.x<box.x then
box.linearVelocity=vec2(-200,0)--push the box towards your finger
else
box.linearVelocity=vec2(200,0)
end
if t.state==ENDED then
box.linearVelocity=vec2(0,0)--stop it when you stop touching
end
end

function createBall(x,y)--the function to create a ball
local ball=physics.body(CIRCLE,50)--define
ball.x=x
ball.y=y
return ball--send the ball's data to put in the table
end

``````

@Coder Thanks! As for timing the ball spawn, how would you set it so that say, every 3 seconds a new ball spawns. I tried setting a timer that increases by 1, but I’m not sure how to get it to spawn EVERY 3 seconds. I used

``````if timer >= 180 then
b1:draw()
timer = 0
else timer = timer + 1
end
``````

, but the ball only appears for a second as once it is set to 0, it is no longer >= 180

@Staples As @Coder mentioned, this can be done without using gravity. Here’s an example of that.

``````
displayMode(FULLSCREEN)

function setup()
balls={}
cnt=200
limit=180
dx=WIDTH/2
gameOver=false
total=0
fontSize(40)
end

function draw()
background(40,40,50)
fill(255)
if gameOver then
text("Game over",WIDTH/2,HEIGHT-100)
text("double tap screen to start again",WIDTH/2,HEIGHT-150)
return
end
cnt=cnt+1
if cnt>limit then
if limit<35 then
limit=35
else
limit=limit-5
end
cnt=0
create()
end
rect(dx,200,100,10)
for a,b in pairs(balls) do
ellipse(b.x,b.y,30)
b.y=b.y-5
if b.x>dx and b.x<dx+100 and b.y>180 and b.y<220 then
table.remove(balls,a)
total=total+1
end
if b.y<0 then
gameOver=true
end
end
text("Balls caught     "..total,WIDTH/2,HEIGHT-100)
end

function create()
table.insert(balls,vec2(math.random(50,WIDTH-50),HEIGHT))
end

function touched(t)
if t.state==BEGAN and gameOver and t.tapCount==2 then
restart()
end
if dx~=nil then
dx=dx+t.deltaX
end
end

``````

If you are using the code I posted just call `createBall()` when the timer is up

@Coder oh ok thanks and sorry,but one last thing. How can I create a reaction to a collision between the box and the ball? I’ve changed the box’s width and height so that is is 100x100, added an image to cover the fill, and changed the ball’s size to 25x25. I want it to look as though the ball is falling into the box. So, I would like the ball not to collide upon contact,but fall behind the box and be destroyed once it reached the center of the box(the 50,50 location inside the box). How would I go about doing so?

I have updated the code so that the box and balls are now in classes. I think it now does what you want

``````
--# Main
-- Catch2

-- Use this function to perform your initial setup
function setup()
physics.gravity(0,-100)--set the gravity for the physics world
box=Box(WIDTH/2,200)
balls={}--table to hold the physics balls
parameter.action("spawn-ball",function()--button that spawns a ball
table.insert(balls, Ball(math.random(100,WIDTH-100),HEIGHT,30,#balls+1))
end)
end

-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(0, 0, 0, 255)

for i=1,#balls do--draw the balls
balls[i]:draw()
end
box:draw()
end

function touched(t)--when you tap the screen
box:touched(t)
end

function collide(c)
if c.state==BEGAN and
(c.bodyA.info=="ball" or c.bodyB.info=="ball") and
(c.bodyA.info=="box" or c.bodyB.info=="box") then
if c.bodyA=="ball" then
balls[c.bodyA.num]:hit()
else
balls[c.bodyB.num]:hit()
end
end
end

--# Ball
Ball = class()

function Ball:init(x,y,r,n)
self.body=physics.body(CIRCLE,r)
self.body.x=x
self.body.y=y
self.body.info="ball"
self.body.num=n
end

function Ball:draw()
fill(255)
if self.body then
fill(0)
text(self.body.num,self.body.x,self.body.y)
else
fill(255,0,0)
ellipse(self.info.x,self.info.y,self.info.r,self.info.r)
end
end

function Ball:hit()
self.body:destroy()
self.body=nil
tween(0.5,self.info,{x=box.body.x,y=box.body.y,r=0})
end

--# Box
Box = class()

function Box:init(x,y)
local w,h=200,50
self.vertices =
{vec2(-w/2,-h/2),vec2(-w/2,h/2),vec2(w/2,h/2),vec2(w/2,-h/2)}
self.body = physics.body(POLYGON,unpack(self.vertices))
self.body.x = x
self.body.y = y
self.body.type=KINEMATIC
self.body.angle = 0
self.body.linearVelocity=vec2(0,0)
self.body.info="box"
self.w,self.h=w,h
end

function Box:draw()
fill(255)
rectMode(CENTER)
rect(self.body.x,self.body.y,self.w,self.h)
end

function Box:touched(t)
if t.x>self.body.x then
self.body.linearVelocity=vec2(200,0)
else
self.body.linearVelocity=vec2(-200,0)
end
if t.state==ENDED then
self.body.linearVelocity=vec2(0,0)
end
end

``````

@Coder I thought about that, similar to the app 100 balls on the App Store, but then if you you cannot score over around 20 in the game because the balls will pile up.

@Coder @dave1707 Thanks for all the help, I’ve figured it out now!

@Staples Here’s another version.

``````
displayMode(FULLSCREEN)
supportedOrientations(PORTRAIT_ANY)

function setup()
dx=0
ball={}
bucket=physics.body(CHAIN,false,vec2(-100,0),
vec2(-50,-100),vec2(50,-100),vec2(100,0))
bucket.x,bucket.y=WIDTH/2,300
bucket.type=KINEMATIC
time=3
end

function create()
b=physics.body(CIRCLE,10)
b.x=math.random(40,WIDTH-40)
b.y=HEIGHT
table.insert(ball,b)
end

function draw()
background(40,40,50)
fill(255,0,0)
strokeWidth(4)
line(bucket.x-100,bucket.y,bucket.x-50,bucket.y-100)
line(bucket.x-50,bucket.y-100,bucket.x+50,bucket.y-100)
line(bucket.x+50,bucket.y-100,bucket.x+100,bucket.y)
strokeWidth(0)
stroke(255)
for z=#ball,1,-1 do
ellipse(ball[z].x,ball[z].y,20)
if ball[z].y<0 then
ball[z]:destroy()
table.remove(ball,z)
end
end
time=time+DeltaTime
if time>2 then
create()
time=0
end
end

function touched(t)
dx=dx+t.deltaX
bucket.linearVelocity=vec2(dx,0)
end

``````

Wow that’s compact

@dave1707 I’ve been working on a game using some of the code above, but recently I’ve decided to change the main idea of the “basket” to be similar to the code you posted just above and make the balls physics bodies. I was just wondering if there was any smoother way of moving the basket. Using the code above, the basket moves quite slowly and the movement is delayed. I am guessing this is because you are changing the linear velocity to move towards your touch rather than always have the basket’s x value located at “dx”. I have tried altering the code to make basket.x = dx and also tried changing the chain to a group of edges which I’m guessing is the exact same as a chain because there was no difference. Can you explain if there is a simple way to make ellipses act as physics bodies on lines(as if they are kinematic edges) without making the balls or the basket physics bodies or if there is a way to make the basket’s movement as a physics body more similar to its movement as a sprite?

P.S. Sorry for the long question and if it is confusing.

@Staples Change the touched() routine above to this.

``````function touched(t)
dx=(t.x-bucket.x)*5
bucket.linearVelocity=vec2(dx,0)
end
``````

@dave1707 That was a lot simpler than I expected! Thanks, that’s exactly what I was going for!