Allegro.cc Forums » Programming Questions » Collision problem. Projectile colliding with invisible diagonal barrier.

Credits go to NiteHackr for helping out!
 Collision problem. Projectile colliding with invisible diagonal barrier.
 piskypom Member #16,813 February 2018 Git Repo (dev branch)I know it's alot of code to look at. And honestly this is just a long shot to see if anybody has spare time to look at it.The problem is when you click your mouse to shoot the projectile out of the end of the line (aimer), the projectile will hit this invisible barrier that runs diagonally across the screen from the bottom left to top right. Probably not a coincidence it crosses the target too. It's like the math I use stretches the target shape and "skews" and stretches it across the screen.I have an entities_collided() function that is making me pull my hair out. The relevant functions are#SelectExpand 1bool Game::entities_collided() 2bool Entity::operator>(const Entity &rhs) const 3void Entity::set_sides(Entity &_ent, Coords _origin, Dimension _dimension) The structure is confusing, so I'll break it down:First I take the top left coordinates of an entity and determine it's top, bottom, left, and right side values. It's not their lengths. I use square collision using the four points. I add like this:#SelectExpand 1// 10x10 square 2pA(0,0) // Top left 3pB(10,0) // Top right 4pC(0,10) // Bottom left 5pD(10,10)// Bottom right 6 7Obj objA.top = pA.x + pB.x + pA.y + pB.y; 8Obj objA.bot = pC.x + pD.x + pC.y + pD.y; 9Obj objA.left = pA.x + pC.x + pA.y + pC.y; 10Obj objA.right = pB.x + pD.x + pB.y + pD.y; Then I just compare the values of each side of each object. It actually works nicely.I do this math for both the projectile and the target. The formula for square collision is: #SelectExpand 1if (objA.left < objB.right && 2 objA.right > objB.left && 3 objA.top < objB.bot && 4 objA.bot > objB.top) I'm sure you veterans know this formula by heart. Just recapping for the rest of us.I created an operator overload of > so that I can just take any object and say objA > objB. The function takes care of all the math.Perhaps I made this all too convoluted and thus confusing to debug. I'll eventually simplify things and make them easier to understand.Thanks for your time.
 NiteHackr Member #2,229 April 2002 The way I do simple box collision is instead of checking for collisions, I reject instances where collisions are impossible.In some older code I have something like this, it's quite simple... ```// If the bottom of one is less than the top of another, than they cannot be colliding... if(bottomA < topB) return false; // if the top of one, is greater than the bottom of another, no collision possible... if(topA > bottomB) return false; // If the right of one is less than the left of another, impossible to be colliding... if(rightA < leftB) return false; // If the left of one is greater than the right of another, impossible to be colliding... if(leftA > rightB) return false; ``` This makes it super simple. And if all four of these tests fail, you absolutely have a collision.Later on, I ended up changing this code so that it did circular collision which is simple as well. You check if the distance between the two objects is less than the sum of their two radius', if so, they are colliding. ---“The world is a dangerous place to live, not because of the people who are evil, but because of the people who don't do anything about it.” ― Albert Einstein
 piskypom Member #16,813 February 2018 OK, right on Neil. I'll give it a shot. Though I'm convinced it's not my collision logic. I have this sad feeling I'll have to abandon this and start over. It's a bit of a can of worms for me eyes. I'll split up things into different classes to make it easier for me to debug.Also, I'll do collision checking before I do any other code. That way I know it works and when something goes wrong, it's not the collision.By chance, did you happen to glance at handle_events()? Just curious if I'm utilizing the even system properly.Anyway, I'm off to go try your suggestion. And you're right, it is a much simpler way. Why not put them in if/else form that way it doesn't check each if implicitly? You know, if it's false it doesn't have to go through those precious cpu cycles to ge to the next condition? *Edit: It was a good idea, but the invisible barrier is still there. So weird. I don't know where it's coming from. Back to the drawing board.*Edit2: I apologize. My math was wrong. It's shameful. I now have the fix. So lesson is don't do this: #SelectExpand 1Rectangle rec1(x,y) 2Rectangle rec2(x,y) 3 4rec1.top = rec1.x + rec2.x + rec1.y + rec2.y; 5 6/* 7 * Comparing sides with the above math is not correct. 8 * It does in fact draw an invisible diagonal. 9 * Solution is to do it properly: 10 */ 11 12rec1.top = rec.y; 13rec1.bot = rec.y + rec.height; 14rec1.left = rec.x; 15rec1.right = rec.x + width; A really simple fix. Thanks for letting me trouble you guys.
 piskypom Member #16,813 February 2018 Oh that's brilliant. The circle collision, I love it! Don't mind if snag these into my stash o' scripts? I've downloaded both pacman. I want to try them out. I love seeing other peoples creations. I haven't made a game yet. But I intend to do something this time. Just like I said last time. And the time before ...
 Eric Johnson Member #14,841 January 2013 I don't have anything meaningful to add, but I wanted to say this...@Neil: That's a neat trick. I haven't considered checking if two objects are NOT colliding before. I typically do something like this for AABB collision:#SelectExpand 1// pseudo-code for check collision between two rectangles. 2isColliding(x1, y1, w1, h1, x2, y2, w2, h2) { 3 4 return abs(x1 - x2) < w1 + w2 && abs(y1 - y2) < h1 + h2; 5} I'll start using your method though. It's a few more lines of code, but it's much simpler and easier to read compared to my method. Plus, your way doesn't have to check the rest of the conditions to return false! Thanks for sharing!
 Edgar Reynaldo Major Reynaldo May 2007 whether you do it with and or or the logic is all the same and i bet you will produce the same code. The first AND check to fail will halt the testing. Likewise with OR it stops as soon as the first positive is found and returns. Same logic.
 Audric Member #907 January 2001 Neil, note that you can do without the sqrt(), using a multiplication of the other term instead : ``` double dist_squared = (dist_x * dist_x) + (dist_y * dist_y); return dist_squared <= rt * rt; ```
 piskypom Member #16,813 February 2018 @Audic: Is there a benefit to using multiplication over sqrt()? I can't remember what I was told, but a friend explained that there is a particular math that the cpu handles faster than others. Is this the same principle? For example, does the cpu handle multiplication better/or faster than division?@Edgar: I know for me, it does wind up being the same code, in that the same principles are applied for checking whether something is or isn't colliding. Thanks to Neil, I will use the method for checking if something is not collding.@Eric: You're right. I prefer code that is easier to read than lengthy one liner formulas (or longer!). My problem with long formulas is that I'm slow at math. So it helps when things are broken down for me. I don't care if it takes using more variables or several shorter lines, I just need to understand what's going on. It's also a plus for sharing your code because fresh eyes looking at the formula may not understand what it's doing or why without detailed notes. Which probably ends up causing you to expend more finger taps on the keyboard thus going counter to writing shorter code with the intent of not having to type as much.Edit: (I do these a lot) Formulas that use single char variables really frustrate me. Something more meaningful with be: origin_x < destination_x or similar to what Bjarne and Herb wrote about here.Edit2: (I can't help myself) Additionally, meaningful/descriptive variables saves me time from having to trace the code back to where the var came from and what it's purpose is.
 Edgar Reynaldo Major Reynaldo May 2007 Trust me you will get tired of long variable names when you have to write them over and over and over again.It's cheaper to compare distance squared than the square root of it.Eric's way of comparing overlap is quite nice and elegant. I would prefer it above all else.
 piskypom Member #16,813 February 2018 Of course this is all a matter of taste!Even if some got lengthy, the text editor has autocomplete
 Edgar Reynaldo Major Reynaldo May 2007 Why use autocomplete? It's an extra couple keys when all I need to do is press one.Take for example this code :``` ALLEGRO_DISPLAY* d = al_create_display(800,600); ALLEGRO_EVENT_QUEUE* q = al_create_event_queue(); ALLEGRO_TIMER* t = al_create_timer(1.0/60.0); ALLEGRO_FONT* f = al_load_ttf_font("Verdana.ttf" , -20 , 0); if (!f || !d || !t || !q) { return -2; } ``` In this case, there's no need to write out "display", "queue", "timer", and "font" when one letter is enough. They're clearly declared there, and they make code elsewhere much simpler and shorter.
 LennyLen Member #5,313 December 2004 Edgar Reynaldo said: In this case, there's no need to write out "display", "queue", "timer", and "font" when one letter is enough. They're clearly declared there, and they make code elsewhere much simpler and shorter.It depends on how good/poor your memory is. Mine is terrible. If I looked at that if statement more than 5 minutes after I wrote it, I'd have to search for the declaration of the variables to know what they mean. And then sometimes by the time I've worked out what the q represents, I've forgotten what the f was again.For people like me, descriptive names save a hell of a lot of time compared to that wasted typing a few extra keystrokes.
 piskypom Member #16,813 February 2018 Edgar Reynaldo said:In this case, there's no need to write out "display", "queue", "timer", and "font" when one letter is enough. They're clearly declared there, and they make code elsewhere much simpler and shorter. It's all a matter of preference. I'm glad it works for you