Pong Collision
Luna Wu
#SelectExpand
1int x = 1; #include <stdio.h> 2#include <allegro5/allegro.h> 3#include "allegro5/allegro.h" 4#include "allegro5/allegro_image.h" 5#include <allegro5/allegro_native_dialog.h> 6#include <allegro5/allegro_primitives.h> 7#include <allegro5/color.h> 8#include <allegro5/allegro_color.h> 9#include <allegro5/allegro5.h> 10#include <allegro5/color.h> 11#include <allegro5/allegro_font.h> 12#include <allegro5/allegro_ttf.h> 13#include <iostream> 14 15ALLEGRO_EVENT ev; 16int main(){ 17 int d = 200; 18 int f = 200; 19 int x = 700; 20 int y = 100; 21 int a = 100; 22 int b = 100; 23 int ballx = 200; 24 int bally = 200; 25 int ballXSpeed = 5; 26 int ballYSpeed = 3; 27 bool ballmoving = true; 28 al_init_image_addon(); 29 ALLEGRO_BITMAP *Player1; 30 ALLEGRO_BITMAP *Player2; 31 ALLEGRO_BITMAP *ball; 32 ALLEGRO_DISPLAY *display = NULL; 33 34 ALLEGRO_EVENT_QUEUE *eventqueue = NULL; 35 ALLEGRO_TIMER *timer = NULL; 36 37 bool playing = true; 38 al_init(); 39 al_init_primitives_addon(); 40 display = al_create_display(800, 600); 41 al_install_keyboard(); 42 eventqueue = al_create_event_queue(); 43 timer = al_create_timer(1.0 / 60.0); 44 al_register_event_source(eventqueue, al_get_keyboard_event_source()); 45 al_register_event_source(eventqueue, al_get_display_event_source(display)); 46 al_register_event_source(eventqueue, al_get_timer_event_source(timer)); 47 Player1 = al_load_bitmap("brick.png"); 48 Player2 = al_load_bitmap("brick.png"); 49 int P1W = al_get_bitmap_width(Player1); 50 int P1H = al_get_bitmap_height(Player1); 51 int P2W = al_get_bitmap_width(Player2); 52 int P2H = al_get_bitmap_height(Player2); 53 ball = al_load_bitmap("ball.png"); 54 55 while (playing){ 56 57 58 al_clear_to_color(al_map_rgb(255, 255, 0)); 59 al_wait_for_event(eventqueue, &ev); 60 al_start_timer(timer); 61 if (ev.type == ALLEGRO_EVENT_TIMER){ 62 63 ballx = ballx + ballXSpeed; 64 bally = bally + ballYSpeed; 65 if (ballx < x+P1W && ballx>x-P1W &&bally<y+P1H && bally>y){ 66 ballXSpeed = ballXSpeed * -1; 67 ballYSpeed = ballYSpeed*-1; 68 } 69 if (ballx > a + P2W && ballx < a+P2W+10 && bally <b + P2H &&bally>b){ 70 ballXSpeed = ballXSpeed*-1; 71 ballYSpeed = ballYSpeed*-1; 72 } 73 if (ballx > 800 || bally > 600){ 74 ballx = 400; 75 bally = 400; 76 std::cout << "2 wins!" << std::endl; 77 } 78 if (ballx<-1 || bally<-1){ 79 ballx = 400; 80 bally = 400; 81 std::cout << "1 wins!" << std::endl; 82 } 83 } 84 if (ev.type = ALLEGRO_EVENT_KEY_DOWN){ 85 switch (ev.keyboard.keycode){ 86 case ALLEGRO_KEY_UP: 87 y -= 20; 88 break; 89 case ALLEGRO_KEY_DOWN: 90 y += 20; 91 break; 92 case ALLEGRO_KEY_W: 93 b -= 20; 94 break; 95 case ALLEGRO_KEY_S: 96 b += 20; 97 break; 98 99 100 } 101 } 102 103 al_draw_bitmap(Player1, x, y, 0); 104 al_draw_bitmap(Player2, a, b, 0); 105 al_draw_bitmap(ball, ballx, bally, 0); 106 al_flip_display(); 107 } 108 109 al_flip_display(); 110 al_rest(5); 111}

Hey guys, I'm making a pong game, but I've been stuck in the collision thing for a while now, the problem is when the paddles (bricks) are in a place up, the collision isn't detected and the ball passes right through them, but when they're down, it is detected and the ball bounces off. Could anyone please help?

Niunio

First of all: Put all your code inside the main function is a VERY BAD idea. You're not coding in BASIC nor Assemble (and even in that languages you can structure your code). Create a few structs (paddle, ball, brick...) and split code in functions and even in different modules (ball.c, play.c, title.c...).

See the example code included with Allegro.

Just doing that may be you find what's wrong with your code by your own.

Audric

I don't really understand the collision code, but it looks suspicious :
- when touching the right paddle or the left paddle, only the ballXSpeed should be reversed
- when touching the top or bottom, only the ballYSpeed should be reversed

Neil Roy

I created a quick pong game a couple years ago, and my collision function (you really should separate your code into functions) basically went like this...

if(bottom1 < top2) return 0;
if(top1 > bottom2) return 0;
if(right1 < left2) return 0;
if(left1 > right2) return 0;

It gets the bottom, top, left and right side (bounding box) of each object to test, then it does the above checks. if the bottom of one is higher up on the screen than the top of the other, than they are obviously not colliding. The same for the left and right sides, if the right side of one object is less than the left side of the other, than they cannot be colliding. This is better than checking to see if they overlap. If all four of the above checks fail, than you have a collision, you can then report a collision, or do further checks if you wish to have pixel perfect collision.

Another method for collision detection which is easy, is circular. You basically assign a radius to each object for collision, you then check the distance between the two objects using some simple math, and if the distance is less than the sum of the two radiuses, than you have a collision. Otherwise you do not. It's probably one of the easiest to do.

duncan perham

Write a function like bool IsRectInRect(RECT *Paddle,RECT *Ball, long Offset)
Inside that function you check if any of the 4 points on the ball are inside the paddle rect, (or the same as, or within 'Offset' pixels). If so return true. if not return false.
This function is now reusable for a lot of collision stuff.
Within it, you should actually write a IsPointInRect function and call it 4 times. That function is very handy.

Peter Hull

Hi Luna,

I love Pong; I used to have one of those things you plug into the TV!*

I would say:

  • (line 1) In your code snippet there's a stray 'int x=1;' at the top which I assume is just a copy/paste error

  • (line 60) You only need to start the timer once, outside the main loop.

  • (line 84) '=' should be '=='

I didn't fully understand what you said was wrong with it but at the moment Player 1 wins if the ball hits the top and Player 2 wins if it hits the bottom. Also the ball bounces in an unusual way, as Audric says.

In your collision code you need to take the size of the ball into account. I would do something like this: [ ball size is (BW, BH) ]

#SelectExpand
1 // Check hit bat 1 2 if (ballx < x + P1W && ballx + BW >= x && bally + BH >= y && bally < y + P1H) { 3 if (ballXSpeed > 0) { 4 ballXSpeed = -ballXSpeed; 5 } 6 } 7 // Check hit bat 2 8 if (ballx < a + P2W && ballx + BW >= a && bally + BH >= b && bally < b + P2H) { 9 if (ballXSpeed < 0) { 10 ballXSpeed = -ballXSpeed; 11 } 12 } 13 // Check going off RHS 14 if (ballx >= 800) { 15 ballx = 400; 16 bally = 300; 17 std::cout << "2 wins!" << std::endl; 18 } 19 // Check going off LHS 20 if (ballx < 0) { 21 ballx = 400; 22 bally = 300; 23 std::cout << "1 wins!" << std::endl; 24 } 25 // Check top and bottom 26 if (bally < 0 || bally + BH >= 600) { 27 ballYSpeed = -ballYSpeed; 28 }

The bouncing is still not right though, IIRC in pong you can control the angle of the bounce by where it hits on the paddle. I didn't have time to implement that.

* Yeah baby! http://www.old-computers.com/museum/computer.asp?st=3&c=1038

Luna Wu

It was indeed a problem with the logic of the if statements, I fixed it now, I'm still gonna do the angle thing and fix lots of weird things, I was just trying to at least make the ball bounce at first :D, I gotta be careful with the logic this time ;D thank you so much for the help guys! :) I'm aware putting everything in main is a bad idea, but that's one of my first allegro5 projects so I found it a little hard to make split functions, I don't know why I found it hard though, ;D, thank you :)

Thread #616191. Printed from Allegro.cc