AABB’s for complex objects in lua.

I touched on complex objects a bit in my previous collision detection post, and now I plan to talk more about them.  Specifically, creating AABB‘s for complex objects, and drawing complex objects.  You can find the example löve file here.

For the purposes of this post, I will define a complex object as a set of points that are connected in a specific order to create a shape.  What do I mean by that?  Something along the lines of this:

obj1 = {{10, 50},{20, 30},{30, 70},{70, 90},{20, 10},{70, 30}}

That would create this object:

Image broken, use link untill I fix it.

I have created 2 useful functions when dealing with complex objects.  A function to draw a complex object, and a function to calculate the AABB of a complex object.

To draw a complex object, use this:

function drawcompobj(obj)
    local ppx = obj[#obj][1]
    local ppy = obj[#obj][2]
    for i=1, #obj, 1 do
        love.graphics.line(ppx, ppy, obj[i][1], obj[i][2])
        ppx = obj[i][1]
        ppy = obj[i][2]
    end
end

Line by line, here’s what it does:

    local ppx = obj[#obj][1]
    local ppy = obj[#obj][2]

This sets ppx and ppy to the last coordinates in the array.  these will be used as the starting point for each line it draws.

for i=1, #obj, 1 do

This loops through all of the coordinates in the array “obj.”  We will draw a line for each one of these points.

love.graphics.line(ppx, ppy, obj[i][1], obj[i][2])

This draws a line from the previous point to the current point.

ppx = obj[i][1]
ppy = obj[i][2]

This sets the previous points to the current points.

I also have a way to get an AABB for a complex object.  All this does is loops through all of the points, and gets the biggest and smallest X’s and Y’s.  Here is the code:

function makeaabb(obj)
    local minx, maxx, miny, maxy = obj[1][1], obj[1][1], obj[1][2], obj[1][2]

    for i=1, #obj, 1 do
        if obj[i][1] > maxx then maxx = obj[i][1] end
        if obj[i][1] < minx then minx = obj[i][1] end
        if obj[i][2] > maxy then maxy = obj[i][2] end
        if obj[i][2] < miny then miny = obj[i][2] end
    end

    return {minx, miny, (maxx - minx), (maxy - miny)}
end

Here’s what it does, line by line:

local minx, maxx, miny, maxy = obj[1][1], obj[1][1], obj[1][2], obj[1][2]

This sets the default minimum and maximum values for X and Y.

for i=1, #obj, 1 do

This loops through all of the points in the complex object.

if obj[i][1] > maxx then maxx = obj[i][1] end
--Other similar stuff.

This sets the current highest x value to reflect it being compared to the previous highest x value.  The other 3 lines do basically the same thing.

return {minx, miny, (maxx - minx), (maxy - miny)}

This returns the x, y, width and height of the complex object.

I hope you find these functions useful, or at least that you enjoyed reading about them.

Once again, you can find the example löve file here.

Looping multiple songs in flashpunk

Hello!  Today I’m going to talk about looping multiple songs in flashpunk.  If you just want to loop one song, you can simply call:

soundeffect.loop();

But if you want multiple songs located in separate files to loop, then it gets harder.  I use the following code:

[Embed(source = '../assets/music/song1.mp3')] private const BGMusicEmbed1:Class;
public var BGMusic1:Sfx = new Sfx(BGMusicEmbed1);
[Embed(source = '../assets/music/song2.mp3')] private const BGMusicEmbed2:Class;
public var BGMusic2:Sfx = new Sfx(BGMusicEmbed2);

public var tracks:Array = new Array(BGMusic1, BGMusic2);
public var musicplaying:Boolean = false;
//...
//...

//Inside update loop:
musicplaying = false;

for (var i:Number = 0; i < tracks.length; i ++)
{
    if (tracks[i].playing)
    {
        musicplaying = true;
    }
}

if (!musicplaying)
{
    tracks[FP.rand(tracks.length)].play()
}

Now I’ll explain what that does.

The first 5 lines embed 2 songs and put them in a array.

The first for loop finds out if any of the songs are playing.  If none are playing, it sets musicplaying to false.

The if statement plays a random song from the array if no songs are playing at the moment.

There are a number of ways this could be improved.  It could keep track of the song it was last playing and make sure not to play it twice in a row.  It could also loop through them, shuffling the array each time, so that it will have the maximum amount of time between each song repeating while still playing a random song.  This snippet is just a *simple* song manager.

 

Point – Object Collision

After writing yesterday’s post, I noticed that I missed one big category of collisions: Point – Object collisions.  This is where a you check if a single XY pair is inside a object.  In this example I’ll use circles and squares, but you could use the algorithms that I wrote about in yesterday’s post with this method.

The technique is fairly simple.  For a square, all you have to do is check if the XY pair is inside a box.  The lua code looks like this:

function RectPoint(ax, ay, aw, ah, bx, by)
    return bx > ax and bx < ax + aw and by > ay and by < ay + ah 
end

All that this code does is checks if:

  1. the point’s X is greater then the rectangle’s X.
  2. The point’s X is less then the rectangle’s X + the rectangle’s width.
  3. the point’s Y is greater then the rectangle’s Y.
  4. the point’s Y is less then the rectangle’s Y + the rectangle’s height.

If these are all true, then it will return true, because the point is inside the rectangle.

The circle code is slightly more complex:

function CirclePoint(ax, ay, bx, by, ar)
    local dx = bx - ax
    local dy = by - ay
    local dist = math.sqrt(dx * dx + dy * dy)
    return dist < ar
end

This is essentially the same as the Distance Based Collision function that I wrote about in my previous post, except instead of taking 4 XY pairs and 2 radii, it takes 4 XY pairs and one radius, assuming that the other radius is zero.

For a example of these 2 functions in action, you can download the .love example file.  Feel free to use these functions in any way you wish.  If you want a license, use Creative Commons Zero.  If you have any questions, just comment, and I’ll try to help.

Loading levels from images

Today I was working on a snippet that will allow you to load png files into löve2d, in a format accepted by YellowAfterLife’s Platformer engine (Although with minor edits, you could make it export to any format).  Without further ado, here is the code:

function imgtolvl(file, key)
    local lvl = {}
    local lvltxt = ''
    local img = love.image.newImageData(file)
    for y=1, img:getHeight(), 1 do
        for x=1, img:getWidth(), 1 do
            local r, g, b, a = img:getPixel(x-1, y-1)
            for c=1, #key, 1 do
                if key[c][1] == r..'.'..g..'.'..b then
                    lvltxt = lvltxt..key[c][2]
                end
            end
        end
    end
    table.insert(lvl, img:getWidth())
    table.insert(lvl, img:getHeight())
    table.insert(lvl, file)
    table.insert(lvl, lvltxt)
    return lvl
end

All you will need is a array (key) and a image (file)  The array should look like this:

key = {
     {'0.0.0', 'x'},
     {'0.255.0', 'g'},
     {'10.10.10', 'w'},
     {'100.100.100', 'p'},
     {'255.255.255', ' '},
 }

The numbers that you see are RGB pairs, so ‘255.255.255’ would be white.  the second string is the character that it will use in the final array.  In the engine, a space is air, so a white pixel would be air.

You will also need to update your level.next function.  Replace this:

d = level.levels[level.current]

with this:

d = imgtolvl(level.levels[level.current], level.key)

I hope that you find this snippet as useful as I do!