Velocity for circular motion

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
timetokill
Posts: 74
Joined: Tue Jul 22, 2008 4:28 am
Location: Los Angeles

Velocity for circular motion

Post by timetokill »

Hi gang,

I want to make a character that moves in a side-scroller fashion, but in a 3D space around a circle. I'm sure there are plenty of ways to do it, and I've been exploring a bunch, but I'm kind of stuck.

I know that what would probably be the simplest way of doing this would be to have an object on the radius of the circle, with a parent at the center of the circle that gets rotated for movement. Indeed I had done this originally but I hadn't done much with it.

Recently I implemented irrNewt physics so that I could mess with it. Don't run away yet -- this isn't an irrNewt specific problem, but a general math problem. :) I've been scouring google but I can't seem to find a solution which I can follow. My math skills aren't so great, unfortunately.

For those cutting to the chase: What I want is to have a character that moves in a circular manner by means of a user-inputted velocity. In other words, when the user presses the right arrow, the character moves around the circle counter-clockwise. With the left arrow, the character moves clockwise around the circle.

How do I calculate the velocity vector to apply to my character? Any help here would be greatly appreciated, especially some code (or even pseudo-code). Feel free to shame me by showing me how easily it is done with code already posted. I did look with the search function and found some useful stuff, often involving cameras, but I was getting a little lost when trying to calculate the velocity vector in particular (and lost overall, really)

Thanks!
Munger
Posts: 28
Joined: Sun Mar 04, 2007 11:39 am
Location: Tokyo

Post by Munger »

So the character should always face the target? Something that might help your googling is 'polar coordinates'. Also, you said 'but in a 3D space around a circle', so is it a circle or a sphere you want to move in? I think you're asking about a circle and that's what I'll base my answer on.

The first problem you're going to face with a pure polar coordinates solution is that if you move at a fixed angular velocity you'll move a lot faster in linear space the closer you are to the centre (i.e. it's a lot further to travel around larger radius circles). So you can either compensate for that by making your clockwise and counter-clockwise (cw and ccw) velocities functions of the radius or...

You can do the whole thing in regular x, y coordinates (Well, x, y, z coordinates but you'll drop one dimension to work in an easy circle). Let's get a few constants out. All the points are considered to be 2D.
  • p - the position of your character
    t - the target position that you are rotating around
    v - the vector from p to t (easily to calculate t - p)
    w - a vector perpendicular to v (i.e. rotated 90 degrees)
    r - the distance you want to keep between p and t
w can be used to calculate your cw and ccw velocities. To calculate a perpendicular vector to a 2D vector (working in the xy plane here):

Code: Select all

w = core:vector2d<float>(v.Y, -v.X, 0.0);
Now to get your fixed speed, we need to get that direction vector and give it the length that we want.

Code: Select all

w.normalize();
w *= requiredSpeed;
Now we can add or subtract w to our character position to go cw or ccw. But there's more. If you just add those vectors, you're no longer going to have r units between p and t. So we have to re-size that as well.

Code: Select all

v.normalize();
v *= r;
p = t+v;
And if you keep all those values updated every frame, you should find yourself turning around that center point. Additionally, to move towards and away from t, just modify r. And you can make requiredSpeed a function of the time elapsed for the previous frame to smooth out your motion.
timetokill
Posts: 74
Joined: Tue Jul 22, 2008 4:28 am
Location: Los Angeles

Post by timetokill »

Thanks for the help. I've been trying to get it working but no luck so far. Here is the code I'm using:

Code: Select all

vector3df playerToOrigin;

	//playerToOrigin = gData->worldCenter - charNode->getAbsolutePosition();
	playerToOrigin = charNode->getAbsolutePosition() - gData->worldCenter;

	//rotate the vector to make it perpendicular
	//vector3df w = vector3df(playerToOrigin.rotateXZBy(90.0f,charNode->getAbsolutePosition()));

	playerToOrigin.rotateXZBy(90.0f,charNode->getAbsolutePosition());

	playerToOrigin.normalize();
	playerToOrigin*=1.0f;

	stringc xVel(playerToOrigin.X);
	xVel.append("\n");
	printf(xVel.c_str());	

	charCollisionBody->setVelocity(playerToOrigin);

The caveat is that I don't want to go through setting the character's position every frame because by setting the position I mess with the collisions and stuff. I'd like to just set a velocity that tells the object to try moving in the appropriate direction and let the collision handle itself.

For some reason, though, my vector always sends my character with a X vector of nearly 1.0, so he tries moving in mostly one direction instead of going in a circle.

I feel like the solution is close but I can't put my finger on it :(
timetokill
Posts: 74
Joined: Tue Jul 22, 2008 4:28 am
Location: Los Angeles

Post by timetokill »

Solved it!

And since it always annoys me when people fix their problems and don't post solutions, here was mine:

Code: Select all

//get the vector from the player to the origin, and then normalize it
			vector3df playerToOrigin;
			playerToOrigin = charNode->getPosition() - gData->worldCenter;
			playerToOrigin.normalize();
			
			//store the vector -- we don't want the y value though, because this is a horizontal measure
			vector3df horizVec(playerToOrigin.X,0.0f,playerToOrigin.Z);

			//rotate it around the center (y-axis)
			horizVec.rotateXZBy(90.0f,vector3df(0.0f,0.0f,0.0f));

			//add in the velocity we want to move in (positive for moving right, negative for moving left)
			horizVec*=runVelocityVal;

I then just applied the vector to the character as their velocity. Worked great!

Now I'm going through and changing all of my movement code to use these velocities. :D
Post Reply