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.
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.
I never knew there was such a thing. I'll give it a try and reply back. Thanks.
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.
I did not know about al_transform_coordinates either, that is freakin awesome.
If you are interested in OBB (Oriented Bounding Box) collision, one way to do it that's not too complex is Separate Axis Theorem.
It's beyond your needs for this, but it might be interesting for future projects.
Umm, I have tried and tried but I don't understand how to start using transformations.
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.
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.
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?
I'm working on a similar task, I got my bounding box (rectange) to display correctly as follows:
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?
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
CHANGE_IN_ANGLE = 0.034906585 (rad)
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.
@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.
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
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
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.
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.
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.
bump for reply...
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.
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?
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 :
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
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?
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
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.
Yeah, what Lenny 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?
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.
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.
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.
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.