Why is this code giving me Bitmap Assertion Failure?
Luna Wu
1void brickss(){ 2for (int i = 0; i < 40; i++){ 3 Bricksin.push_back(Bricksin[i]); 4 Bricksin[i] = al_load_bitmap("brick.png"); 5 for (int bricksini = 0; bricksini < 1000; bricksini = bricksini + 120){ 6 bricksinj = 0; 7 al_draw_tinted_bitmap(Bricksin[i], al_map_rgb(colorX, colorY, colorZ), bricksini, bricksinj, 0); 8 if (intersects(ball, Bricksin[i],ballX,ballY,bricksini,bricksinj)){ 9 al_set_target_bitmap(Bricksin[i]); 10 al_clear_to_color(al_map_rgb(255,255,0)); 11 ballMoveX *= -1; 12 ballMoveY *= -1; 13 } 14 } 15}

The error:Assertion failed! Expression:bitmap!=dest && bitmap!=dest->parent
I am trying to change the color of the brick upon getting hit
Note:this is just a code snippet, if you want me to display the whole code, please tell me.

Chris Katko

Which function is throwing the assert, and does the assert have any details?


- You're not checking to see if al_load_bitmap actually returns a bitmap or NULL on failure.

- There's no need to load the same bitmap from the hard drive 40 times. You could load it once and blit it to a bunch of bitmaps as necessary. But I get it that it's conceptually simpler as you're learning / developing.

- Are you sure the relevant Allegro addons have been initialized? (for example, al_init_image_addon() for images.)

[edit] Now wait a minute. You've got an intersection function in there. Are you loading the file every time you try to draw the bricks? Is that function called once, or many times? Because if it's called many times you've got memory leaks. A new bitmap is created in memory every time al_load_bitmap is called.

Luna Wu

The assertion failed error appears right when the intersection occurs, all the needed addons have been initialized in an init() function (including the one for images), I know there is a way other than vectors to draw several similar bitmaps using memory allocation, but it's still confusing me.
edit:Wait, I could change the position of loading the image to the main function, so that probem is solved now(but the assertion failure is still there).


I find this line suspicious:


Do you really mean to draw on the Bricksin bitmap? And if so, where are you setting the target bitmap to the back buffer again for the next call to al_draw_tinted_bitmap?

Luna Wu

Thank you! I set the target back to the back buffer and it's now no longer giving me the assertion failure, but the color of all the bricks changes, is there a way I can change the color of the brick that was hit only? Thank you for your patience with me.


Well, brickss() is somewhat confusing. It...

* loads resources from disk (with al_load_bitmap)
* draws to the screen
* and also updates the game objects (with ballMoveX *= -1).

Normally these three tasks are handled by separate functions. So it's hard to figure out what you're trying to achieve here. Maybe posting a bit more code would help, but I definitely recommend splitting this function and thinking about which task each function is supposed to achieve.

Luna Wu

The main function:-

1int main(){ 2 3 init(); 4 load(); 5 getBitmapWH(); 6 7 while (!done){ 8 9 al_clear_to_color(al_map_rgb(255, 255, 0)); 10 11 12 ALLEGRO_EVENT ev; 13 al_wait_for_event(eventqueue, &ev); 14 al_start_timer(timer); 15 16 17 18 if (ev.type == ALLEGRO_EVENT_TIMER){ 19 moveBall(); 20 } 21 if (ev.keyboard.keycode == ALLEGRO_KEY_LEFT){ 22 playerMoveXPositive(); 23 } 24 25 26 if (ev.keyboard.keycode == ALLEGRO_KEY_RIGHT){ 27 playerMoveXNegative(); 28 } 29 30 31 if (ballX > width || ballY > height || ballX < - 10 || ballY < - 10){ 32 ballX = 430; 33 ballY = 470; 34 } 35 36 37 if (intersects(ball, brick, ballX, ballY, xPos, yPos)){ 38 float midBallX = ballX + (ballW / 2); 39 float midPaddleX = xPos + (playerW / 2); 40 if (midBallX > midPaddleX){ 41 ballMoveX = ballMoveX*-1; 42 ballMoveY = ballMoveY*-1; 43//set bouncing angle here 44 } 45 46 47 if (midBallX < midPaddleX){ 48 ballMoveX = ballMoveX*-1; 49 ballMoveY = ballMoveY*-1; 50//set bouncing angle here 51 } 52 53 } 54 55 if (playerOutOfBounds()){ 56 xPos = 400; 57 yPos = 500; 58 } 59 60 61 62 draw(); 63 64 65 } 66 67 al_flip_display(); 68 al_rest(10); 69 70 71 }

I'm trying to display all the bricks and iterate through them to check if a collision between a brick and a ball occurs, it's hard for me to do that using separate functions, if a collision occurs, I want to change the color of the brick that collided with the ball.


A more object oriented but expensive approach is to create a struct or class for your bricks to store their state. Part of that state is if it is in the highlighted state. When you detect a collision, set brick[i].isHighlighted = !brick[i].isHighlighted

Now when you draw, draw it yellow if isHighlighted.

Chris Katko

I wouldn't have mentioned the expensive part at all. Expensive is a very relative term and often misunderstood by novices. On computers made in the last decade, OO is practically free and coefficient performance should never be considered by novices until it's an actual problem.

It's way more important to have code that makes sense and manages complexity without becoming an ugly confusing mess.


Yeah, that's a good point.

Luna Wu

Thank you jmasterx, but I'm not good at all with OOP yet, should I re-write the whole code Chris? Is it that bad?

Chris Katko
Luna Wu said:

should I re-write the whole code Chris? Is it that bad?

It's not horrible. Architecting code is a life-long endeavor and you'll constantly get better at it the more you do it.

Basically though, it's good to separate things based on their purpose.

Have an init() function, and put all the "setup" code in that function. (You can of course split that init function into sub-purposes like init allegro, loading fonts, loading bitmaps.)

Have a function related to execution of the game loop. (I just use "execute()".) Within that, you have input() (handling keyboard/joystick/etc), logic(), and draw(). In that order. You check for inputs and set relevant flags. You then run logic that affects the game (updating positions), you then draw everything.

You can decouple logic and drawing events by having them occur at different rates but it's not necessary. But notice, by keeping those functions (input, logic, and draw) separate, it would be really easy to call one more times than the other, or with delay if necessary. It's also easier to keep track of what you're doing because the only thing that happens in logic() is related to logic. The only thing that happens in draw() is related to drawing. So you'll don't have to think about things that are outside your function, and if you know you have a drawing problem, you go straight to the draw() function.

Now, then comes a problem. You're in the input function, but you want to affect something related to logic or drawing! You press a key, and you want a guy to move, or you want something special to be drawn like a message. How do you effect something outside of your function? You do it through interfaces. A specifically-defined way to access the other "aspect" of your game. If your input() function wants a character to move, you set a flag that says "move_character_left = true", and then when the logic() function gets called, it reads that value "if(move_character_left)player.x -= 10;".

The key there is, since you've "decoupled" input from logic through a defined interface (the move_character_left variable), if someone were to press the left arrow 5 times in a row before the next frame was processed, the character would only move once. Which is what you want. If logic happens 30 times a second (a typical rate), you want that character to move a maximum of YOUR_SPEED * 30 times a second. Consider the alternative: If you called the function "move left" every time the a "left arrow" event is fired, then someone could press the left key super fast (or have an outside program fake it) and move faster than expected. Also, the opposite applies. Allegro 5 only fires off an event when you press the key. If you hold the key, the event doesn't fire again! So if you want "guy/paddle/whatever" to keep moving as it is held down, you mark the flag when the key is pressed inside input(), and then unset that flag only when Allegro says the key has been unpressed.

I may be getting a bit off track and confusing, so if it is confusing, don't stress out.

Now back to what you're trying to do:

- You're trying to setup Allegro (init)
- Load resources specific to your game (the brick bitmap) (init, or a second, more specific init function)
- Read from the keyboard (input)
- Act on those keys (logic)
- Draw the result (draw)

Inside logic(), you're trying to decide whether a brick is intersecting or not.

So what you want to do, is keep track of all bricks and whether or not they have been intersected with. Then, when you get to the draw() routine, you check if "has_intersected = true" and if so, draw it another color. If not, draw the main color.

Since it appears that you want real-time colors, you will use al_draw_tinted_bitmap(). So you only need one ALLEGRO_BITMAP for the brick image, and then you draw it to the screen as many times you want with the added tint that you specify in that function. There's no need for an array of bitmaps, or multiple al_load_bitmap calls.

As amarillion and jmasterx has suggested, objects will help here. For example, you have a structure like this:

// - bricks are all the same width/height
// - There are always 100 bricks

struct brick_type{
int x;
int y;
bool has_intersected;
}bricks[100]; //array of 100 "brick_type" objects

and then:

1logic() //decide collisions here, and mark them 2{ 3 for(int i = 0; i < 100; i++) 4 { 5 if(intersect(bricks[i].x, bricks[i].y, ball.x, ball.y) 6 { 7 bricks[i].has_intersected = true; 8 }else{ 9 bricks[i].has_intersected = false; 10 } 11} 12 13draw() //draw them, based on the previous marking 14{ 15 for(int i = 0; i < 100; i++) 16 { 17 if(bricks[i].has_intersected) 18 { 19 //draw with tinted color 20 //al_draw_tinted_bitmap 21 }else{ 22 //draw normal 23//al_draw_tinted_bitmap 24 } 25}

If you want to mark whether a brick has been destroyed, you do the same thing, the same way as has_intersected. It becomes much easier to add and modify your code when things are split like this.

Luna Wu

Thank you!

Thread #616320. Printed from Allegro.cc