# Catapult physics

Just thought I’d share it with you guys if anyone wants to know how to make a catapult, if the ball isn’t in the red zone then you can still set a catapult for when it returns. There’s a bug that I can’t seem to solve where the ball sometimes starts in the corner.

``````

-- flick

-- Use this function to perform your initial setup
function setup()
displayMode(FULLSCREEN)
PhysCreate:setup()
-- ball
ball = physics.body(CIRCLE,40)
ball.x = WIDTH/4
ball.y = HEIGHT/2
ball.interpolate = true
ball.restitution = 0.4
-- walls
vert={vec2(WIDTH,HEIGHT),vec2(0,HEIGHT),vec2(0,0),vec2(WIDTH,0),vec2(WIDTH,HEIGHT)}
floor = physics.body(CHAIN,unpack(vert))

-- store catapult variables
pos = vec2(150,400)
tpos = vec2()
force = 0

-- create boxes in grid
bodies = {}
local y = 1
local x = 1
for i = 1,45 do
bodies[i] = PhysCreate:create(vec2(600+x*41,y*40),vec2(2,2))
-- x < n, n sets the grid width
if x < 5 then
x=x+1
else
y=y+1
x=1
end
end
end

function touchPos()
--print(vec2(CurrentTouch.x,CurrentTouch.y))
return vec2(CurrentTouch.x,CurrentTouch.y)
end

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

-- start touch and store first position
if CurrentTouch ~= nil and CurrentTouch.state == BEGAN and touchPos().x < 300 then
holding = 1
pos = touchPos()
end

-- keep ball in the air while in red zone
if ball.x < 300 then
if ball.y < 100 then
ball.linearVelocity = vec2(ball.linearVelocity.x*0.3,(100-ball.y)*5)
end
end

-- grab ball and set force
if holding == 1 then
local bl = (touchPos()-vec2(ball.x,ball.y)):normalize()
ball.linearVelocity = bl*touchPos():dist(vec2(ball.x,ball.y))*5

force = touchPos():dist(pos)
end

-- release catapult and set ball velocity
if holding == 1 and CurrentTouch.state == ENDED and touchPos():dist(vec2(ball.x,ball.y)) < 40 then
ball.linearVelocity = (pos-touchPos())*force
holding = 0
end

-- Set catapult starting variable if in red zone
if ball.x > 300 and CurrentTouch.state == BEGAN and touchPos().x < 300 and holding == 0 then
holding = 1
elseif ball.x > 300 and touchPos().x > 300 and CurrentTouch.state == MOVING then
holding = 0
end

-- draw boxes
PhysCreate:draw()

-- draw gui
-- catapult area (red zone)
line(300,0,300,HEIGHT)
strokeWidth(0)
fill(250,50,50,50)
rect(0,0,300,HEIGHT)
-- catapult
if holding == 1 then
strokeWidth(3)
fill(186, 186, 186, 255)
ellipse(pos.x,pos.y,20)

fill(255)
line(pos.x,pos.y,touchPos().x,touchPos().y)
end
-- draw ball
strokeWidth(5)
fill(100)
ellipse(ball.x,ball.y,80)
end

---------
PhysCreate = class()

function PhysCreate:init(x)
self.x = x
end

function PhysCreate:setup()
Di = 0
DTbl = {}
end

function PhysCreate:create(vpos,vsize)
local vert = {vec2(-10*vsize.x,10*vsize.y),vec2(-10*vsize.x,-10*vsize.y),
vec2(10*vsize.x,-10*vsize.y),vec2(10*vsize.x,10*vsize.y)}

local p = physics.body(POLYGON,unpack(vert))
p.mass = 2
p.x = vpos.x
p.y = vpos.y
p.w = vsize.x*10*2
p.h = vsize.y*10*2
p.interpolate = true
p.sleepingAllowed = false

p.m = mesh()
p.m:setRectTex(mr,0,0,1,1)

Di = Di + 1
DTbl[Di] = {p.m,mr,p}
end

function PhysCreate:draw()
for i=1,#DTbl do
local d = DTbl[i]
d[1]:draw()
d[1]:setRect(d[2],d[3].x,d[3].y,d[3].w,d[3].h,d[3].angle/57.3)
end
end

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

``````

Tell me what you think, I was thinking of a game with this concept, thanks

Really good!

2 things:

1. I noticed that the bug where the ball starts in the corners seems to happen mainly when I lifted my finger before the ball is thrusted rightwards
2. I’m not sure if its a bug or not, but the ball still collides with objects on its way back to the starting position.

Other than that, its fun to play with, and I believe it has potential to be used in a larger scale game

Yeah I know about the ball starting in the corner it’s really annoying me, I looked at it and tried what I thought should fix it but it didnt, and nah it’s not a bug i didn’t put in anything to stop the ball from colliding when it came back. Thanks for the comments!