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()
    local mr = p.m:addRect(p.x,p.y,p.w,p.h,0)
    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!