My level background is a bitmap with various obstacles on it
Whats the best way to say just put a square over that image and stop my player from moving into them
I started putting pink squares/rectangles over the item I want collision with, to get the x1, x2, y1, y2 co-ordinates but there are maybe around 25 squares and rectangles.
Do i just do it 1 by one or does it in an array (not done this before)
Also How do I overcome this
I know I need to somehow stop him moving in the x/y direction but I still need him to move in the other x/y direction
EDIT:- I found this forum post and going to try following it https://www.allegro.cc/forums/thread/613787
for each objectA in array of objects for each objectB in array of objects if(objectA != objectB) //we don't want to collide with ourself! // do bounding box collision
I don't recall the exact formula off the top of my head for bounding boxes, but the point here is you are doing an O(n^2) ("n squared") algorithm that means the number of operations is equal to the square of the number of objects in the array.
You only need more elegant solutions when number of objects become very high. (1000 or more.)
As for the geometry of whether or not the collision has occured:
https://wiki.allegro.cc/index.php?title=Bounding_Box
You can use pixel-perfect collision detection (each pixel is tested), or you can use what I'll call "finite point" method where you a certain number of points that are relative to the center x,y position. So if you had a guy that was twice as tall as he was wide, you would test say [x,y-10],[x,y+10],[x-5,y],[x+5,y]. The number of points and their positions can very. So you can use more for a bigger object, or even change their positions as the sprites change. It's almost as good as pixel perfect, much faster, and in some cases, can behave even better. (A single stray pixel won't cause problems, only the pixel locations you want.)
[edit] I think I'm going to learn HTML5/JS/whatever and then throw together some scripted examples so people can see/feel how they interact.
Cheers Chris, I'll have a read through those pages and see what I can work out
I'd like to point out that the easiest collision detection is between points-circles and circles-circles, they only require very simple distance checks.
Some untested code for common collision cases:
I'm trying to get this collision working and it doesn't seem to be going right
Not sure if I got things in the wrong place or just doing it wrong entirely
You're not using the BoundingBox function correctly. It should be used to check whether the player overlaps with something when a key is pressed by checking for the future (one step ahead) position of the player versus the future position of the game objects and walls. Also don't case the bounds in variables, use the player and game object's positions directly.
Thanks beoran. After that I re worked the code and I do have collision being detected and correctly stops my player on the collision.
However, once collision had been detected I cannot move my player anymore.
Removed alot of code and left the Collision section in
I think I understand it, As it now calls to check collision after a key press and before movement. I also changed the variable to hold the player rather than extra variables.
Although I did change everything into a function now, (Hope that's heading along the right line).
That global variable hasCollision is a bad idea, it's bound to get out of date. In stead, make the Collide function return an int for C89 or bool for C++ or C99, and then check that in your if.
Secondly, the reason your player is getting stuck is because Collision checks the current position of the objects. This means that once a collision happens the object will not be able to move anymore because it will always keep colliding since the overlap already happened, like bullet stuck in the wall. It's necessary to check the next position of the game objects by taking their speed into consideration.
Alternatively, you can leave the collision as it is now, but then, you have to move the player back out of collision whenever collision happens.
Hope I'm heading in the right direction which this now
I removed the global hasCollision
I know the Human1.y += Human1.speed; is wrong at the moment and as such make my character's controls reserve after collision, which I'm trying to fix.
Although now I can collide with something and still move (albeit in the wrong direction haha).
Does this look slightly better now ?
Yes, this looks better. What you are doing is actually not so bad at all. There are several ways to do collision handling. The main distinction between these ways is how objects are kept from getting stuck.
This can be done in general in two ways:
Check where the objects will be after moving and if they will collide, don't move them.
Check if the objects are colliding and were moving before. If thy collide and were moving, put the objects back at their previous position.
The way you are trying is the second correcting approach, which can work if done correctly. In such an approach you could give the player struct an extra old_x and old_y to keep track of the previous position and restore that on collision.
Hope that helps.
Thanks Beoran, long delay as I had stayed up all night trying to get my head around all this bounding box/collision stuff, and so many people write things which are slightly different or totally different to how I have it done and then I get confused .
I have tried to add in the old_x and old_y value which you mentioned although I still get stuck on the bounding box.
There is this i found which I think explains what you said about old_x and old_y
Which didn't seem to work for me
He states it should work, but I just get stuck again.
You're doing this too soon!
Human1.oldx = Human1.x; Human1.oldy = Human1.y;
You can only do this after checking that Human1 is not colliding with anything at it's x and y position. Otherwise you're just storing the "stuck" coordinates in the oldx and oldy , which makes them useless.
Got it now, Beoran ty.
You make me think :-)
I do like to know that code is correct and what the error is and it helps me figure it out, sometimes it just takes forever, but I have a somewhat working collision
Although (Sorry another issue)
My player now kinda bounces back and forth between pixels on collision and if I release the movement key while he is furthest away from the collision he can carry on moving as normal, but if i release the movement key when he is closest to collision he gets stuck.
What area of the code would/could causes this issue ?
I've tried to add/subtract numbers from various x/y values to compensate for this but haven't fixed it yet
EDIT, I kinda got the bouncing to stop, but it then stops me moving in the other axis, so if I collided --> i cant move up or down. Still working on it though :-)
EDIT AGAIN, I think I have solved it now, seems to be working fine.
EDIT AGAIN: Any idea how I go about adding around 20 different x, y, w, h values for Human2 (There not humans, just keeping it that way for this purpose) Mine seems to be a long long way
In C++, you normally set initial conditions with a constructor.
[edit] DOH, I confused your post with someone else, so I thought you were using C++.
This actually works fine. But it should be like this:
void Human2Bounds(Player Human2[], int size) { for (int i = 0; i < size; i++) { Human2[i].x = 0; //note i Human2[i].y = 0; Human2[i].w = 860; Human2[i].h = 90; } }
I don't understand what "human2bounds" means, but if you're just setting up coordinates that will work. The gigantic width also confuses me.
Now as for specific coordinates. You can read in a list of coordinates from a file, from a hand-written array, or, the easiest, use rand() to randomly select positions:
Tbh I posted this with 2 human images on to try and get the bounding box collision working, now that seems to be fine I want to try and implement the code into my game.
Its nothing to to with a Human, the bounding boxes will be for terrain on screen I want collision on (hence the 25 items and strange sizes)
I just thought I'd keep with the "Humans" so if anyone looked over previous code they could kinda understand it more.
What I have been doing is drawing rectangles and squares on screen for these items and just need to add them into an array for the bounding boxes.
Ill read over you help and try and get it working.
As of now I can only get 1 of the rectangles to work any others I add in the player just goes through them
You have to compare every moving object with every other object it could possibly collide with. There are ways to prune the number of potential collisions but that's a more advanced topic.
What you want is a Rectangle struct that stores the rectangle of whatever kind of object needs one. Then you compare rectangles instead of humans.
This is what I have as of now
@ Chris
I used (Changed your code to match mine)
But this didn't seem to allow any collision, probably my coding somewhere, it always is.
And again I really appreciate all your help guys, it is helping me learn, albeit slow at times.
Allow me to explain in code :
Then you include a Rectangle member in your Human or other structs if they need one.
typedef struct Human { // ... Rectangle pos; };
And you test for collision between Humans and other objects (such as Humans) by checking their rectangles.
bool HumansCollide(Human* h1 , Human* h2) { return RectCollide(&(h1->pos) , &(h2->pos)); }
You certainly seem to know what your talking about Edgar in the way you respond with your coding, although at times I don't understand your code especially for this newbie (Bearing in mind my C++/Allegro5 knowledge was none existent a month - 6 weeks ago and I only watched Mike Geigs tutorials and some of CodingMadeEasy).
If I do get what you mean, should it be like this for me ? I'm trying not to change too much as I need to be able to take this code and put it straight into my game's code.
If this is somewhat correct then it breaks at my BoundsSet function @ b2->x = x; saying Unhandled exception at 0x01352644 in Testing.exe: Access violation writing location 0x00000000.
I think I have all your code in place, and again I'm sorry if I don't fully grasp everything you helping me on.
Take a look at the highlighted lines (which have problems) and the comments I made
Please note that this code still has problems. p1->b2 is still unitialized. You never allocate memory for the Bounds struct. What you want is probably a member variable for Bounds that isn't a pointer.
typedef struct Player { Bounds b; }; TestBounds(&(p1->b));
Sorry, just not getting this, i just keep getting faced with errors
I though I nearly had it when I did it earlier which was this way, but I'm guessing this way can't work which is a shame
I think the problem I am having it that I don't fully understand the setup up between having a struct then calling information from it inside another struct and linking everything together and I only have 2 days left before I finish the game:-(
What you really need is a primer on C.
Given this declaration :
struct Rectangle { int x,y,w,h; }; struct Player { Rectangle r; };
You can create an array of one of them like this :
const int array_size = 4; Rectangle rects[array_size] = { {0,0,10,10}, {0,0,10,10}, {0,0,10,10}, {0,0,10,10} };
You don't have to specify a size in this case but it never hurts to specify it directly.
You access data members either through the struct or through a pointer.
Rectangle r = {0,0,10,10}; Rectangle* prect = &r; r.x = 5; prect->y = 15;
And when you have nested structs you follow from outer to inner members :
Player p = {{0,0,10,10}}; Player* pplayer = &p; p.r.x = 10; pplayer->r.y = 20;
And you'll need a for loop as well :
for (int i = 0 ; i < array_size ; ++v) { }
It has the syntax :
for (VAR v = initial_value ; v comparison_operator v2 ; v expression) {
And finally, you access array elements using an index ie array[i] where i is from 0 to size - 1. It is zero indexed.
I'm trying to work through you code again Edgar, and I appreciate your time on this
Taking things 1 step at a time
If I do
I read into this and 1 person fixed it they said
They added:
#using <system.drawing.dll>
at the top
However if I add this I get : Error:"#using" requires C++/CLI mode
I read into this and 1 person fixed it they said
They added:
#using <system.drawing.dll>
at the top
However if I add this I get : Error:"#using" requires C++/CLI mode
That is not how you fix it. :/
The error has to do with Microsoft so helpfully defining a function named Rectangle which conflicts with naming the struct Rectangle as well. If you #define NOGDI before including windows headers then the Rectangle function won't be visible.
Try this code with and without NOGDI defined :
You should get comfortable working with both member access using the dot operator . and dereferencing pointers with the dereference operator ->. & means "the address of" an object, and is what a pointer stores. That's why I set pp to &p in the code above. It now holds the value of the address of the Player object p. And you can also dereference a pointer with *. *pointer means "the data pointed to by" pointer. And so to access the Player p through pp you would use *pp = Player object.
That's slowly making some kind of sense to me. Thanks
I saw the difference between #define NOGDI and without it too, I'd never heard of this till now.
I have no implemented code which you gave previously and tried to do it the best I could, it now runs without errors, although no collision detected.
I'm now going to try and see what is not working and hopefully fix it. It is quite difficult to learn as it's a lot of new things to take in.
Edit: I think I'm slowly getting there, but having an issue with the array (Not sure where to put it or code it);
I have only managed to get 1 bound to collide, I guess as there is no array whatever the last x, y, w, h values where are the only ones stored.
I hope I have things in somewhat the correct way now, as you can see I have taken parts of the codes you have provided me
Go ahead and keep posting code if you need to. The best way to learn is from making mistakes and figuring them out. We're here to help.
Edit for your edit. Don't just add code in without knowing what it does. Those were just examples of how to work with structs and pointers, it isn't all actual code that you should be using.
Then you include a Rectangle member in your Human or other structs if they need one.
typedef struct Human { // ... Rectangle pos; };
And you test for collision between Humans and other objects (such as Humans) by checking their rectangles.
bool HumansCollide(Human* h1 , Human* h2) { return RectCollide(&(h1->pos) , &(h2->pos)); }
Something that will help you is a helper function like this :
bool CollideRects(Rectangle* r1 , Rectangle* r2) { //... } bool CollidePlayerAndHuman(Player* p , Human* h) { return CollideRects(&(p->rect) , &(h->rect)); }
To create an array, you need to use a constant size variable for the size, or else you need to allocate memory dynamically through malloc or new or new[] and then use free or delete or delete[] respectively.
Edit2
Oh, and I forgot you need to test against the future position. This can easily be accomplished by another helper function :
void MoveRectBy(Rectangle* r , int dx , int dy) { r->x += dx; r->y += dy; }
Then to use it you do :
bool CollideHumanWithPlayer(Human* h , Player* p) { Rect future_human_rect = h->rect; MoveRectBy(&future_human_rect , h->xvelocity , h->yvelocity); return CollideRects(&(p->rect) , &future_human_rect); }
Yeah, I was kinda thinking the code you posted was to be used to get it to work. But also if I write my code how I get the advice I can sometimes see how and why it works.
At the moment I have all the movement and things set up to work correctly.
The only thing I'm working on at the moment, is to have my rectangles co-ordinates set into an array and then pass this array into the collision detection.
So for example (I know this isn't code format but easier to do for me)
RectangleBoundingBox say has 2 rectangles to store data for
(x, y, w, h)
So my 2 rectangles are
(0, 0, 860, 90)
(920, 0, 360, 210)
These should be stored in an array
Then in my collision which I have setup as
(Human1.x > Human1.speed + RectangleBoundingBoxArray.x + RectangleBoundingBoxArray.w - 1)
Rather than mutliple rows of that code, all my bounds co-ords should be in an array.
As of now I have only managed to collided with 1 rectangle, to me is seems that the array isn't working well inside the collision function.
The code you posted, I will look at in future, as I feel the way we got told to program this is not the easiest nor the best, so next time around I'll be looking into different ways to do it.
Should I use my array like ARRAYNAME[2][4], so it has 2 rows and 4 co-ords or is that not needed because I'm reading about them and they say to do that with a 2 dimensonal array.
Arrays can be hard to work with. You might want to use a std::vector<Rectangle>.
With a vector you can add a rectangle to your vector at any time.
SGI's STL guide is the best way to learn the C++ Standard Template Library.
https://www.sgi.com/tech/stl/
And specifically on vectors :
https://www.sgi.com/tech/stl/Vector.html
Later on once you want to remove objects from your array you might want to use a std::list<Rectangle> instead.
Read about list here :
https://www.sgi.com/tech/stl/List.html
I'll look into these Edgar, I'm going to have more time on this as I hand in my game tomorrow.
I may even look into using the tile map editor to create the bounds for my terrain, it was some that seemed really complicated and I didn't want to break my game before the hand in.
I do feel I still went above and beyond what was needed so here's hoping.
Not sure where to put this but for everyone that helped on this. I appreciate it, and this is was I came up with in the end.
Still issues and bugs to fix, but it will all come in time.
Thank again all.