As per my last post I got that problem solved, and I also read that website down near the bottom of the post as per Neil: http://www.helixsoft.nl/articles/circle/sincos.htm
This gave me the though to add hit zones or collision circles that identify the hit zones on an object. Seemed simple enough I use a defining point of x,y and rotate that around a central point at the same rate as the image rotates. This is the code I wrote to accomplish my goal, I also have a function to draw green circles to show where the C_Circs are placed on the spider. Currently they aren't drawing correctly I get white circles, but I can see them(guessing it is a mode setting in my drawing routine or the alpha channel). After I use a key to rotate the spider the circles just disappear I assume this is because of some misinterpretation of the atan2 function or a misconversion to a fixed. Going to keep playing with it and see if I can find my error any help would be appreciated.
EDIT: Found my circles decided to do a blit to force it to draw without alpha or masking(and learned even more from that!) For some reason the circles are stuck in the top left corner only in a couple rotation positions though.
EDIT 2: Attached a copy of what is going on to help explain things.
Wrong approach. You should not find any current angle, add rotation and use the new angle to find the new point. Theoretically it works, but there's a much shorter way. In your code you seem to forget to add back the center point.
Anyway, here's what you should do:
First, simplify your rotation. Think of it as rotating around origin. Divide (x, y) into (x, 0) plus (0, y). How do you rotate (x, 0)? That's (x * cos(a), x * sin(a)), right? How do you rotate (0, y)? That's (-y * sin(a), y * cos(a)), right. Add these and you get:
x1 = x * cos(a) - y * sin(a)
y1 = x * sin(a) + y * cos(a)
If I made an error, the idea should still be clear. Just check it all
Ok, you're rotating around X, Y. Do what you did in your code (but don't forget the last part):
x = x - X;
y = y - Y;
Do my rotation around origin
x = x + X;
y = y + Y;
Or uglify everything by not rotating around origin.
After tinkering with the code I can explain my thought process as to why exactly I was doing things the way I was trying to accomplish them.
You should not find any current angle, add rotation and use the new angle to find the new point.
The reasoning for that is one of my C_Circ classes may not start at 0 degrees of rotation. These are hit zones on a mob ex(Head shots, body shots, or other vital area shots). This class can potentially start anywhere that is possible in the sprite.
Problem I have found: Length is returning inconsistant values for some reason making the points jump all over the place.
Loading information into a C_Circ class:
Class constructor:
C_Circ::C_Circ(int X,int Y,int R) { x = X; y = Y; rad = R; }
Here we have the monster rotation code I intend to switch over to vectors for my container, but the netbook I compile on when I am at work on break or whatever doesn't seen to have vector.h and I haven't remembered to copy it over.
For the function call to rotate
NOTE: I have set my length to a static 16 to do error checking(and I can see one hit zone work properly). I assume I could just use sin(Degrees) and drop all the conversions, but for now getting functionality and then later making it optimized will work.
EDIT:
Now after all that you must be thinking "You should use the code Johan posted" his code becomes unstable as well.
void C_Circ::Rotate_Around_Point(int X,int Y,int Degrees) { //int Length = sqrt((abs(X-x)*abs(X-x))+(abs(Y-y)*abs(Y-y))); x = X + (X-x) * fixtoi(fcos(itofix(Degrees))) - (Y-y) * fixtoi(fsin(itofix(Degrees))); y = Y + (X-x) * fixtoi(fsin(itofix(Degrees))) + (Y-y) * fixtoi(fcos(itofix(Degrees))); //x = X + Length * fixtoi(fcos(itofix(Degrees))); //y = Y + Length * fixtoi(fsin(itofix(Degrees))); }
EDIT #3:So I started outputting everything into a txt file so I could see what was going on.... What I learned:
fixtoi(fsin(itofix(r))) or similar functions will give no precision guess I should have noticed int and not float or something similar... -1 0 1 are the only states given by this method might work for an 8 direction numpad type game, but not for anything with true angles.
Rounding errors are going to be a nightmare as I watch the circles slowly move to the origin point as the sprite rotates now...
huh<<"C: "<<lcv<<endl; huh<<"WIDTH OF BMP/2: "<<ceil(MAGIC->w/2)<<endl; huh<<"HEIGHT OF BMP/2: "<<ceil(MAGIC->h/2)<<endl; huh<<"HZ_X: "<<Hit_Zones[lcv]->Get_X()<<endl; huh<<"HZ_Y: "<<Hit_Zones[lcv]->Get_Y()<<endl; huh<<"ANGLE: "<<r<<endl; huh<<"SIN ANGLE: "<<fsin(itofix(r))<<endl; huh<<"COS ANGLE: "<<fcos(itofix(r))<<endl; huh<<"d65536 SIN ANGLE: "<<(float)fsin(itofix(r))/65536<<endl; huh<<"d65536 COS ANGLE: "<<(float)fcos(itofix(r))/65536<<endl; huh<<"F_SIN ANGLE: "<<fixtoi(fsin(itofix(r)))<<endl; huh<<"F_COS ANGLE: "<<fixtoi(fcos(itofix(r)))<<endl; huh<<"LENGTH: "<<sqrt((abs(ceil(MAGIC->w/2)-Hit_Zones[lcv]->Get_X()) * abs(ceil(MAGIC->w/2)-Hit_Zones[lcv]->Get_X())) + (abs(ceil(MAGIC->h/2)-Hit_Zones[lcv]->Get_Y()) * abs(ceil(MAGIC->h/2)-Hit_Zones[lcv]->Get_Y())))<<endl<<endl;
FINAL EDIT:
Finally got the issues fixed. Instead of recalculating the length every time(which was introducing rounding issues). Getting rid of the recalculating length fixed most of the issues, just had to do a little bit of sign preservation.
void C_Circ::Rotate_Around_Point(int X,int Y,int Degrees) { if(RX != X || RY != Y) //Not the same rotation point! { RX = X; RY = Y; RL = sqrt((abs(X-x)*abs(X-x))+(abs(Y-y)*abs(Y-y))); if(X - x > 0)RL *= -1; if(Y - y < 0)RL *= -1; } x = X + (int)(RL * (double)fcos(itofix(Degrees)) / 65536); y = Y + (int)(RL * (double)fsin(itofix(Degrees)) / 65536); }
The reasoning for that is one of my C_Circ classes may not start at 0 degrees of rotation.
Irrelevant. You have a point (x, y) and you want to rotate it around point (X, Y) by an angle Degrees, right?
I'd still do it like this:
And if you want speed, you should calculate cos and sin only once:
As for rounding errors, use doubles, not ints. X and Y may be ints, if they really are just screen coordinates. But x and y, if they define your object position which change through rotation and whatnot, should be doubles.
In my code, the only expensive calculations are one sin and one cos. Where you calculate the distance with Pythagoras, in my code it's reduced to x -= X and y -= Y. You don't need the fixed functions here. People say double is as fast as fixed nowadays. fixed maybe is needed only when you do rotate_sprite() in Allegro 4.
I wasn't having as much of a problem with the sin / cos rounding, but the sqrt rounding was coming out of no where. I think this solution is faster than yours even assuming I rotate around one point at a time.
FINAL EDIT:
Finally got the issues fixed. Instead of recalculating the length every time(which was introducing rounding issues). Getting rid of the recalculating length fixed most of the issues, just had to do a little bit of sign preservation.
void C_Circ::Rotate_Around_Point(int X,int Y,int Degrees) { if(RX != X || RY != Y) //Not the same rotation point! { RX = X; RY = Y; RL = sqrt((abs(X-x)*abs(X-x))+(abs(Y-y)*abs(Y-y))); if(X - x > 0)RL *= -1; if(Y - y < 0)RL *= -1; } x = X + (int)(RL * (double)fcos(itofix(Degrees)) / 65536); y = Y + (int)(RL * (double)fsin(itofix(Degrees)) / 65536); }
How can it possibly be faster?
The inverse square root function using that special number with Newtons method might work.
Mine calls that once assuming one point of rotation.
If I recall my asm a compare is a 4 tick command which TBH would be faster than the extra casting calls and the like. His code is also flawed in the fact that Degrees in 0 - 256 so it is missing the conversion there not a big thing. My sqrt only occurs in the first itteration, after that it does not get called again untill we change our rotation point(which never changes as it is the center of the sprite and not a position in the world.) While each sprite has hit zones, they each have a master zone which is used in world calculations. Either code works I think, but origonally his code did not work, and neither did mine I had fixed the issue only to find a few days later that there are replys which I am grateful for as it does help to see from a different point of view. I would rather post my code and get it working my way if it is possible then be shown another possibly more efficent way. I had reffered to his origonal post with 2xsin and 2xcos one call to sqrt(since that part of the code never changes the rotation point) and only one call to cos and sin each seemed alot better.
To show what has been accomplished I am attaching an exe. Still need to tweak the movement a little since the spider seems to have issues getting to the correct point when he is walking(a bit of walking sideways apparently fixes that, but looks horrible)
I just use this:
public void rotateAboutPoint(Location point, float r) { float n = dist(point.getX(), point.getY(), getX(), getY()); float a = point.getX() - getX(), b = point.getY() - getY(); r -= (float)(Math.Atan2(b, a)); moveTo(point.getX() - (float)(n * Math.Cos(r)), point.getY() + (float)(n * Math.Sin(r))); }
It's probably slow, but it works just fine and is easy to understand.
Isn't atan2 undefined for angle = 0? I know that was in the reading I did...
atan2(a, b) is probably undefined when a and b both equal 0.
and is easy to understand
Well, go through this:
{"name":"605647","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/7\/0712d4a6e70c7308d4a4830d6f07d737.png","w":400,"h":300,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/7\/0712d4a6e70c7308d4a4830d6f07d737"}
You have x1 y1 and you want to rotate it by the angle of a to reach x2 y2.
Well, x1 y1 is practically x1 0 plus 0 y1, right? When you rotate x1 y1 and get x2 y2, it's same as first rotating x1 0 to get to r1, then rotating 0 y1 to get r2...
{"name":"605648","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/e\/7\/e7e1a75dd99cfe4764015b8f487efbc6.png","w":400,"h":300,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/e\/7\/e7e1a75dd99cfe4764015b8f487efbc6"}
Some maths here. xr1 = x1 * cos(a), yr1 = x1 * sin(a)
xr2 = -y1 * sin(a), yr2 = y1 * cos(a)
Now you can add r1 and r2...
{"name":"605649","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/d\/2\/d27450d956545c051f0399eae599839f.png","w":400,"h":300,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/d\/2\/d27450d956545c051f0399eae599839f"}
...and you get:
x2 = x1 * cos(a) - y1 * sin(a)
y2 = x1 * sin(a) + y1 * cos(a)