Collision Detection with a rotating square.
Darren Hoehna

Hey there Allegro goers,

I have a square bitmap that I am able to move around the screen. The left and right keys rotate the bitmap, the up key is to move the bitmap in the direction the bitmap is facing, and the down key is used to move the bitmap in the opposite direction the bitmap is facing.

Now that I have the movement down I am on to collision detection. I learned from http://wiki.allegro.cc/index.php?title=Allegro_5_Tutorial/Bitmaps about border detection, but that was with a square that did not rotate.

My question is how do I go about seeing if the square has collided with the display?

My first, and only, thought was to keep track of the four corners of the square and see if any of them are overlapping the display but I don't know how to keep track of the points through the rotation.

I also just don't know where to start with solving this problem.

Thanks,

Darren.

Trent Gamblin

The easiest way to do this is to use transforms right from the start, if you're not already. When you draw the square you'd do something like:

```al_rotate_transform(&t, angle);
al_use_transform(&t);
al_draw_filled_rectangle(x1, y1, x2, y2, color);
```

Hold onto the transform, t. When you do collision detection, you'd use the transform again:

```float x = x1;
float y = y1;
al_transform_coordinates(&t, &x, &y);
if (x < 0 || x >= SCREEN_WIDTH || y < 0 || y >= SCREEN_HEIGHT) {
/* collided */
}
/* check another point... */
x = x2;
y = y1;
/* and so on for all 4 points */
```

al_transform_coordinates will apply the same transform to the point x, y as was applied to the square, so you'll get the position after the rotation.

Darren Hoehna

I never knew there was such a thing. I'll give it a try and reply back. Thanks.

Neil Roy

You could also use circular collision detection. It's actually easier to use that a box, though perhaps not as accurate if you have a square object, it works quite well.

It's really easy. In this case SPRITE is just a struct containing the x, y co-ordinates on screen of the center of the sprite, and the radius (r) of the circle from that center to check.

```bool collision(SPRITE *sprite1, SPRITE *sprite2)
{
double dist_x = (double)sprite1->x - (double)sprite2->x;
double dist_y = (double)sprite1->y - (double)sprite2->y;

// The distance of the vector between the two
double dist = sqrt((dist_x * dist_x) + (dist_y * dist_y));

// is the distance less than or equal to the absolute sum of the two radiuses?
// returns true is it is (collision) false if they're too far apart.
return dist <= abs(sprite1->r + sprite2->r);
}
```

Edit: Sorry just realized you asked about a collision with the DISPLAY, this is with two sprites. You could still use the same idea, test the radius and see if it is less than the left edge, greater than the right edge etc.

AmnesiA

I did not know about al_transform_coordinates either, that is freakin awesome.

jmasterx

If you are interested in OBB (Oriented Bounding Box) collision, one way to do it that's not too complex is Separate Axis Theorem.

http://www.jkh.me/files/tutorials/Separating%20Axis%20Theorem%20for%20Oriented%20Bounding%20Boxes.pdf

It's beyond your needs for this, but it might be interesting for future projects.

Darren Hoehna

Umm, I have tried and tried but I don't understand how to start using transformations.

Edgar Reynaldo

Transforms aren't too difficult to understand if you know what they are doing.

First, start with an identity transform. This is a transform that will not alter any coordinates passed to it.

```ALLEGRO_TRANSFORM t;
al_identity_transform(&t);
```

Second, apply in order each transformation that you need.

```al_translate_transform(&t , -camx , -camy);
al_scale_transform(&t , (double)SCREEN_WIDTH/BUFFER_WIDTH , (double)SCREEN_HEIGHT/BUFFER_HEIGHT);
```

These two transforms apply a translation (movement) and a scale (stretching).

Now you need to use the transform :

```al_use_transform(&t);
```

Now everything you draw will be shifted by (-camx , -camy) pixels and scaled from buffer size to screen size.

If you want to transform coordinates manually, use al_transform_coordinates.

```float x = player.x;
float y = player.y;
al_transform_coordinates(&t , &x , &y);
```

Now x and y hold the screen coordinates of the player after applying the camera transformation.

Darren Hoehna

Well, good news is I got it working. Bad news is that it's not working correctly. Here are the transformations I have now to rotate the square.

al_translate_transform(&ShipTransformation, -Ships_X_Position, -Ships_Y_Position);
al_rotate_transform(&ShipTransformation, -CHANGE_IN_ANGLE);
al_translate_transform(&ShipTransformation, Ships_X_Position, Ships_Y_Position);
al_transform_coordinates(&ShipTransformation, &UpperLeft.X, &UpperLeft.Y);
al_transform_coordinates(&ShipTransformation, &UpperRight.X, &UpperRight.Y);
al_transform_coordinates(&ShipTransformation, &LowerLeft.X, &LowerLeft.Y);
al_transform_coordinates(&ShipTransformation, &LowerRight.X, &LowerRight.Y);

And it works. I then call al_draw-filled rectangle and pass in the x and y coordinates of the upper left, and lower right corners.

The problem is that as the square rotates the corners soon meet up on the same vertical or horizontal line. I don't know how to explain it. So I'll draw it.

-----
| |
| |
-----

--------
| |
--------

----------

--------
| |
--------

-----
| |
| |
-----

---
| |
| |
| |
---

|
|
|
|
|

The problem is with the al_draw_rectangle because it is defined on only two points. Is there another drawing I can use that I can use all four points?

Werwolf696

I'm working on a similar task, I got my bounding box (rectange) to display correctly as follows:

1al_identity_transform(&trans); 2al_translate_transform(&trans, -Origin.x, -Origin.y); 3al_rotate_transform(&trans, RotationAngle); 4al_translate_transform(&trans, Origin.x, Origin.y); 5al_use_transform(&trans); 6al_draw_rectangle(BoundingBox.x, BoundingBox.y, BoundingBox.x + BoundingBox.w, BoundingBox.y + BoundingBox.h, al_map_rgba_f(0.6, 0, 0.6, 0.6), 1.0); 7al_use_transform(&identity);

Without seeing your draw call, I can only assume you are not using it correctly by adding the width to the x coordinate to get "x2" and the height to y to get "y2".

Can you post your rectangle draw line of code?

Darren Hoehna

I can post my code. Also, thank you for helping me.
I have structures that holds two floats, one for a X-coordinate and one for a Y-coordinate.

With this code I can see the square change shape

al_translate_transform(&ShipTransformation, -Ships_X_Position, -Ships_Y_Position);
al_rotate_transform(&ShipTransformation, -CHANGE_IN_ANGLE);
al_translate_transform(&ShipTransformation, Ships_X_Position, Ships_Y_Position);
al_transform_coordinates(&ShipTransformation, &UpperLeft.X, &UpperLeft.Y);
al_transform_coordinates(&ShipTransformation, &UpperRight.X, &UpperRight.Y);
al_transform_coordinates(&ShipTransformation, &LowerLeft.X, &LowerLeft.Y);
al_transform_coordinates(&ShipTransformation, &LowerRight.X, &LowerRight.Y);

al_draw_filled_rectangle(UpperLeft.X, UpperLeft.Y, LowerRight.X, LowerRight.Y, al_map_rgb(255, 128, 64));
al_identity_transform(&ShipTransformation);
al_use_transform(&ShipTransformation);

But if you omit the al_transform_coordinates then the square rotates and move like the square is rotating but the square does not visually rotate.

Edgar Reynaldo

@Darren - you're not using transformations quite right. Instead of manually transforming coordinates and then drawing a rectangle over them, let allegro use the transform to draw the rectangle from the original coordinates.

```CHANGE_IN_ANGLE = 0.034906585 (rad)
al_identity_transform&(&ShipTransformation);
al_translate_transform(&ShipTransformation, -Ships_X_Position, -Ships_Y_Position);
al_rotate_transform(&ShipTransformation, -CHANGE_IN_ANGLE);
al_translate_transform(&ShipTransformation, Ships_X_Position, Ships_Y_Position);
al_use_transform(&ShipTransformation);
al_draw_filled_rectangle(UpperLeft.X, UpperLeft.Y, LowerRight.X, LowerRight.Y, al_map_rgb(255, 128, 64));
al_identity_transform(&ShipTransformation);
al_use_transform(&ShipTransformation);
```

Don't use these because they modify the contents of UpperLeft.X and UpperLeft.Y and so on

```al_transform_coordinates(&ShipTransformation, &UpperLeft.X, &UpperLeft.Y);
al_transform_coordinates(&ShipTransformation, &UpperRight.X, &UpperRight.Y);
al_transform_coordinates(&ShipTransformation, &LowerLeft.X, &LowerLeft.Y);
al_transform_coordinates(&ShipTransformation, &LowerRight.X, &LowerRight.Y);
```

I think this will work, try it. I got a paper I got to write.

AmnesiA

This might be an incredibly stupid question but how does al_rotate_transform know how big the rectangle is? Obviously a bigger rectangle means larger change in coordinates based on an angle

J-Gamer
AmnesiA said:

This might be an incredibly stupid question but how does al_rotate_transform know how big the rectangle is? Obviously a bigger rectangle means larger change in coordinates based on an angle

Actually, al_rotate_transform just multiplies the current transformation matrix with a rotation matrix. If you use al_use_transform, OpenGL/DirectX will multiply all coordinates it draws to with that matrix, thus performing the rotation.
It doesn't matter what you draw

Darren Hoehna

That does work. Almost. The square is rotated and the square acts like it has been rotated when I move the square forward. The only problem is that the display draws the square with only one rotation and when I let go of the left or right key the square returns to normal, but the rotation is kept.

But I am using what you gave me and it should work.

Any ideas? I can give you the code so you can see what I am doing.

Also good luck on your paper.

Edgar Reynaldo

Thanks, got it done and met all the reqs too.

If your code is not working still, post what you have. You have to rebuild the transform each time your rectangle changes angle or position, and reset it every time you don't need one.

Darren Hoehna

Glad you got it done. My school starts on the 26th. I have started a new project so I can play with translations. I'll post what I have in a few days.

Edgar Reynaldo

Darren Hoehna

Thanks for the bump. Here is what I have. I am only including the code for moving the square up and rotating it to the left.

1#include <allegro5/allegro.h> 2 3float ULX = 320; 4float ULY = 320; 5float LRX = 340; 6float LRY = 340; 7 8double FPS = 60.0; 9ALLEGRO_TIMER *Timer = al_create_timer(1.0/FPS); 10ALLEGRO_EVENT_QUEUE *EventQueue = al_create_event_queue(); 11bool Stop = false; 12al_start_timer(Timer); 13bool Redraw = false; 14bool Keys[] = {false, false, false, false}; 15float Ships_X_Position = 330; 16float Ships_Y_Position = 330; 17 18al_clear_to_color(al_map_rgb(0, 0, 0)); 19al_draw_filled_rectangle(ULX, ULY, LRX, LRY, al_map_rgb(204, 153, 64)); 20al_flip_display(); 21 22float ChangeInAngle = 0.034906585; 23while(!Stop) 24{ 25 ALLEGRO_EVENT Event; 26 al_wait_for_event(EventQueue, &Event); 27 if(Event.type == ALLEGRO_EVENT_TIMER) 28 { 29 al_identity_transform(&ShipTransformation); 30 if(Keys[0]) 31 { 32 al_translate_transform(&ShipTransformation, 0, -5); 33 Ships_Y_Position -= 5; 34 } 35 if(Keys[2]) 36 { 37 al_translate_transform(&ShipTransformation, -Ships_X_Position, -Ships_Y_Position); 38 al_rotate_transform(&ShipTransformation, ChangeInAngle); 39 al_translate_transform(&ShipTransformation, Ships_X_Position, Ships_Y_Position); 40 } 41 Redraw = true; 42} 43 else if(Event.type == ALLEGRO_EVENT_KEY_DOWN) 44 { 45 switch(Event.keyboard.keycode) 46 { 47 case ALLEGRO_KEY_UP: 48 Keys[0] = true; 49 break; 50 case ALLEGRO_KEY_LEFT: 51 Keys[2] = true; 52 break; 53 } 54 } 55 else if (Event.type == ALLEGRO_EVENT_KEY_UP) 56 { 57 switch(Event.keyboard.keycode) 58 { 59 case ALLEGRO_KEY_UP: 60 Keys[0] = false; 61 break; 62 case ALLEGRO_KEY_LEFT: 63 Keys[2] = false; 64 break; 65 } 66 } 67 if(Redraw && al_is_event_queue_empty(EventQueue)) 68 { 69 70 //al_transform_coordinates(&ShipTransformation, &ULX, &ULY); 71 //al_transform_coordinates(&ShipTransformation, &LRX, &LRY); 72 al_use_transform(&ShipTransformation); 73 al_draw_filled_rectangle(ULX, ULY, LRX, LRY, al_map_rgb(204, 153, 64)); 74 al_identity_transform(&ShipTransformation); 75 al_use_transform(&ShipTransformation); 76 al_flip_display(); 77 al_clear_to_color(al_map_rgb(0, 0, 0)); 78 Redraw = false; 79 } 80 } 81}

Now...this works. Kind of. If I comment out the al_transform_coordinates then, when I hole the up key, the square will move five pixles up and stay there. If I have al_transform_coordinates un-commented, then the square continuously moves up because the coordinates are being changed as well.

The square rotates correctly, but the square morphs because the ULX, ULY, LRX, and LRY are changing. My only solution to this is to make a method that draws a square where I can define all four points and not two points.

So my question is, how do I successfully rotate a square and have the square keeps it's shape?

Edgar Reynaldo

Okay, you need to keep track of the angle too, you can't just display one angle and expect it to keep rotating, and yes your ship should move up 5 pix per frame but you're setting the view to 0,5 that's not really what you wanna do. And you need to update your ULX... variables. But better than that make a ship or player or object struct and store all the info in there. Have it store the rectangle of the ship and its angle.

Read, and try compiling this source code and running it. It should give you a basic example of transforms and movement :

1 2#include <allegro5/allegro.h> 3#include <allegro5/allegro_primitives.h> 4 5#include <cstdlib> 6#include <cmath> 7 8const float SCREEN_WIDTH = 800; 9const float SCREEN_HEIGHT = 600; 10 11int TIMER_BPS = 60; 12float TIMER_FREQ = 1.0f/(float)TIMER_BPS; 13 14float camera_xpos = 0.0f; 15float camera_ypos = 0.0f; 16 17const float SHIP_WIDTH = 50.0f; 18const float SHIP_HEIGHT = 100.0f; 19const float SHIP_SPEED = 120.0f/60.0f;// 120 pixels every 60 seconds 20 21 22enum KEYS { 23 KEY_MOVE_FORWARD = 0, 24 KEY_MOVE_BACKWARD = 1, 25 KEY_TURN_LEFT = 2, 26 KEY_TURN_RIGHT = 3 27}; 28 29// These match the KEYS enum 30const int NUMKEYS = 4; 31int keycodes[NUMKEYS] = {ALLEGRO_KEY_UP , ALLEGRO_KEY_DOWN , ALLEGRO_KEY_LEFT , ALLEGRO_KEY_RIGHT}; 32 33int keys[NUMKEYS] = {0,0,0,0};// track key ups and downs 34 35 36 37typedef struct SHIP { 38 float x,y,w,h,rx,by,angle; 39}; 40 41SHIP s; 42void init_ship(SHIP* s) { 43s->x = s->y = s->w = s->h = s->rx = s->by = s->angle = 0.0f; 44} 45 46void update_ship_corner(SHIP* s) { 47 s->rx = s->x + s->w; 48 s->by = s->y + s->h; 49} 50 51void set_ship_rectangle(SHIP* s , int x , int y , int w , int h) { 52 s->x = x; 53 s->y = y; 54 s->w = w; 55 s->h = h; 56 update_ship_corner(s); 57} 58 59void set_ship_pos(SHIP* s , int x , int y) { 60 s->x = x; 61 s->y = y; 62 update_ship_corner(s); 63} 64 65void translate_ship(SHIP* s , float xshift , float yshift) { 66 set_ship_pos(s , s->x + xshift , s->y + yshift); 67} 68 69void set_angle(SHIP* s , float angle) { 70 s->angle = angle; 71} 72 73void shift_angle(SHIP* s , float angle_delta) { 74 set_angle(s , s->angle + angle_delta); 75} 76 77void move_ship_forward(SHIP* s) { 78 translate_ship(s , SHIP_SPEED*cos(s->angle) , SHIP_SPEED*sin(s->angle)); 79} 80 81void move_ship_backward(SHIP* s) { 82 translate_ship(s , -SHIP_SPEED*cos(s->angle) , -SHIP_SPEED*sin(s->angle)); 83} 84 85 86void set_transform_for_ship(ALLEGRO_TRANSFORM* t , SHIP* s) { 87 al_identity_transform(t); 88 // center on ship 89 al_translate_transform(t , -(s->x + s->w/2.0f) , -(s->y + s->h/2.0f)); 90 // rotate 91 al_rotate_transform(t , s->angle); 92 // move ship back where it was 93 al_translate_transform(t , +(s->x + s->w/2.0f) , +(s->y + s->h/2.0f)); 94} 95 96void draw_ship(SHIP* s) { 97 ALLEGRO_TRANSFORM transform, old; 98 set_transform_for_ship(&transform , s); 99 // follow our camera 100 al_translate_transform(&transform , -camera_xpos , -camera_ypos); 101 al_use_transform(&transform); 102 al_draw_filled_rectangle(s->x , s->y , s->rx , s->by , al_map_rgb(255,127,0)); 103 // theoretically, reset transformation matrix for allegro here,too lazy though 104} 105 106int main(int argc , char** argv) { 107 108 if (!al_init()) {exit(1);} 109 if (!al_install_keyboard()) {exit(2);} 110 if (!al_init_primitives_addon()) {exit(2);} 111 112 al_set_new_display_flags(ALLEGRO_OPENGL | ALLEGRO_WINDOWED); 113 ALLEGRO_DISPLAY* disp = al_create_display(SCREEN_WIDTH , SCREEN_HEIGHT); 114 115 if (!disp) {exit (3);} 116 117 ALLEGRO_EVENT_QUEUE* events = al_create_event_queue(); 118 if (!events) {exit(4);} 119 120 ALLEGRO_TIMER* timer = al_create_timer(TIMER_FREQ); 121 if (!timer) {exit(5);} 122 123 al_register_event_source(events , al_get_keyboard_event_source()); 124 al_register_event_source(events , al_get_display_event_source(disp)); 125 al_register_event_source(events , al_get_timer_event_source(timer)); 126 127 SHIP ship; 128 init_ship(&ship); 129 set_ship_rectangle(&ship , 100 , SCREEN_HEIGHT/2 - SHIP_HEIGHT/2 , SHIP_WIDTH , SHIP_HEIGHT); 130 131 bool quit = false; 132 bool redraw = true; 133 134 al_start_timer(timer); 135 136 while (!quit) { 137 if (redraw) { 138 redraw = false; 139 al_clear_to_color(al_map_rgb(0,0,0)); 140 draw_ship(&ship); 141 al_flip_display(); 142 } 143 do { 144 ALLEGRO_EVENT e; 145 al_wait_for_event(events , &e); 146 if (e.type == ALLEGRO_EVENT_TIMER) { 147 redraw = true; 148 if (keys[KEY_TURN_LEFT]) { 149 shift_angle(&ship , TIMER_FREQ*(-M_PI/3.0f)); 150 } 151 if (keys[KEY_TURN_RIGHT]) { 152 shift_angle(&ship , TIMER_FREQ*(M_PI/3.0f)); 153 } 154 if (keys[KEY_MOVE_FORWARD]) { 155 move_ship_forward(&ship); 156 } 157 if (keys[KEY_MOVE_BACKWARD]) { 158 move_ship_backward(&ship); 159 } 160 } 161 else if (e.type == ALLEGRO_EVENT_KEY_DOWN) { 162 if (e.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {quit = true;} 163 for (int k = 0 ; k < NUMKEYS ; ++k) { 164 if (e.keyboard.keycode == keycodes[k]) { 165 keys[k] = 1; 166 } 167 } 168 } 169 else if (e.type == ALLEGRO_EVENT_KEY_UP) { 170 for (int k = 0 ; k < NUMKEYS ; ++k) { 171 if (e.keyboard.keycode == keycodes[k]) { 172 keys[k] = 0; 173 } 174 } 175 } 176 else if (e.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { 177 quit = true; 178 } 179 } while (!al_is_event_queue_empty(events) && !quit); 180 } 181 182 183 /** Leak a bunch of memory here because I haven't called any of the al_destroy routines and cleaned up after myself */ 184 185 return 0; 186}

And if you learn anything from this code, it should be to use functions and compartmentalize your code.

Edit - the movement isn't quite right for some reason I haven't figured out yet

Darren Hoehna

It works. I'll look it over and learn from it. I know that I should use functions. I do that at my job. But I wanted to first get the rotation correct then I was going to worry about functions and the such.

EDIT:

I'm going through you code and I have some questions.

I understand what by are used for, but what do they stand for?
for init_ship(), why do you have SHIP x; before the method?

Dizzy Egg

Do you mean why does he have SHIP s; before calling init? He's declaring an instance of the structure; s is an instance of SHIP...you need it to pass to init..

```struct SHIP; //the structure

SHIP s;  //s is a SHIP

initShip(s); //send ship to function
```

LennyLen
Dizzy Egg said:

Do you mean why does he have SHIP s; before calling init? He's declaring an instance of the structure; s is an instance of SHIP...you need it to pass to init..

Except that in the main function a SHIP called ship is declared and passed to the initShip() function.

That line is not required at all. I'm guessing it was part of an earlier revision and was not removed.

Dizzy Egg

Yeah, what Lenny said.

Edgar Reynaldo
LennyLen said:

That line is not required at all. I'm guessing it was part of an earlier revision and was not removed.

Yes, you are correct.

Anybody know why the movement follows integer or rounded angles, but the orientation looks perfect all the time? Ie. why doesn't it go the direction it is facing? I don't get it. Anybody try the code?

Darren Hoehna

I have tried the code yet I have not found out why it does that. I'm still wondering why doesn't the rectangle go flat when both x-coordinates are the same. But when I find it our I'll give you a hollar.

Here is the code I used to make the rotating square work. It doesn't have any functions or methods yet, but it works.

1#include <allegro5/allegro.h> 2#include <allegro5/allegro_image.h> 3#include <allegro5/allegro_native_dialog.h> 4#include <allegro5/allegro_primitives.h> 5#include <stdio.h> 6#include <math.h> 7#include <iostream> 8 9 10const int SCREEN_WIDTH = 640; 11const int SCREEN_HEIGTH = 640; 12 13const int SHIP_WIDTH = 32; 14const int SHIP_HEIGTH = 32; 15 16const double CHANGE_IN_ANGLE = 0.034906585; 17const double SPEED_OF_SHIP = 4.0; 18 19const double FRAMES_PER_SECOND = 60.0; 20 21const enum KEYS {UP, DOWN, LEFT, RIGHT}; 22 23//I keep track of the center and not a second point since the second point is never used. 24//To get the secodn point the program uses First_X_Position + SHIP_WIDTH 25 26//The Center_X_Position and Center_Y_Position is used in the redraw step near the end of the program. 27//The Center points are to make the square move around the center of the square. 28struct ShipStuff 29{ 30 float First_X_Position; 31 float First_Y_Position; 32 float Width; 33 float Heigth; 34 float Center_X_Position; 35 float Center_Y_Position; 36 float Angle; 37}; 38int main(int argc, char **argv) 39{ 40 ALLEGRO_DISPLAY *Display = NULL; 41 ALLEGRO_TIMER *Timer = NULL; 42 ALLEGRO_EVENT_QUEUE *EventQueue = NULL; 43 44 ShipStuff Ship; 45 Ship.First_X_Position = SCREEN_WIDTH / 2.0; 46 Ship.First_Y_Position = SCREEN_HEIGTH / 2.0; 47 Ship.Width = 0.0f; 48 Ship.Heigth = 0.0f; 49 Ship.Center_X_Position = Ship.First_X_Position + (SHIP_WIDTH / 2.0); 50 Ship.Center_Y_Position = Ship.First_Y_Position + (SHIP_HEIGTH / 2.0); 51 Ship.Angle = -ALLEGRO_PI/2; 52 if(!al_init()) 53 { 54 al_show_native_message_box(Display, "Bad Init", "Bad Init", "Can't initilize allegro", NULL, ALLEGRO_MESSAGEBOX_ERROR); 55 return -1; 56 } 57 58 al_init_primitives_addon(); 59 Display = al_create_display(SCREEN_WIDTH, SCREEN_HEIGTH); 60 if(!Display) 61 { 62 al_show_native_message_box(Display, "Bad Display", "Bad Display", "Sorry, can't make the display", NULL, ALLEGRO_MESSAGEBOX_ERROR); 63 return -1; 64 } 65 66 if(!al_install_keyboard()) 67 { 68 al_show_native_message_box(Display, "No Keyboard", "No Keyboard", "Sorry, can't install the keyboard", NULL, ALLEGRO_MESSAGEBOX_ERROR); 69 al_destroy_display(Display); 70 return -1; 71 } 72 73 Timer = al_create_timer(1.0/FRAMES_PER_SECOND); 74 if(!Timer) 75 { 76 al_show_native_message_box(Display, "Bad Timer", "Bad Timer", "Sorry, can't make the timer", NULL, ALLEGRO_MESSAGEBOX_ERROR); 77 al_destroy_display(Display); 78 return -1; 79 } 80 81 EventQueue = al_create_event_queue(); 82 if(!EventQueue) 83 { 84 al_show_native_message_box(Display, "Bad Queue", "Bad Queue", "Can't make the event queue.", NULL, ALLEGRO_MESSAGEBOX_ERROR); 85 al_destroy_display(Display); 86 al_destroy_timer(Timer); 87 return -1; 88 } 89 90 //UP, DOWN, LEFT, RIGHT 91 bool KeyPresses[] = {false, false, false, false}; 92 bool Redraw = true; 93 double Ships_X_Position = SCREEN_HEIGTH / 2.0; 94 double Ships_Y_Position = SCREEN_WIDTH / 2.0; 95 96 al_register_event_source(EventQueue, al_get_display_event_source(Display)); 97 al_register_event_source(EventQueue, al_get_timer_event_source(Timer)); 98 al_register_event_source(EventQueue, al_get_keyboard_event_source()); 99 al_draw_filled_rectangle(Ship.First_X_Position, Ship.First_Y_Position, Ship.First_X_Position + SHIP_WIDTH, Ship.First_Y_Position + SHIP_HEIGTH, al_map_rgb(255, 124, 68)); 100 al_flip_display(); 101 al_start_timer(Timer); 102 float AngleInRadians = 0.0f; 103 bool DoExit = false; 104 while (!DoExit) 105 { 106 ALLEGRO_EVENT Event; 107 al_wait_for_event(EventQueue, &Event); 108 109 if(Event.type == ALLEGRO_EVENT_TIMER) 110 { 111 if(KeyPresses[UP]) 112 { 113 Ship.First_X_Position += cos(Ship.Angle) * SPEED_OF_SHIP; 114 Ship.Center_X_Position += cos(Ship.Angle) * SPEED_OF_SHIP; 115 116 Ship.First_Y_Position += sin(Ship.Angle) * SPEED_OF_SHIP; 117 Ship.Center_Y_Position += sin(Ship.Angle) * SPEED_OF_SHIP; 118 } 119 if (KeyPresses[DOWN]) 120 { 121 Ship.First_X_Position -= (cos(Ship.Angle) * SPEED_OF_SHIP); 122 Ship.Center_X_Position -= cos(Ship.Angle) * SPEED_OF_SHIP; 123 124 Ship.First_Y_Position -= (sin(Ship.Angle) * SPEED_OF_SHIP); 125 Ship.Center_Y_Position -= sin(Ship.Angle) * SPEED_OF_SHIP; 126 127 } 128 if(KeyPresses[LEFT]) 129 { 130 Ship.Angle -= CHANGE_IN_ANGLE; 131 if( Ship.Angle > (2 * 3.1415)) 132 { 133 Ship.Angle = 0; 134 } 135 136 } 137 if(KeyPresses[RIGHT]) 138 { 139 Ship.Angle += CHANGE_IN_ANGLE; 140 if(Ship.Angle > (2 * 3.1415)) 141 { 142 Ship.Angle = 0; 143 } 144 145 } 146 Redraw = true; 147 } 148 else if (Event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 149 { 150 break; 151 } 152 else if (Event.type == ALLEGRO_EVENT_KEY_DOWN) 153 { 154 switch (Event.keyboard.keycode) 155 { 156 case ALLEGRO_KEY_UP: 157 KeyPresses[UP] = true; 158 break; 159 case ALLEGRO_KEY_DOWN: 160 KeyPresses[DOWN] = true; 161 break; 162 case ALLEGRO_KEY_LEFT: 163 KeyPresses[LEFT] = true; 164 break; 165 case ALLEGRO_KEY_RIGHT: 166 KeyPresses[RIGHT] = true; 167 break; 168 } 169 } 170 else if (Event.type == ALLEGRO_EVENT_KEY_UP) 171 { 172 switch(Event.keyboard.keycode) 173 { 174 case ALLEGRO_KEY_UP: 175 KeyPresses[UP] = false; 176 break; 177 case ALLEGRO_KEY_DOWN: 178 KeyPresses[DOWN] = false; 179 break; 180 case ALLEGRO_KEY_LEFT: 181 KeyPresses[LEFT] = false; 182 break; 183 case ALLEGRO_KEY_RIGHT: 184 KeyPresses[RIGHT] = false; 185 break; 186 case ALLEGRO_KEY_ESCAPE: 187 DoExit = true; 188 break; 189 } 190 } 191 192 if(Redraw && al_is_event_queue_empty(EventQueue)) 193 { 194 195 Redraw = false; 196 al_clear_to_color(al_map_rgb(0, 0, 0)); 197 ALLEGRO_TRANSFORM ShipTransformation, Old; 198 al_identity_transform(&ShipTransformation); 199 al_translate_transform(&ShipTransformation, -(SCREEN_WIDTH - (SCREEN_WIDTH - Ship.Center_X_Position)), 200 -(SCREEN_HEIGTH - (SCREEN_HEIGTH - Ship.Center_Y_Position))); 201 al_rotate_transform(&ShipTransformation, Ship.Angle); 202 al_translate_transform(&ShipTransformation, (Ship.Center_X_Position), (Ship.Center_Y_Position)); 203 al_translate_transform(&ShipTransformation, 0.0, 0.0); 204 al_use_transform(&ShipTransformation); 205 al_draw_filled_rectangle(Ship.First_X_Position, Ship.First_Y_Position, Ship.First_X_Position + SHIP_WIDTH, Ship.First_Y_Position + SHIP_HEIGTH, al_map_rgb(255,127,0)); 206 al_use_transform(&Old); 207 al_flip_display(); 208 } 209 } 210 al_destroy_timer(Timer); 211 al_destroy_event_queue(EventQueue); 212 al_destroy_display(Display); 213 214 return 0; 215}

Also, I found this very interesting.

Let's say you have these variables:
Upper_Left_X
Upper_Left_y
Lower_Right_X
Lower_RIght_Y

and you make a square by doing this
al_draw_filled_rectangle(Upper_Left_X, Upper_Left_y, Lower_Right_X, Lower_Right_Y,
al_map_rgb(255, 10, 13))

Than the square contorts and will become a straight line whenever the two X coordinates are the same.

But if you draw a rectangle like this.
al_draw_filled_rectangle(Upper_Left_X, Upper_Left_Y, SHIP_WIDTH, SHIP_HEIGTH,
al_map_rgb(255, 10, 13)) then the rectangle will always stay the same shape.

Edgar Reynaldo

Hey, you can post your code now Darren.

And if you click on the pen and paper icon at the top of your post you can edit it and then send to top.

Darren Hoehna

The transformations are done with the center of the square. That way the square will rotate around the center. Because of that I don't know who to the stop the square from moving if one point touches the border.

I'm looking into this as well. I just can't figure it out yet.