1
\$\begingroup\$

Is this possible?

To elaborate, I am making a PacMan offshoot. Essentially it is a "zoomed in" version of the game, but the board is randomly generated. I have 11 .png files each to be used as a background for different hallway shapes. You have your straightaways, corners T junctions and cross intersection. They are very simple, each has a black background and the walls are blue. What I am looking for is a way to stop the player from walking on the blue parts of each image. Is that possible?

My current set-up is that I have a Piece class that holds the image, Entry points as bools (up down left right) for when I randomly select the image to be used so that a path can be created, size, etc. I then have a Board class that holds a list of Pieces (size 11 (One for each image))) and then 2D an array "board" (currently 9x9) that randomly but intelligently generates the map. When it comes to player pathing, I was manually going to add to the Piece class code that adds invisible rectangles over the blue walls and then have the Player class, or some other class, check for collision. This would take a ton of extra code because each image is different so each would need to be manually done.

I was just thinking there must be an easier way to do this, and the whole color idea occurred to me. If i could just check if it intersects the blue and then change its position back that would be much easier.

I am at work currently, but if there is any code you would need to see, or any other helpful information let me know and I will add it as soon as I get home!

TL;DR Is there a way to check collision via color, or add rectangle automatically over a specific color.

\$\endgroup\$
3
  • \$\begingroup\$ Related: gamedev.stackexchange.com/questions/38851/… \$\endgroup\$
    – House
    Jan 15, 2014 at 1:28
  • \$\begingroup\$ @Byte56 what I'm gathering from that thread, is that I was on the right track doing the bounding boxes? The biggest issue between that thread and my question is that I'm not dealing with any specific objects to check collision against, Its just a background image that will scroll to the next tile as you move and will contain three or more walls. These images take up the whole screen so there would be a lot of extra work to do it that way. If that is the best option though, I am more than willing to do it the way I originally planned. I hope that helps clarify a bit. \$\endgroup\$
    – Nick
    Jan 15, 2014 at 2:40
  • \$\begingroup\$ It's possible to do it both ways. You may find the alternative to be more work, but you may also find it to be worth it performance wise. I suggest you try it the easy way first, then move on to the more challenging way if you find the performance lacking. \$\endgroup\$
    – House
    Jan 15, 2014 at 3:04

2 Answers 2

1
\$\begingroup\$

I wouldn't even try to use pixel perfect collisions for this. Given the fact that you've got a limited and fixed amount of possible tiles as well as pretty simple rules ("allow player to leave the tile in some direction or not"), I'd just work with a bitmask/property for your tiles.

For example, you could create an enum with the possible directions:

enum TileFlags
{
    BorderTop    = 0x01,
    BorderBottom = 0x02,
    BorderLeft   = 0x04,
    BorderRight  = 0x08,
    Solid        = 0x0f
};

Every tile would then store its own bitmask defining the directions that are enclosed/sealed-off:

struct TileData
{
    uint spriteOffset; // used for drawing
    uint flags;        // define the tile's behavior
}

For example, to define a tile that has a border on the top and right borders, you could set its flags like this:

tiles[someIndex].flags = BorderTop | BorderRight;

When determining, whether the player is able to leave that tile to the right (or get close to the right border; depends on your implementation):

bool may_move = (tiles[someIndex].flags & BorderRight) == 0;

This will also allow you to add even more tile flags later on, for example you could create ice fields, acceleration pads, mud slowing you down, teleports, etc. Just add a new enum member and then use it when doing your checks.

\$\endgroup\$
0
\$\begingroup\$

An option would be to process the images once, when they are loaded. Grab the pixel data, and process it to determine the smallest Rectangle that encompasses all the pixels of a specific color.

This isn't a pixel perfect collision, but it will help with processing your images, and getting collision boxes for you.

You can further optimize this by storing the bounds in a data file, instead of running it every time you execute the binary. But if you just do it during your game load phase, it should be relatively fast, considering you have a relatively small number of images to process.

//Get smallest rectangle from Texture, cased on color
Rectangle GetSmallestRectangleFromTexture(Texture2D Texture, Color color)
{
    //Create our index of sprite frames
    Color[,] Colors = TextureTo2DArray(Texture);

    //determine the minimum bounds
    int x1 = 9999999, y1 = 9999999;
    int x2 = -999999, y2 = -999999;

    for (int a = 0; a < Texture.Width; a++)
    {
        for (int b = 0; b < Texture.Height; b++)
        {
            //If we find a color match, update bounds if needed
            if (Colors[a, b] == color)
            {
                if (x1 > a) x1 = a;
                if (x2 < a) x2 = a;

                if (y1 > b) y1 = b;
                if (y2 < b) y2 = b;
            }
        }
    }

    //We now have our smallest possible rectangle for this texture
    return new Rectangle(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
}

//convert texture to 2d array
Color[,] TextureTo2DArray(Texture2D texture)
{
    //Texture.GetData returns a 1D array
    Color[] colors1D = new Color[texture.Width * texture.Height];  
    texture.GetData(colors1D);  

    //convert the 1D array to 2D for easier processing
    Color[,] colors2D = new Color[texture.Width, texture.Height]; 
    for (int x = 0; x < texture.Width; x++) 
        for (int y = 0; y < texture.Height; y++)
            colors2D[x, y] = colors1D[x + y * texture.Width];

    return colors2D; 
}

This is not exactly what you are asking, but I think this could help you.

Edit: Write up a blog post about this: http://www.jgallant.com/auto-calculating-bounding-box-from-texture-in-monogame-xna/

\$\endgroup\$
2
  • \$\begingroup\$ This doesn't quite solve my issue. I will need many rectangles because not all of the blue touches. for example on a intersection the four corners are blue squares and the rest is black, giving the look of a hallway or road intersection. I might be able to work off of this however! \$\endgroup\$
    – Nick
    Jan 17, 2014 at 0:02
  • \$\begingroup\$ @Nick Another idea would be to use the Rectangle as a first step collision detection, and then possibly run a per-pixel collision check only if the Rectangle collides. Per-pixel is really not an optimal collision check, but depending on the size of your textures, it might be fine. \$\endgroup\$
    – jgallant
    Jan 17, 2014 at 0:26

You must log in to answer this question.

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