New Game Challenge: Pong/Air Hockey Variant

This challenge is to make the best variation of either Pong or Air Hockey.

  1. It can be similiar to the games but must have a cool twist.
  2. No line limit.
  3. Menu and Game Over preferred but not required
  4. Prize: TBD
  5. Judges: Monkeyman
  6. Deadline: November 11, 2014 @ 11:11 am

Best of Luck,
Griffin

What’s with all the 11s in the deadline? :wink:

Whats TBD 5?

To be determined

Oh, then the 5 in there must mean rule 5.

What the heck, I’m bored. I’ll enter.

I’ll enter, but be warned that my entry will be too awesome for your mind to handle.

I still need another judge PM’s please

I’ll join, but not sure if I’ll have the free time to finish writing an app

We dont have enough applicants to make a decent competition. Please consider joining this.

Sorry, but how can i post a comment with a fancy box containing my code? I’m new here and couldn’t find it anywhere and I wanted to share my fully functional pong variant with clever bots with you guys.

@TheMcSebi If you want to post your code, put 3 ~'s (tildes) on a line before and after your code.

@TheMcSebi That sounds like a frequently asked question…maybe you should read the FAQ?

‘2) No line limit.’

What does that mean? Does it mean that the paddles should be able to go anywhere on the screen?

@CayDay47 , I think he means your code can be as many lines as you want.

Couldn’t find it on the FAQ, but thanks @dave1707 :slight_smile:

So this is what i did during a couple of days when I was really bored - hope you enjoy it :slight_smile:

-- Main

supportedOrientations(LANDSCAPE_ANY)
displayMode(FULLSCREEN)

function setup()
    
    -- ADJUSTABLE PARAMETERS
    local toggleBot1 = true
    local toggleBot2 = false
    
    local botOperationDelay = 60    --min 3
        -- bot max speed at 3: 365
        -- bot max speed at 5: 250
    local botMovementMode = 1    -- 1 || 2
    local initialBallSpeed = 12
    
    local bouncesToSpeedIncrease = 5
    -- END OF ADJUSTABLE PARAMETERS
    
    doGameSetup(botOperationDelay, initialBallSpeed, bouncesToSpeedIncrease, botMovementMode, toggleBot1, toggleBot2)
end


function doGameSetup(bod, ibs, btsi, bmm, tb1, tb2)
    ball = {pos=vec2(WIDTH/2, HEIGHT/2), dir=nil, s=4}
    bars = {{x=0, y=HEIGHT/2}, {x=1, y=HEIGHT/2}}
    bot1 = {fin = nil, delay = bod, job = false, ball = nil}
    bot2 = {fin = nil, delay = bod, job = false, ball = nil}
    score = {left=0, right=0}
    
    bgc = color(31, 39, 82, 255)
    noSmooth()
    
    parameter.boolean("bot1_enabled", tb1)
    parameter.boolean("bot2_enabled", tb2)
    parameter.boolean("autorestart", false)
    parameter.integer("sysMultiply", 1, 20, 1)
    parameter.watch("ballSpeed")
    
    maxBounces = btsi
    initBallSpeed = ibs
    ballSize = 20
    barLength = 200
    borderWidth = 15
    botMode = bmm
    
    touches = {}
    bounces = 0
    gameState = 0
    ballSpeed = ibs
end

function touched(touch)
    if touch.state == ENDED then
        touches[touch.id] = nil
        started = false
    else
        touches[touch.id] = touch
    end
end

function draw()
    handleTouches()
    
    drawField()
    drawScore()
    drawBall()
    
    for i = 1, sysMultiply do
        for i = 1, ballSpeed do
            if gameState == 1 then
                updateBall()
            end
        end
        
        if gameState == 1 then
            updateGame()
        end
        
        if bot1_enabled then bot(1) end
        if bot2_enabled then bot(2) end
    end
    
    for i,b in pairs(bars) do drawBar(b) end
end


function bot(n)
    -- simple bot code
    --bars[n].y = ball.pos.y + math.random((-barLength/2.1)*100, (barLength/2.1)*100)/100
    
    -- hardcore bot code
    if (n == 1) and not (bot1.ball == nil) then
        local b = bot1.ball
        --local rand = vec2(0, math.random((-barLength/2.3)*100, (barLength/2.3)*100)/100)
        local randRange = barLength/1.1
        local rand = vec2(0, math.random()*randRange-randRange/2)
        local fin = simulation(b.pos, b.dir) + rand
        
        bot1.job = true
        bot1.fin = fin
        bot1.speed = (bot1.fin.y-bars[1].y)/bot1.delay
        bot1.ball = nil
        
        
    elseif (n == 2) and not (bot2.ball == nil) then
        local b = bot2.ball
        --local rand = vec2(0, math.random((-barLength/2.3)*100, (barLength/2.3)*100)/100)
        local randRange = barLength/1.1
        local rand = vec2(0, math.random()*randRange-randRange/2)
        local fin = simulation(b.pos, b.dir) + rand
        
        bot2.job = true
        bot2.fin = fin
        bot2.speed = (bot2.fin.y-bars[2].y)/bot2.delay
        bot2.ball = nil
    end
    
    if (bot1.job == true) and (n == 1) then
        if botMode == 1 then
            bars[1].y = bars[1].y + bot1.speed
        elseif botMode == 2 then
            bars[1].y = bars[1].y + (bot1.fin.y - bars[1].y)/(bot1.delay/2.2)
        end
        if math.floor(bot1.fin.y*10) == math.floor(bars[1].y*10) then
            bars[1].y = bot1.fin.y
            bot1.job = false
            --print("bot1 job done")
        end
    end
    
    if (bot2.job == true) and (n == 2) then
        if botMode == 1 then
            bars[2].y = bars[2].y + bot2.speed
        elseif botMode == 2 then
            bars[2].y = bars[2].y + (bot2.fin.y - bars[2].y)/(bot1.delay/2.2)
        end
        if math.floor(bot2.fin.y*10) == math.floor(bars[2].y*10) then
            bars[2].y = bot2.fin.y
            bot2.job = false
            --print("bot2 job done")
        end
    end
    
end

function simulation(startPos, direction)
    local pos = startPos
    local dir = direction
    local targetReached = false
    
    while not targetReached do
        pos = pos + dir:normalize()
        
        if pos.y > HEIGHT-borderWidth-ballSize/2 then
            dir = vec2(dir.x, -dir.y)
            pos.y = HEIGHT-borderWidth-ballSize/2
        elseif pos.y < borderWidth+ballSize/2 then
            dir = vec2(dir.x, -dir.y)
            pos.y = borderWidth+ballSize/2
        end
        
        if pos.x > WIDTH-borderWidth-ballSize/2 then
            -- rechts
            targetReached = true
        elseif pos.x < borderWidth+ballSize/2 then
            -- links
            targetReached = true
        end
    end
    
    return pos
end


function updateGame()
    if bounces >= maxBounces then
        bounces = 0
        ballSpeed = ballSpeed + 1
    end
end


function handleTouches()
    
    local x = 0
    local y = 0
    
    for k,touch in pairs(touches) do
        x = touch.x
        y = touch.y
        
        for i,b in pairs(bars) do
            if x < WIDTH/2 then
                if b.x == 0 then
                    b.y = y
                end
            elseif x > WIDTH/2 then
                if b.x == 1 then
                    b.y = y
                end
            end
        end
    end
    
    if gameState == 0 then
            
        local bpos = ball.pos
                
        local dist = bpos:dist(vec2(x, y))
        if (dist < ballSize*3) or autorestart then
            gameState = 1
                    
            local buffer = math.random(1, 2)
            local yDir = math.random()*12-6
                    
            if buffer == 1 then
                ball.dir = vec2(-3, yDir)
                bot1.ball = ball
            elseif buffer == 2 then
                ball.dir = vec2(3, yDir)
                bot2.ball = ball
            end
        end
    end
end


function updateBall()
    local pos = ball.pos
    local dir = ball.dir
        
    pos = pos + dir:normalize()
        
    local x = pos.x
    local y = pos.y
    
    local passToBot1 = false
    local passToBot2 = false
        
    -- oben + unten
    if y > HEIGHT-borderWidth-ballSize/2 then
        dir = vec2(dir.x, -dir.y)
        pos.y = HEIGHT-borderWidth-ballSize/2
    elseif y < borderWidth+ballSize/2 then
        dir = vec2(dir.x, -dir.y)
        pos.y = borderWidth+ballSize/2
    end
        
    if x > WIDTH-borderWidth-ballSize/2 then
        -- rechts
        local barY = bars[2].y
        local ballY = ball.pos.y
            
        if math.abs(barY-ballY) < barLength/2 then
            dir = vec2(-dir.x, (ballY-barY)/20)
            pos.x = WIDTH-borderWidth-ballSize/2
            
            if bot1_enabled then
                passToBot1 = true
            end
        else
            scorePoint(2)
            pos = vec2(WIDTH/2, HEIGHT/2)
        end
        
        bounces = bounces + 1
            
    elseif x < borderWidth+ballSize/2 then
        -- links
        local barY = bars[1].y
        local ballY = ball.pos.y
            
        if math.abs(barY-ballY) < barLength/2 then
            dir = vec2(-dir.x, (ballY-barY)/20)
            pos.x = borderWidth+ballSize/2
            
            if bot2_enabled then
                passToBot2 = true
            end
        else
            scorePoint(1)
            pos = vec2(WIDTH/2, HEIGHT/2)
        end
        
        bounces = bounces + 1
    end
        
    ball.pos = pos
    ball.dir = dir
    
    if passToBot1 then
        bot1.ball = ball
    end
    
    if passToBot2 then
        bot2.ball = ball
    end
end


function drawField()
    background(bgc)
    
    pushMatrix()
    pushStyle()
    
    rectMode(CENTER)
    stroke(255, 255, 255, 255)
    strokeWidth(borderWidth)
    lineCapMode(SQUARE)
    fill(bgc)
    translate(WIDTH/2, HEIGHT/2)
    
    rect(0, 0, WIDTH+300, HEIGHT)
    stroke(255, 255, 255, 106)
    line(0, -HEIGHT/2, 0, HEIGHT/2)
    
    popMatrix()
    popStyle()
end


function drawBall()
    pushMatrix()
    pushStyle()
    
    local x = ball.pos.x
    local y = ball.pos.y
    
    rectMode(CENTER)
    fill(255, 255, 255, 255)
    
    rect(x, y, ballSize, ballSize)
    
    popMatrix()
    popStyle()
end

function drawBar(bar)
    pushMatrix()
    pushStyle()
    
    local h = barLength
    local w = borderWidth
    local x = bar.x*(WIDTH-w)+w/2
    local y = bar.y
    
    rectMode(CENTER)
    fill(255, 255, 255, 255)
    
    rect(x, y, w, h)
    
    popMatrix()
    popStyle()
end


function scorePoint(side)
    if side == 1 then
        --print("point for right")
        score.right = score.right + 1
    elseif side == 2 then
        --print("point for left")
        score.left = score.left + 1
    end
    
    gameState = 0
    ballSpeed = initBallSpeed
end


function drawScore()
    local size = 50
    local str = score.left.."   "..score.right
    
    pushMatrix()
    pushStyle()
    fill(255, 255, 255, 255)
    fontSize(size)
    font("Arial-BoldMT")
    textMode(CENTER)
    text(str, WIDTH/2, HEIGHT-borderWidth-size/2)
    popMatrix()
    popStyle()
end

Edit: Oooooohh, THAT FAQ… I only found that on the wiki ._. Sorry again…

I’ll give this one a try but it won’t be soo great!

@Mr_Ninja, thanks for making me see the obvious thing I overlooked :slight_smile:
It’s funny, I was already thinking about how to do it by then.

Great game @TheMcSebi I really liked how you made the “AI” for the players. Remember all others deadline for game is Remembrance Day at 11:11

Here’s my version, somewhat sloppily done, which I’m not proud of, but I like the visuals, so there is that. I was going to add more features, but I’ve been strapped for time, I may still add them.

displayMode(OVERLAY)
displayMode( FULLSCREEN)
supportedOrientations(LANDSCAPE_ANY)

function setup()
    physics.continuous=true
    p1=physics.body(CIRCLE,50)
    p1.mass=1
    p1.sleepingAllowed=false
    p1.bullet=true
    p1.position = vec2(50,HEIGHT/2)
    p1.lastpos = p1.position
    p1.name = "paddle1"
    p1.gravityScale = 0
    p1.type = KINEMATIC
    p1.draw = function()
        pushStyle()
        stroke(255,63.75,0)
        strokeWidth(score2/10*(p1.radius))
        fill(0, 255, 255, 255)
        ellipse(p1.x,p1.y,p1.radius*2+2)
        popStyle()
    end
    p2=physics.body(CIRCLE,50)
    p2.mass = 1
    p2.sleepingAllowed=false
    p2.bullet=true
    p2.position = vec2(WIDTH-50,HEIGHT/2)
    p2.lastpos = p2.position
    p2.name = "paddle2"
    p2.gravityScale = 0
    p2.type = KINEMATIC
    p2.draw = function()
        pushStyle()
        stroke(0,255,255)
        strokeWidth(score1/10*(p2.radius))
        fill(255, 63.75, 0, 255)
        ellipse(p2.x,p2.y,p2.radius*2+2)
        popStyle()
    end
    p3=physics.body(CIRCLE,20)
    p3.linearDamping=.25
    p3.mass = 1000
    p3.sleepingAllowed=false
    p3.bullet=true
    p3.position = vec2(WIDTH/2,HEIGHT/2)
    p3.name = "ball"
    p3.gravityScale = 0
    p3.type = DYNAMIC
    p3.draw = function()
        pushStyle()
        noStroke()
        fill(color(255,63.75,0):mix(color(0,255,255),.5+(score2-score1)/20))
        ellipse(p3.x,p3.y,p3.radius*2+2)
        popStyle()
    end
    maxlinedash = 33.3
    score1 = 0
    gs1=0
    score2 = 0
    gs2=0
    fps=60
    s=Starter()
    s:start(false)
    
end
function draw()
    background(127.5)
    strokeWidth(10)
    stroke(255, 63.75, 0, 255)
    lineCapMode(ROUND)
    for i=-2,maxlinedash do
        if i%2==0 then
            line(WIDTH/2,(i/maxlinedash)*HEIGHT+(ElapsedTime*10)%(HEIGHT/(maxlinedash/2)),WIDTH/2,(i+1)/maxlinedash*HEIGHT+(ElapsedTime*10)%(HEIGHT/(maxlinedash/2)))
        end
    end
    clip(WIDTH/2+(score2-score1)*10,0,WIDTH/2,HEIGHT)
    stroke(0, 255, 255, 255)
    for i=-2,maxlinedash do
        if i%2==0 then
            line(WIDTH/2,(i/maxlinedash)*HEIGHT+(ElapsedTime*10)%(HEIGHT/(maxlinedash/2)),WIDTH/2,(i+1)/maxlinedash*HEIGHT+(ElapsedTime*10)%(HEIGHT/(maxlinedash/2)))
        end
    end
    clip()
    if p3.position.y > HEIGHT-p3.radius then
        p3.linearVelocity = vec2(p3.linearVelocity.x,math.min(-p3.linearVelocity.y,p3.linearVelocity.y))
        elseif p3.position.y < p3.radius then
        p3.linearVelocity = vec2(p3.linearVelocity.x,math.max(-p3.linearVelocity.y,p3.linearVelocity.y))
    end
    if p3.position.x > WIDTH+p3.radius then
        score1 = score1 + 1
        if score1 >= 11 then 
            score1 = 0
            gs1 = gs1 + 1
        end
        p3.linearVelocity=vec2(0,0)
        p3.position=vec2(WIDTH/2,HEIGHT/2)
        s:start(false)
    end
    if p3.position.x < -p3.radius then
        score2 = score2 + 1
        if score2 >= 11 then 
            score2 = 0
            gs2 = gs2 + 1
        end
        p3.linearVelocity=vec2(0,0)
        p3.position=vec2(WIDTH/2,HEIGHT/2)
        s:start(true)
    end
    if touch2 then p2.position = vec2(touch2.x,touch2.y) end
    if touch1 then p1.position = vec2(touch1.x,touch1.y) end
    if p2.position.x < WIDTH/2+p3.radius+p2.radius then
        p2.position=vec2(WIDTH/2+p3.radius+p2.radius,p2.position.y)
        p2.linearVelocity.x =0
    end
    if p2.linearVelocity.x < (WIDTH/2+p3.radius+p2.radius)-p2.position.x then
        p2.linearVelocity.x = (WIDTH/2+p3.radius+p2.radius)-p2.position.x
    end
    if p1.position.x > WIDTH/2-p3.radius-p1.radius then
        p1.position=vec2(WIDTH/2-p3.radius-p1.radius,p1.position.y)
        p1.linearVelocity.x =0
    end
    if p1.linearVelocity.x > (WIDTH/2-p3.radius-p1.radius)-p1.position.x then
        p1.linearVelocity.x = (WIDTH/2-p3.radius-p1.radius)-p1.position.x
    end
    if p3.linearVelocity:len() > 1500 then
        p3.linearVelocity = 1500/p3.linearVelocity:len()*p3.linearVelocity
    end
    s:draw()
    p3:draw()
    p1:draw()
    p2:draw()
    fontSize(50)
    textAlign(RIGHT)
    fill(0,255,255)
    local w,h = textSize(score1.."\
"..gs1)
    text(score1.."\
"..gs1,WIDTH/2-w/2-15,HEIGHT-h/2)
    fill(255,63.75,0)
    local w,h = textSize(score2.."\
"..gs2)
    text(score2.."\
"..gs2,WIDTH/2+w/2+15,HEIGHT-h/2)
    output.clear()
    fps=.9*fps+.1*(1/DeltaTime)
    print(math.floor(fps))
end
function touched(t)
    if not touch1 and t.state == BEGAN and p1.position:dist(vec2(t.x,t.y))<p1.radius then
        touch1 = t
        elseif not touch2 and t.state == BEGAN and p2.position:dist(vec2(t.x,t.y))<p2.radius then
        touch2 = t
    end
    if t.state == MOVING and touch1 and t.id == touch1.id then
        p1.lastpos = p1.position
        touch1=t
        p1.linearVelocity = 1*vec2(30*t.deltaX,30*t.deltaY)
        if p1.linearVelocity.x > (WIDTH/2-p3.radius-p1.radius)-p1.position.x then
            p1.linearVelocity.x = (WIDTH/2-p3.radius-p1.radius)-p1.position.x
        end
        elseif t.state == MOVING and touch2 and t.id == touch2.id then
        p2.lastpos = p1.position
        touch2=t
        p2.linearVelocity = 1*vec2(30*t.deltaX,30*t.deltaY)
        if p2.linearVelocity.x < -(WIDTH/2+p3.radius+p2.radius)+p2.position.x then
            p2.linearVelocity.x = (WIDTH/2+p3.radius+p2.radius)-p2.position.x
        end
    end
    if t.state == ENDED and touch1 and touch1.id == t.id then
        touch1 = nil
        p1.linearVelocity=vec2(0,0)
        elseif t.state == ENDED and touch2 and t.id == touch2.id then
        touch2 = nil
        p2.linearVelocity=vec2(0,0)
    end
end

Starter = class()

function Starter:init()
    self.target = vec2(WIDTH/2,HEIGHT/2)
    self.d=100
    self.del = 2
    self.active = false
    self.left = true
    self.t=0
    self.on = false
end

function Starter:draw()
    if self.active then
        if self.t<self.del then
            self.t = self.t + DeltaTime
            else
            self.on=true
        end
        if self.on then
            p3.type=DYNAMIC
            if self.left ==true then
                p3.linearVelocity=vec2(500,0):rotate(math.rad(math.random(115,245)))
                else
                p3.linearVelocity=vec2(500,0):rotate(math.rad(65-math.random(130)))
            end
            self.active,self.on=false,false
        end
    end
end

function Starter:start(left)
    self.left = left
    self.t=0
    self.active = true
    p3.type=STATIC
end