12
\$\begingroup\$

For a Peggle-like game, I want to make blocks that follow a curve, like this:

blocks along a curve

The blocks would then disappear as the ball hits them.

I managed to draw some horizontally, but I'm having trouble making them follow a path:

my attempt at path-following blocks

How do I do this? Do I need to create Box2D objects with custom vertices?

\$\endgroup\$
7
  • \$\begingroup\$ Do you want the boxes to simply not overlap or do you want there to be no gaps anywhere? (I'm not exactly sure what you mean by "offsetting the object Y axis according to the object angle"). \$\endgroup\$
    – Roy T.
    Feb 19, 2014 at 14:51
  • 1
    \$\begingroup\$ You can't fill a curve with non-overlapping rectangles, so you're going to have to create some custom geomety if you want no gaps. \$\endgroup\$ Feb 19, 2014 at 14:58
  • \$\begingroup\$ @RoyT. The gaps aren't important. My real problem is to compute the position of the block which follow each other with different angle. \$\endgroup\$
    – Moerin
    Feb 19, 2014 at 15:11
  • \$\begingroup\$ The way I would approach this is to define a series of vertices that act as the common corners between each box. Even using a path to define them, you still need additional parameters to define the distance between the vertices and how long each box is. \$\endgroup\$
    – user39686
    Feb 19, 2014 at 15:19
  • 4
    \$\begingroup\$ The "boxes" on the first image are not boxes, they are pairs of triangles: i.stack.imgur.com/Tzuql.png \$\endgroup\$
    – egarcia
    Feb 19, 2014 at 15:46

1 Answer 1

14
\$\begingroup\$

Given a "root" curve, here's how you might generate block vertices.

Bézier with blocks

The root curve is in the middle, in black. Its control points are shown with red Xs.

In short: I made a Bézier and sampled it (at a configurable rate). I then found the perpendicular vector of the vector from each sample to the next, normalised it, and scaled it to to a (configurable) half-width, first to the left, then inversely to the right. Then drew it.

Stuff you could add to this:


Here's my code. It's written in Lua (for the LÖVE game framework), but I think it's readable for anyone.

local v = require "vector"

-- A function that makes bezier functions
-- Beziers have start point     p0
--              control point   p1
--              end point       p2
local function makeBezierFunction(p0,p1,p2)
    return function (t)
        local pow = math.pow
        return pow( (1-t),2 ) * p0
               + 2 * (1-t) * t * p1
               + pow(t,2) * p2
    end
end

love.graphics.setBackgroundColor(255, 255, 255)
function love.draw()
    local line = love.graphics.line
    local colour = love.graphics.setColor

    -- Bezier sampling parameters
    local nSegments = 10
    local segIncr = 1/nSegments

    -- Bezier definition: Start (`p0`), control (`p1`) and end `p2`) point
    local p0 = v(100,100)
    local p1 = v( love.mouse.getX(), love.mouse.getY() )
    local p2 = v(500,100)
    local controlPoints = {p0,p1,p2}
    local bez = makeBezierFunction(p0,p1,p2)

    -- Sample the bezier
    for i=0,1-segIncr,segIncr do
        colour(0, 0, 0)
        local x1,y1 = bez(i        ):unpack()
        local x2,y2 = bez(i+segIncr):unpack()
        line(x1,y1,x2,y2)

        -- Find left and right points.
        local center = v(x1, y1)
        local forward = v(x2, y2) - center
        local left = center + forward:perpendicular():normalize_inplace() * 10
        local right = center - forward:perpendicular():normalize_inplace() * 10

        -- Draw a line between them.
        line(left.x, left.y, right.x, right.y)

        -- Find *next* left and right points, if we're not beyond the end of
        -- the curve.
        if i + segIncr <= 1 then
            local x3, y3 = bez(i+segIncr*2):unpack()
            local center2 = v(x2, y2)
            local forward2 = v(x3, y3) - center2
            local left2 = center2 + forward2:perpendicular():normalize_inplace() * 10
            local right2 = center2 - forward2:perpendicular():normalize_inplace() * 10

            -- Connect the left and right of the current to the next point,
            -- forming the top and bottom surface of the blocks.
            colour(0, 0xff, 0)
            line(left.x, left.y, left2.x, left2.y)
            colour(0, 0, 0xff)
            line(right.x, right.y, right2.x, right2.y)
        end
    end

    -- Draw an X at the control points
    for _,p in ipairs(controlPoints) do
        local x,y = p:unpack()
        colour(0xff,0x00,0x00)
        line(x-5,y-5, x+5,y+5)
        line(x-5,y+5, x+5,y-5)
    end
    -- Draw lines between control points
    for i=1,#controlPoints do
        colour(0xff,0x00,0x00, 100)
        local cp1 = controlPoints[i]
        local cp2 = controlPoints[i+1]
        if cp1 and cp2 then
            line(cp1.x, cp1.y
                ,cp2.x, cp2.y)
        end
    end
end

If you'd like to play with it: Get LÖVE and put the above code into main.lua in its own directory. Put vector.lua from the HUMP library in the same directory. Run it as love <that-directory> from a command line.

Move the mouse around! The middle control point is set to the mouse location:

Setting control point with mouse

\$\endgroup\$
4
  • \$\begingroup\$ Anko have u tried LibGdx? if so, do u prefer Löve? I am moving away from using standard android API after my current game and Im trying to decide between LibGdx and Löve. Interesting answer above as always btw \$\endgroup\$
    – Green_qaue
    Feb 19, 2014 at 18:20
  • \$\begingroup\$ @Anko Thanks a lot, it's more than i expected. More i think i can easly understand your code since i use MonkeyX for my game which is similar to LUA. \$\endgroup\$
    – Moerin
    Feb 19, 2014 at 18:42
  • 1
    \$\begingroup\$ @iQ I haven't used Libgdx, but I've read lots about it and I know Java well. Libgdx is big. (It has accelerometer support, built in curve generators and everything), while Love2D is very small (it doesn't have any of those, theres' no shader support, etc). Thanks to its simplicity though, Love2D has been great for quick prototypes and small games, but it might be too minimalist for some projects. Who knows. (You do! Try it and see. :D) \$\endgroup\$ Feb 19, 2014 at 18:57
  • \$\begingroup\$ Great answer, and that GIF is really a nice bonus! \$\endgroup\$
    – Roy T.
    Feb 25, 2014 at 12:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .