Getting the color of a background pixel
agonvs

I'm trying to do a color-based collision type of thingy. Basically, I'm going through the grid of background pixels under a sprite one by one to see what color they are, and if they aren't black, BOOM!

Here's my code:

    for (int i = 0; i < 32; i++)
      for (int j = 0; j < 32; j++)
      {
        bkgd = al_get_pixel(al_get_backbuffer(display),x+j,x+i);
        if (bkgd == (al_map_rgb(0,0,0)))
          alive = false;
      }

And the errors:

1>------ Build started: Project: shell, Configuration: Release Win32 ------
1>  looney.cpp
1>looney.cpp(85): error C2678: binary '==' : no operator found which takes a left-hand operand of type 'ALLEGRO_COLOR' (or there is no acceptable conversion)
1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\exception(470): could be 'bool std::operator ==(const std::_Exception_ptr &,const std::_Exception_ptr &)'
1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\exception(475): or       'bool std::operator ==(std::_Null_type,const std::_Exception_ptr &)'
1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\exception(481): or       'bool std::operator ==(const std::_Exception_ptr &,std::_Null_type)'
1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\system_error(408): or       'bool std::operator ==(const std::error_code &,const std::error_condition &)'
1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\system_error(416): or       'bool std::operator ==(const std::error_condition &,const std::error_code &)'
1>          C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\guiddef.h(192): or       'int operator ==(const GUID &,const GUID &)'
1>          while trying to match the argument list '(ALLEGRO_COLOR, ALLEGRO_COLOR)'
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

I found some code online which helpeed me get this working, but now, while the color collision detection works, it's incredibly slow. In the allegro manual for al_get_pixel it says to consider locking the bitmap if you're going to be using the function. Well, I locked the bitmap and the frame rate went back to normal but now the collision code no longer works! What's going on?

Thoughts?

StevenVI

Since Allegro 5 is a C library, there's no default comparator provided to overload the == operator. It's entirely possible that two pixels will have the same color but use different instances of the ALLEGRO_COLOR struct to describe it. You'll want to write your own comparator for that.

However, I do not believe that your approach for collision detection is efficient. :) Take a look at the wiki article on Pixel Perfect Collision.

jmasterx

al_get_pixel is an extremely expensive operation in Allegro5. The 'faster' way is to use bitmap locking, but really, you should either try to represent your objects as convex polygons, rectangles, or circles. It is very hard to get good performance for pixel-perfect using hardware-accelerated graphics techniques.

devo_au

You still working on your arkanoid? If so maybe better to use a bounding box collision technique. This might help http://fixbyproximity.com/2011/12/14/2d-game-dev-part-12-1-bounding-rectangle-collision-detection/

agonvs

No, I'm working on a lunar lander clone and I need to collide with the irregular-shaped lunar surface.

LennyLen
agonvs said:

No, I'm working on a lunar lander clone and I need to collide with the irregular-shaped lunar surface.

If you make your irregular surface a collection of line segments, you can do collision detection against those.

devo_au
agonvs

I found a good solution to this. I ran a routine that converted the image to a grid of bools (or "bitmask"), then saved the grid to a file. I then loaded it up the next time I ran it, then compared the sprite area to the corresponding area in the bool grid for any truth values. This collision detection algorithm works great and runs at full speed. I've included my code for your perusal.

Chris Katko

You don't need pixel perfect for a lunar lander. You can get away with point collision. They did it in the game Clonk Planet (and various other sequels).

You have your object.

You list points relative to the center of that object.

Every frame you check ONLY those points to determine if a collision has occurred with your pixel map world.

{"name":"1351269062.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/2\/1\/21e341c534fdd4b0de74f1511ca2816e.jpg","w":640,"h":480,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/2\/1\/21e341c534fdd4b0de74f1511ca2816e"}1351269062.jpg

This game ran every object that way and it rarely failed. And it long predates Minecraft for having gigantic, computer-intesive maps.

So say you have a guy, like in this game. You have one point at the top of his head, one in the center of his feet, and on his right and left side (and center height.) A mere four points that works in 90% of cases, and each point can be linked to specific events. So someones head being touched triggers the guy to get knocked over, verses his feet touching the ground.

In your case, you can use one for each landing gear leg, one on the top, and two at the sides. That's a mere 5-points.

[edit]

Here's a diagram of what I'm talking about. The red diamonds are the points you scan every frame.

{"name":"609359","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/e\/3\/e3d4c12ef965376b88aa469b7fc14daa.gif","w":394,"h":330,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/e\/3\/e3d4c12ef965376b88aa469b7fc14daa"}609359

Of course, you can use more points as necessary, like one in the bottom center to prevent landing on a tall spike from being detected.

agonvs

Yes Chris you could use just those points. But you would still need to check those points against some kind of bitmask for the lunar surface, would you not?

Chris Katko

It depends on how you structure things, but yes. If you've got a simple "a bitmap/array is my world map", it's as simple as:

#SelectExpand
1 2const int NUM_OF_POINTS = 5; 3int my_map[100][100]; //where 0 implies empty 4 5class point{ 6int x; //relative to object center 7int y; 8}; 9 10class my_object 11{ 12int x; 13int y; 14point points[NUM_OF_POINTS]; //set these somewhere 15 16bool is_colliding(); 17//... 18} 19 20bool my_object::is_colliding() 21{ 22for(int i = 0; i < number_of_points; i++) 23 { 24 if(my_map[ x + points[i].x ][ y + points[i].y ] != 0)return true; 25 } 26return false; 27}

And most of that is boilerplate just so you can see what everything means.

It works very well for objects against a bitmap world collision detection. As for "objects against objects" that's different but can still be done.

Lastly, pixel-perfect collision is usually performed only AFTER a bounding box test has been performed. If two objects aren't crossing bounding boxes, then they absolutely aren't going to be colliding on a pixel level. So you go bounding box first and if that says yes, you can go more accurate by performing pixel then. It saves a lot of time instead of comparing pixels to pixels for objects nowhere near each other.

Thread #615236. Printed from Allegro.cc