Skip to main content
GameDev.net gamedev.net
🔒 Locked

Rotation with Trigonometry and Movement based on facing

Started by Gyad May 12, 2009 at 8:17 AM 6 replies 2.9k views
Original Post
Gyad
Gyad
So I've been trying to figure out how to get rotation for any arbitrary object working, but so far I've had no luck. What I basically need to do is rotate a sprite 360 degrees around it's own center point using some sort of trigonometry as well as move the object forward depending on the direction it's facing. I was told to use the formula:

		x = x * cos(theta) - y * sin(theta);
		y = y * sin(theta) + y * cos(theta);
but I'm not really sure what it really does. And even if it does rotate the sprite correctly (which it doesn't), I don't know how to determine the direction it's facing so I can't move it forward. The way my design works right now, is that I have a separate class for every movable object. This is done by giving it a Top Left coordinate, and a length/width to determine its rectangle size. It then has a RECT for its bounding/collision box. Note: This is all done in 2D using C++ and DirectX
scwizzo
scwizzo
My working version is for 3D with X and Z, but it could easily be X and Y. It's also in OpenGL, but the math is the same. Here's something to give you an idea.

//in the render loop/functionheading = 360.0f - lookdir; //reset look direction which is opposite of 360glRotatef(heading,0,1.0f,0);glTranslatef(xpos,jump,zpos); //moves the starting position//in the keyboard message sequence, cos/sin sees radians not degrees                                if(keys[VK_UP])				{				    zpos+=0.05f*cos(lookdir*pi/180.0);				    xpos+=0.05f*sin(lookdir*pi/180.0);				}				if(keys[VK_DOWN])				{				    zpos-=0.05f*cos(lookdir*pi/180.0);				    xpos-=0.05f*sin(lookdir*pi/180.0);				}				if(keys[VK_NEXT]) //for strafing side to side				{				    xpos+=(0.05f*cos((heading+180)*pi/180.0));				    zpos+=(0.05f*sin((heading+180)*pi/180.0));				}				if(keys[VK_PRIOR]) //for strafing side to side				{				    xpos-=(0.05f*cos((heading+180)*pi/180.0));				    zpos-=(0.05f*sin((heading+180)*pi/180.0));				}				if(keys[VK_LEFT])				{				    lookdir+=0.5f;				}				if(keys[VK_RIGHT])				{				    lookdir-=0.5f;				}
/ Visual Studios 2010 / Codeblocks 10.05 / Windows 7 / Ubuntu 10.10 / - I might be wrong
Zakwayda
Zakwayda
Quote:
I was told to use the formula:

x = x * cos(theta) - y * sin(theta);
y = y * sin(theta) + y * cos(theta);
That should actually be:
x' = x * cos(theta) - y * sin(theta)y' = y * sin(theta) + y * cos(theta)
If use the formulas exactly as you've shown, you'll overwrite 'x' while it's still in use and get nonsensical results. [Edit: It looks like there's a typo as well - the second equation should have an 'x' in it.]
Quote:
but I'm not really sure what it really does. And even if it does rotate the sprite correctly (which it doesn't), I don't know how to determine the direction it's facing so I can't move it forward.
Normally you wouldn't rotate the corners of the sprite incrementally. It's more typical to store the orientation of the object (using the represention of your choice - a single angle is a reasonable choice in 2-d), and then transform a local-space copy of the sprite geometry as needed for rendering. This will also make it easier to compute a direction vector for the object.
Quote:
The way my design works right now, is that I have a separate class for every movable object.
That sounds a bit suspicious. How do the classes differ exactly?
Quote:
This is done by giving it a Top Left coordinate, and a length/width to determine its rectangle size. It then has a RECT for its bounding/collision box.
For most purposes it's usually more convenient to associate the object's position with the sprite's center rather than a corner (this makes rendering more straightforward, and can simplify collision detection as well).
Gyad
Gyad
Quote:

That should actually be:
x' = x * cos(theta) - y * sin(theta)y' = y * sin(theta) + y * cos(theta)


Yeah that's a typo; it doesn't actually look like that in my code.

Quote:
That sounds a bit suspicious. How do the classes differ exactly?


That's bad wording on my part; I meant I have one separate class (called Tangible) that handles any object on the screen.

Quote:
My working version is for 3D with X and Z, but it could easily be X and Y. It's also in OpenGL, but the math is the same. Here's something to give you an idea.


I'll try to make some sense of it and report back!
Gyad
Gyad
Small update + clarification on other stuff:

So I took scwizzo's code and experimented with it a little, and it only gave me half of the results I needed. It gives me the movement that I need, but not the correct rotation.

For the record, I use D3DXMatrixTransformation2D to apply the actual rotation.

The rotation I have right now, rotates the entire object around a certain point depending on its coordinates. What I need is for it to rotate around it's own center point (a coordinate I set).

http://i40.tinypic.com/1zp46zm.jpg

This image describes what is happening to my object right now. The circle is the rotation path the square is following. Notice that as it gets closer to the bottom right of the screen, the size increases.
scwizzo
scwizzo
I don't know how you have your rendering set up, nor do I know how DirectX does it since I've never programmed in DX3D, but here is how my render function is set up. It rotates everything (the world) about the player, instead of rotating the player in the world. That way it gives the impression that the player is rotating on it's own when really it's rotating at the origin and the world is moving. As for the rotation size getting bigger, I have no idea.

Here is how my render function is set up

/*same stuff from previous post with comments*/heading = 360.0f - lookdir;//render the character here so it will remain stationaryglRotatef(heading,0,1.0f,0);glTranslatef(xpos,jump,zpos); //moves the starting position//render the world after this point, as the world will be translating, not the character/sprite/whatever
/ Visual Studios 2010 / Codeblocks 10.05 / Windows 7 / Ubuntu 10.10 / - I might be wrong
Emergent
Emergent
Many graphics APIs will rotate a sprite for you and you don't need to know what's going on under the hood. Moreover, the rotation is handled by the graphics hardware so it's fast. You'll need to look up DirectX-specific information if you want to do this.

The formula you refer to is what you'd use if you wanted to write your own rotation function in software. Referring to the equation in jyk's post, (x', y') is the point (x,y) rotated by theta degrees.

Writing your own image rotation function is easy to do -- it'll be under 10 lines of code -- and a decent learning opportunity if you've never done it before. However, letting the hardware do the rotation is faster and probably easier depending on the specific API you're using.

If you want to write your own image rotation function, here's how it's normally done: For each pixel in the destination image, you find the corresponding point in the source image using the rotation formula mentioned earlier. Since this point will not be an integer, you use bilinear interpolation to generate its value.

This is the algorithm referred to as 'rotation by area mapping' here. Rotation by shear, mentioned earlier in the linked page, is kind of neat too but a tiny bit less intuitive.
Erik Rufelt
Erik Rufelt
Firstly, cos and sin take their angles in radians, not degrees. To convert degrees to radians you do 'rad = degrees * pi / 180'.
If you have an angle 'a' between 0 and 360, where 0 is in the positive X direction, 90 is positive Y, 180 is negative X, and 270 is negative Y, which is the standard, then you can get an (X,Y) direction from your angle by doing:
xdir = cos(a * pi / 180)ydir = sin(a * pi / 180)

So to move in the correct direction, you simply move it with
xposition += xdir * moveLengthyposition += ydir * moveLength


To rotate a point around the origin, you use
a = in radiansnewX = oldx * cos(a) - oldy * sin(a)newY = oldy * cos(a) + oldx * sin(a)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.