Bull Puckey

After a name change and a graphic overhaul, this is starting to turn into something fun.

http://www.youtube.com/watch?v=aUB7N9wQ4Sc&feature=youtube_gdata_player


Original version below…

Fiddling with the little touch example I wrote yesterday, I expanded it into a simple game. Flick the “cue puck” toward the others and try to knock them into a hole in the designated number of shots.

I’m going to rework a little to make the energy transfer more accurate, and add a few graphical touches, but it was fun to scribble this up in just a little code.



--# Circle
Circle = class()

function Circle:init(n, x, y)
    -- you can accept and set parameters here
    self.n = n
    self.x = x
    self.y = y
    self.lifted = false
    self.dx = 0
    self.dy = 0
    self.sx = x
    self.sy = y
    self.color = color(122, 122, 122, 255)
end

function Circle:draw()
    fill(self.color)
    ellipse(self.x, self.y, 50)
    fill(0, 0, 0, 255)
    if self.n > 0 then 
        text(self.n, self.x, self.y)
    end
end

function Circle:move()
    if (self.x + self.dx > WIDTH) or (self.x + self.dx < 0) then 
        self.dx = self.dx * -1 
    end
    if (self.y + self.dy > HEIGHT) or (self.y + self.dy < 0) then 
        self.dy = self.dy * -1 
    end
    self.x = self.x + self.dx
    self.y = self.y + self.dy
    
    self.dx = self.dx - (self.dx / 10)
    self.dy = self.dy - (self.dy / 10)
end

function Circle:bounce(c)
    if self:collide(c) then
        
        self.x = self.x - self.dx
        self.y = self.y - self.dy
        c.dx = c.dx + (self.dx * 0.9)
        c.dy = c.dy + (self.dy * 0.9)
        self.dx = self.dx / 10
        self.dy = self.dy / 10
    end
end

function Circle:collide(c)
    if (math.abs(self.x - c.x) < 50) and 
        (math.abs(self.y - c.y) < 50) then
        return true
    end
    return false
end

function Circle:speed()
    return math.abs(self.dx) + math.abs(self.dy)
end

function Circle:touched(touch)
    if touch.state == BEGAN then
        if math.abs(touch.x - self.x) < 30 and 
            math.abs(touch.y - self.y) < 30 then
                self.lifted = true
                self.sx = self.x
                self.sy = self.y
                return true
        end
    end
    if touch.state == MOVING and self.lifted then
        self.x = touch.x
        self.y = touch.y
        self.dx = touch.deltaX
        self.dy = touch.deltaY
        if math.abs(self.x - self.sx) > 150 or
           math.abs(self.y - self.sy) > 150 then
            self.lifted = false
        end
        
    end
    if touch.state == ENDED and self.lifted then
        self.lifted = false
    end
    return false
end


--# Main
-- PoolPuckey

displayMode(FULLSCREEN)
supportedOrientations(PORTRAIT_ANY)

function setup()
    pucks = {}
    holes = {}
    c = color(246, 246, 246, 255)
    for i = 1, 16 do pucks[i] = Circle(i-1, -111, 50) end
    pucks[1].color = color(253, 253, 253, 255)
    pucks[2].color = color(255, 236, 0, 255)
    pucks[3].color = color(65, 73, 236, 255)
    pucks[4].color = color(240, 47, 47, 255)
    pucks[5].color = color(175, 35, 156, 255)
    pucks[6].color = color(236, 91, 7, 255)
    pucks[7].color = color(45, 193, 21, 255)
    holes[1] = Circle(0,0,0)
    holes[2] = Circle(0,WIDTH,0)
    holes[3] = Circle(0,0,HEIGHT)
    holes[4] = Circle(0,WIDTH,HEIGHT)
    holes[5] = Circle(0,0,HEIGHT/2)
    holes[6] = Circle(0,WIDTH,HEIGHT/2)
    for i = 1,6 do holes[i].color = color(0, 0, 0, 255) end
    round = 1
    shotStarted = false
    setUpRound()
    font("Arial-BoldMT")
end

function setUpRound()
    for i = 1, 16 do 
        pucks[i].x = -111 
        pucks[i].dx = 0
        pucks[i].dy = 0
    end
    pucks[1].x = WIDTH / 2
    pucks[1].y = 100
    scratch = false
    if round == 1 then
        count = 1
        shots = 2
        pucks[2].x = 60 
        pucks[2].y = HEIGHT - 60
    end
    if round == 2 then
        count = 2
        shots = 3
        pucks[2].x = 60 
        pucks[2].y = HEIGHT - 60
        pucks[3].x = 60 
        pucks[3].y = HEIGHT / 2
    end
    if round == 3 then
        count = 2
        shots = 3
        pucks[2].x = 60 
        pucks[2].y = HEIGHT - 60
        pucks[3].x = WIDTH - 60 
        pucks[3].y = HEIGHT - 60
    end
    if round == 4 then
        count = 2
        shots = 3
        pucks[2].x = 60 
        pucks[2].y = HEIGHT - 60
        pucks[3].x = WIDTH - 60 
        pucks[3].y = 60
    end
    if round == 5 then
        count = 3
        shots = 3
        pucks[2].x = 60 
        pucks[2].y = HEIGHT - 60
        pucks[3].x = WIDTH - 60 
        pucks[3].y = 60
        pucks[4].x = WIDTH - 60 
        pucks[4].y = HEIGHT - 60
    end
end

function totalSpeed()
    s = 0
    for i, p in ipairs(pucks) do
        s = s + math.abs(p.dx)
        s = s + math.abs(p.dy)
    end
    return s
end

function draw()
    background(42, 90, 35, 255)
    stroke(5, 116, 238, 255)
    strokeWidth(2)
    fontSize(111)
    fill(145, 145, 145, 76)
    text("Pool Puckey", WIDTH / 2, HEIGHT / 2)
    fontSize(48)
    text("Round: " .. round, WIDTH / 2, 35)
    if shots > 0 then
        text("Shots Remaining: " .. shots, WIDTH / 2, HEIGHT - 35)
    elseif totalSpeed() < 1 then
        fontSize(96)
        fill(190, 75, 75, 255)
        if scratch then text("Scratch", WIDTH / 2, 800) end
        text("Game Over", WIDTH / 2, 700)
        fill(125, 210, 13, 105)
        text("Try Again", WIDTH / 2, 150)
    end
    if shotStarted then
        stroke(29, 130, 122, 119)
        if math.abs(startX - pucks[1].x) > 75 or
           math.abs(startY - pucks[1].y) > 75 then
            stroke(216, 92, 79, 109)
        end
        noFill()
        ellipse(startX, startY, 300)
    end
    fontSize(18)
    stroke(187, 181, 181, 255)
    for i, circle in ipairs(pucks) do 
        circle:move()
        circle:draw() 
        for k, p in ipairs(pucks) do
            if i ~= k then 
                if circle:collide(p) then circle:bounce(p) end
            end 
        end
    end
    strokeWidth(4)
    stroke(26, 46, 25, 255)
    for i, hole in ipairs(holes) do
        hole:draw()
        for k, p in ipairs(pucks) do
            if hole:collide(p) and p:speed() < 4 then 
                p.x = -111
                p.dx = 0
                if k > 1 then
                    count = count - 1
                    sound(SOUND_BLIT, 27470)
                    if count == 0 then
                        round = round + 1
                        setUpRound()
                    end
                else
                    scratch = true
                    shots = -1
                end
            end 
        end
    end
end

function touched(touch)
    if shots > 0 then 
        if pucks[1]:touched(touch) and touch.state == BEGAN then
            shotStarted = true
            startX = pucks[1].x
            startY = pucks[1].y
        end
    end
    if shotStarted and touch.state == ENDED then
        shots = shots - 1
        shotStarted = false
    end
    if shots <= 0 and touch.y < 300 and touch.state == BEGAN then
        round = 1
        setUpRound()
    end
    
end

Nice! Yet a bit too difficult…

New version

http://www.youtube.com/watch?v=aUB7N9wQ4Sc&feature=youtube_gdata_player

A couple of screen shots to show the game as it’s developing. I like this one. If you’re interested in beta testing, let me know. With some fine tuning, I think this could really work.

.@Mark that looks fantastic. Have you thought about using the “Small World:Grass Patch” and “Small World:Dirt Patch” overlays to add some texture to the grass and dirt? They might be ideal for your level designs.

It’s actually designed to be used on solid coloured circles, like you have (although a different shade of green). So you draw all the circles, then for each circle, use the grass patch overlay. This lets each circular patch blend into the adjacent patches.

You could vary the opacity and tint to get a colour that’s more in line with your characters, too.

Here’s a screenshot:

Small World

Interesting, @Simeon. I fooled around with different tints and kind of like it this way.

Looks good!

Wow - it’s a small change, but it really makes a big difference.

much, much better :wink: . Now it shows a 3d effect.

@Simeon, what’s the code look like that generated that screen? Did it get rendered back to front? I’m trying to figure out how the “circles” would be able to be placed so that things aren’t overwritten.

Updated images from latest. Got the z order sort going and took the opportunity for a big refactor of everything from graphics to collisions (I’m not using physics, because I’m just that stupid).

Anyway, pretty darn happy with how it’s coming together. I’m going to grab @Fred’s ABC Music player, and try to get some sound into this thing.

Trying again…

.@aciolino that screen is actually from Daniel Cook’s preview image on how to use his art assets. To render such a thing in Codea you would need to draw it back-to-front (as @Mark is now doing).

.@Mark that’s looking great. Glad you got the z-sort working.

Now with 100% more sheep, beavers, and owls.

http://www.youtube.com/watch?v=joa3VZ8F7tQ&feature=youtube_gdata_player

Closing in on the App Store. Seemed like a good time for a little teaser.

You video says it is Private when I try to play it.

Sorry about that. Give it another try. I couldn’t get the mobile version of Youtube to let me change it and had to wait till I got to a PC.

Looks great. Is the music on the video generated with @Fred’s ABC music player? If so, how easy was it to implement? Also have you got an ETA for getting it in the App Store?

Sorry to be deceptive. The music in the video is just one of apple’s canned iMovie tunes. For the in-game music, I’m trying old folk tunes and tweaking instrument sounds toward what I hope approximates “funky banjo.”

I’m finishing up the menu, design of the last 9 (of 36 stages) and still have some intermission screens and music to do, but I’m hoping to have it all cleaned up and submitted by Mar 1.

Looks nice! :slight_smile:

Apple has rejected BullPuckey, saying that BullPuckey is an inappropriate name.

Sheesh.

@Mark wow. I really can’t see how they reached that conclusion.

What other names are you considering?