Allegro.cc - Online Community

Allegro.cc Forums » Game Design & Concepts » ricochets

This thread is locked; no one can reply to it. rss feed Print
ricochets
David Sopala
Member #5,056
September 2004

My current code for bouncing a bullet off of an arbitrary line in my game. Currently it does some odd things such as a bullet getting up to the line and stopping. Occasionally it bounces off the line then bounces off nothing hits the line again and does this for a while. Other times it works perfectly. Currently all my lines are horizontal or vertical, but I intend to add triangles to give the game a better feel instead of being square. does anyone see the issue I am overlooking in my code?

#SelectExpand
1void Bullet::Ricochet(C_Rect *r) 2{ 3 C_Line Line; 4 x = x + ceil(speed * ((double)fcos(itofix(angle)) / 65536)); 5 y = y + ceil(speed * ((double)fsin(itofix(angle)) / 65536)); 6 C_Point Prev(x,y); 7 8 Line = r->Get_Closest_Line(Prev); //checks our position to all the lines will give us an answer which line we will hit. 9 10 if(!Line.Is_Horizontal()) 11 { 12 int langle = Line.Get_Point1().Find_Fixed_Angle(Line.Get_Point2()); 13 //to make my incidence line horizontal I will subtract my angle from the bullet's angle to get the angle of incidence. 14 int tangle = angle - langle; //this makes it seem as though we are hitting the x-axis of a graph. Basicly subtracted the angle from both sides of the equation one side (the line) is zero the other is the angle of approach of the bullet 15 if(tangle > 0 && tangle < 128)//hitting from the bottom 16 { 17 angle = 128 - tangle + langle; 18 }else //hitting from above 19 { 20 angle = 256 + tangle + langle; 21 } 22 }else 23 { 24 angle = 256 - angle; 25 } 26 27}

gnolam
Member #2,030
March 2002
avatar

You can start by not using Allegro angles for anything other than the final rotate_sprite()/pivot_sprite() call. They make the code hard to read, unnecessarily painful to write, and give you no performance benefits whatsoever. :P

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Schyfis
Member #9,752
May 2008
avatar

To me it sounds like sometimes your bullet is registering more than one collision on consecutive frames. This would explain the bouncing back and forth you're experiencing.

Ideally it should only collide once, right? Try printing something in the console when a collision is detected and see if that's the problem. (i.e. two or more printed lines appear in the console)

________________________________________________________________________________________________________
[freedwill.us]
[unTied Games]

David Sopala
Member #5,056
September 2004

Is cout still safe to use even with the graphics window open from allegro? Or is printf preferred?

LennyLen
Member #5,313
December 2004
avatar

Is cout still safe to use even with the graphics window open from allegro? Or is printf preferred?

I'm not sure what you mean by safe, but they both use stdout, so they will both work equally.

David Sopala
Member #5,056
September 2004

I was trying to ask if I could still use it with allegro in the picture and not have issues.

-I did a data dump to a file to trace the bullet, it is bouncing off the same wall multiple times.

Although my calculations seem to be working - at the very least.

Never done any math like what I am using here that I can remember anyways everything was applied to electronics and such back in college and not to programming or arbitrary angles and the like.

Very very close to the code working correctly... although I am having some issues on one wall segment for some reason, it is like it doesn't even try to bounce it flys through, but does the ricochet calculations many many times on the bullet, but never fixes the issue.

#SelectExpand
1void Bullet::Ricochet(C_Rect *r) 2{ 3 C_Line Line; 4 x = x + ceil(speed * ((double)fcos(itofix(angle)) / 65536)); 5 y = y + ceil(speed * ((double)fsin(itofix(angle)) / 65536)); 6 C_Point Prev(x,y); 7 8 Line = r->Get_Closest_Line(Prev); //checks our position to all the lines will give us an answer which line we will hit due to no lines with angles > 90 lines of a rect always shield the other lines. 9 int langle = 0; 10 if(!Line.Is_Horizontal()) //we need to rotate the line to a horizontal position 11 { 12 langle = Line.Get_Point1().Find_Fixed_Angle(Line.Get_Point2()); 13 angle = angle - langle; //to give us the new angle of approach 14 } 15 //at this point the line is horizontal and the bullet is ready to be fixed. 16 angle = 256 - angle; 17 angle += langle; 18}

I am clueless as to why my test situation was acting weird doing what I said - I randomly thought to myself screw it I will make one big wall all by itself out there in the world and see if it is a clipping issue or something - well one big wall works fine... maybe my lines were too close or something with lots of little walls :/ Well maybe one day this code will help someone else it seems to be working perfectly now.

decepto
Member #7,102
April 2006
avatar

Hi David,

I'm not sure what the "horizontal position" part of your code is trying to do, but I might be able to help with your overall goal.

All of the data required to simulate and render a ricochet can be calculated using some rather simple mathematics. Try the following:

1. Think of your wall (or object which the bullet will bounce off) as a line or line segment, W.

2. Think of your bullet (and it's initial path) as a line, L.

3. Perform an intersection test between L and W. We'll call their intersection point P.

4. If L and W intersect, calculate L's normal vector. This is easy, it just involves changing the sign of one of the components. From this vector and the point of intersection, we can build another line which represents the bullets first ricochet path. We'll call this line R1.

So, now you have four pieces of data:
(Line L) Bullet's initial path
(Line W) The wall
(Point P) The point where L and W intersect
(Line R1) The bullets ricochet path.

R1 is the bullet's first ricochet path. You could continue to calculate ricochets off other walls if you wish. This is exactly how one builds a billiards game.

All of these calculations should be done before any animation or rendering takes place.

From my understanding, you don't often work with mathematical code. However, I would strongly suggest you take this approach. You code will be much shorter, easier to follow, and easier to change.

Since you're using C++, I would highly recommend using GLM as a math library. It's a header only library, so no need for compilation.

Intersection testing is this most difficult part of this process. It's a large area of research when you get into higher dimensions and more complex shapes. However, testing for a Line/Line intersection is fairly painless.

edit

A quick method for performing Line/Line intersection is to take the cross product of two vectors, which is effectively the determinant. The lines don't intersect if their parallel. In all other cases, they do intersect...somewere. If the determinant is Zero, the lines are parallel.

float det = glm::cross( glm::vec3(1, 0, 0), glm::vec3(1, 0, 0) )
if ( det == 0 ) {
  // lines are parallel, no intersection
} else {
  // lines are _not_ parallel, but where do they intersect
  // next, find intersection point of lines
  ...
}

--------------------------------------------------
Boom!

David Sopala
Member #5,056
September 2004

I wrote all my line - line point comparison code and the like myself from my research. Looks like your functions are coded for 3D space which is nice, but not something I want to dive into before my long vacation in October so I have time to learn whats going on.

The line - line intersection code is:

#SelectExpand
1bool C_Line::Lines_Intersect(C_Line l) 2{ 3 4 C_Point A = p; 5 C_Point B = p1; 6 C_Point C = l.Get_Point1(); 7 C_Point D = l.Get_Point2(); 8 9 int x1 = A.Get_X(); 10 int x2 = B.Get_X(); 11 int x3 = C.Get_X(); 12 int x4 = D.Get_X(); 13 14 int y1 = A.Get_Y(); 15 int y2 = B.Get_Y(); 16 int y3 = C.Get_Y(); 17 int y4 = D.Get_Y(); 18 19 20 float denom = ((y4 - y3)*(x2 - x1)) - ((x4 - x3)*(y2 - y1)); 21 if(denom == 0)return false; 22 float ua = ((x4 - x3)*(y1 - y3) - (y4 - y3)*(x1 - x3)) / denom; 23 float ub = ((x2 - x1)*(y1 - y3) - (y2 - y1)*(x1 - x3)) / denom; 24 25 if(ua <= 1 && ua >= 0 && ub <= 1 && ub >= 0)return true; 26 else return false; 27}

Cross product? Yea I got that too.

float C_Point::Dot_Product(const C_Point &p)
{
    return ((x * p.x) + (y * p.y));
}

float C_Point::Cross_Product(const C_Point &p)
{
    return (x * p.y) - (y * p.x);
}

Note you can take the primary line normalize x1 and x2 to the origin and then multiply by the ua factor then add that back to the first x1 to get the x intersect. Works as well with the y coordinate with ub I believe.

The reason my code was written how it is was because normally I am checking vs shapes in the game loop, see how this function takes a rectangle? My goal was to write code that would handle the bounce properly and it does although I think your might be better designed to push two objects away from each other(like in pool when two balls hit they both move.) Currently this is working better I still need to code a few things, but I am a lot closer to what my goal is now. I just need to rotate some shapes now and I will be all set.

Go to: