3
\$\begingroup\$

Edit 2 - clarification

Just to clarify, the issue I have at the moment is how I specify a time (in seconds) for a complete revolution to occur. My delta is fixed and is 1/ticks per second (1/60). As you can see with my linear sprite movement, I have a 'time' variable which is where I specify (in seconds) how long the sprite should take to travel the length (or height) of the screen. I'm looking at how I do this for circular movement.

Edit 1 - Results from suggestions

See at end of question.

Background

When moving my sprites along a straight path, I'm using delta so I can get the same rate of relative motion on all devices like so:

spriteGridX = 240/480;  //I start out with a virtual 'Grid' so I can scale position to all resolutions etc so 240/480 would place the sprite at the center of the screen (X)

spriteScreenX = spriteGridX * width;  //Scale to physical screen where width is the width of the current devices screen (viewport)

spriteXTime = 8f; //8 being the amount of time in seconds that this sprite will take to traverse the entire width of the screen

spriteXVel = 1/spriteXTime; //Velocity that will be used to move the sprite along the virtual grid position

So, when I need to move the sprite, I simply do the following:

spriteXGrid+= (spriteXVel * Delta) //+= for right -=for left. I'm using a fixed delta time
spriteScreenX = spriteGridX * width; //And again, convert to usable screen position for current device
drawsprite(spriteScreenX, SpriteScreenY); //Draw the sprite (drawSprite is just a method I've written to draw openGL quads and it takes the screen X and Y as coordinates - spriteScreenY not shown here but essentially same as X with height instead of width.

Now, I need to have a sprite move along a circular path. So far, I have a test up and running which directly acts on the 'screen' coordinates of the sprite directly like so:

Java Code

int rad = 25;
float angle = 50;

spriteScreenX-=Math.round(rad*Math.cos(angle));
spriteScreenY+=Math.round(rad*Math.sin(angle));
angle+=.1;

The Problem

Now, the above does work, but the sprite completes it's circular path way too quickly (it's doing approximately 1 revolution per second).

So my question is:

  • Am I doing this correctly and if so..........
  • How do I slow this down? I won't particularly need to keep changing the speed, I just want to be able to set it initially.

Would really appreciate some pointers.

Edit 1

When I put the following the code above I get the following result:

enter image description here

If I put the following:

spriteScreenX-=Math.round(rad*Math.cos(angle*Math.PI/180*delta));
spriteScreenY+=Math.round(rad*Math.sin(angle*Math.PI/180*delta));
angle+=.1;

Or:

spriteScreenX-=Math.round(rad*Math.cos(angle*delta));
spriteScreenY+=Math.round(rad*Math.sin(angle*delta));
angle+=.1;

Something like this happens:

enter image description here

\$\endgroup\$
  • \$\begingroup\$ 1. Learn to us radians. 2. Apply your delta to your rotational velocity, like you do for your linear speed. Right now you're rotating at 0.1 per frame, which is roughly 1/60 of a full circle. So at 60fps, that's 1 rev per second. \$\endgroup\$ – Seth Battin Dec 12 '13 at 2:04
  • \$\begingroup\$ @SethBattin, thanks for the comment. I understand that there are 2Pi Radians in a full circle and that 1 radian is about 57.2958 degrees. However, I can't understand how I can alter the size and / or speed along which my sprite travels. I'm not sure how to correctly apply delta to control speed. Please see my updated question. Thanks for your time. \$\endgroup\$ – BungleBonce Dec 12 '13 at 19:06
  • \$\begingroup\$ Ahha, I think I understand. I'll post a proper answer. \$\endgroup\$ – Seth Battin Dec 12 '13 at 19:14
0
\$\begingroup\$

Math's trig functions use radian so multiply the angle by Math.PI/180 before passing as parameter

you can apply a delta to the angle to reduce the speed

if you want to rotate along a specific point (px, py) then you can do the following

double tmpx = spriteXGrid - px;
double tmpy = spriteYGrid - py;

double resultx = tmpx*Math.cos(angle*Math.PI/180*delta)-tmpy*Math.sin(angle*Math.PI/180*delta) + px;
double resulty = tmpy*Math.cos(angle*Math.PI/180*delta)+tmpx*Math.sin(angle*Math.PI/180*delta) + px;
\$\endgroup\$
  • \$\begingroup\$ I'm not sure how to alter the time. Let's say I want the revolution to take 5 seconds. Where do I specify the T Time period? As with my linear sprite movement where I have a 'time' variable. This is the part I'm not sure about. \$\endgroup\$ – BungleBonce Dec 13 '13 at 12:42
0
\$\begingroup\$

You are using += to modify the position directly from the angle. Effectively, you aren't updating the position along an arc, you are updating the direction of movement. So when you slow it down, all you get is a direction that changes more slowly, which means a bigger circle.

To use a radial velocity, you would need the center of rotation. But that seems like a cumbersome extra bit of data to store. It would be simpler to store and update speed separately from direction. Then you could always update the position according to a single frame's instantaneous velocity, rather than calculating some offset based on a radius, then calculating the angle traverse, turning that back into a position, etc.

For example:

// class members

//    speeds
double spriteVel;
double radian_speed;  // can be zero while not turning

//    positions
double positionx;
double positiony;
double radians_angle;

//update

double speed = (spriteVel * Delta);

radians_angle += (radians_speed * Delta);     

double directionx = Math.cos(radians_angle);  // from -1 to 1
double directiony = Math.sin(radians_angle);  // from -1 to 1

positionx += speed * directionx;
positiony += speed * directiony;

Now if you increase the angular speed, the object will turn in a smaller radius. It would still be possible to calculate the radius of the turn. The math will be very simple, if you use radians. :)

\$\endgroup\$
  • \$\begingroup\$ Thanks @SethBattin for this. I'm definately doing something wrong but I can't figure out what. When I implement the code, all I get is a very 'jerky' diagonal movement. I've no idea where I'm going wrong. I'm not sure I understand the '-1 to 1' comment in your code. Thanks :-) \$\endgroup\$ – BungleBonce Dec 12 '13 at 21:22
  • \$\begingroup\$ The trig functions cos and sin should return values between -1 and 1. If you run both of them on the same angle, you will get the components of a normalized 2-vector (cos^2 + sin^2 = 1). If you want further debugging help, try the Game Development Chat. \$\endgroup\$ – Seth Battin Dec 12 '13 at 21:24
0
\$\begingroup\$

The solution I used for anyone who comes across this problem was this:

Initial Setup

int rad = 200;       //Radius in px
float angle = 0;     //Angle (this needs to be represented in radians, not degrees)
float centreX;       //X Coordinate of the centre of rotation
float centreY;       //Y Coordinate of the centre of rotation
float time;          //Number of seconds a full revolution should take
int ticksPerSecond   //Number of game updates per second
float spriteX;       //X Position of sprite
float spriteY;       //Y Position of sprite

To rotate the sprite

//Update the angle

angle+= 2 * Math.PI / (ticksPerSecond * time);

//Update the coordinates

spriteX = (centreX  + (rad*Math.cos(angle)));
spriteY = (centreY  + (rad*Math.sin(angle)));

I've tested this at various screen resolutions and time settings and the sprite rotates according to the time variable (i.e. specify 10 seconds and it will take 10 seconds for 1 complete revolution to occur).

Changes in the time setting will not alter the radius of the orbit's path and the opposite is also true.

If you want to set the initial angle of the object around the orbit-path, then simply specify in radians

angle = (angle in degrees)/180 * Math.PI
\$\endgroup\$
0
\$\begingroup\$

Forget approx. You can get the thing to move in 1 circle exactly 1 time per sec.

A sinusoid sin( 2*M_PI*freq*t ) makes freq cycles per second.

Your framerate is kinda irrelevant to the sinuosoid. If you are using a framerate of 60 fps, just fix your timestep to timeStep=1./60. Now if t represents "clocktime", the sinusoid will progress at freq cycles per second. The sinusoid doesn't care that your t is discrete.

Also, don't accumulate your sin offset. What you want to do is specify a centroid position, and the sin/cos values are the offsets that get applied on each frame.

The position of a sprite moving in a circle of radius r with centroid c should be computed as

px = cx + r*cos( 2*M_PI*freq*t ) ; // t is accumulated "real" time, 1/60 first frame, 2/60 2nd frame..
py = cy + r*sin( 2*M_PI*freq*t ) ;

enter image description here

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.