Game Development Community

Interpolating rotation

by Hans Sjunnesson · in Torque Game Builder · 06/16/2005 (5:59 am) · 3 replies

This is a pretty basic vector arithmetic question, but my math skillz isn't really up to snuff today.

I've created an agent with artificial intelligence to roam around in a dungeon. Part of its behavior is to rotate to face a target. It does this by scheduling a method which linearly interpolates between the sprite's initial rotation and the angle between the target position and the sprite's position.

function Agent::smoothRotate(%this, %start, %stop, %duration, %time) {
	%ratio = 1.0 - ((%duration - %time) / %duration);
	%rot = %start + %ratio * (%stop - %start);
	
	%this.sprite.setRotation(%rot);

	%time += 0.01;

	if (%time <= %duration)
		%this.schedule(10, "smoothRotate", %start, %stop, %duration, %time);
}

This works fine and dandy, there is only one issue with it. The angleBetween2D() method returns an angle between -180 and 180, where 0 is if the target is centered over the agent.

www.iki.his.se/~a02hansj/rotation1.png
The idea is for the agent to face its new direction by turning the shortest amount. But the agent will never cross the -180/180 limit. Here's an illustration of how it LERPs over two face changes.

www.iki.his.se/~a02hansj/rotation2.png www.iki.his.se/~a02hansj/rotation3.png
Any ideas of how to solves this? I have a few ideas, but they seem kludgy. There's got to be a proper way of doing it.

#1
09/07/2005 (1:47 am)
I'd like to reawaken this dead thread. I'm still having the same problems and I really can't figure out a way around it.
Here's a new image describing my problem.

img294.imageshack.us/img294/7919/rotationlerp1wl.jpg
As you can see, if I interpolate between angles which don't cross the over the "south" direction (where 180 degrees turn into -180 degrees, if you rotate clockwise), the smoothRotate function will turn the shortest distance to the new direction. However, the second example shows what happens if you try to interpolate across the -180/180 limit. It goes the long way around.

Here's a bare-bones example which you can just chuck into the standard T2D example setup to see how it looks for me.
function fxSceneObject2D::smoothRotate(%this, %start, %stop, %duration, %time) {
	%ratio = 1.0 - ((%duration - %time) / %duration);
	%rot = %start + %ratio * (%stop - %start);
	
	%this.setRotation(%rot);

	%time += 0.01;

	if (%time <= %duration)
		%this.schedule(10, "smoothRotate", %start, %stop, %duration, %time);
	else
		%this.isTurning = false;
}

function setupScene() {
	$sprite = new fxStaticSprite2D() {scenegraph = t2dSceneGraph;};
	$sprite.setImageMap(ggLogoImageMap);
	$sprite.setPosition("10 -10");
}

function sceneWindow2D::onMouseDown(%this, %modifier, %worldPosition, %mouseClicks) {
	%angle = angleBetween2D($sprite.getPosition(), %worldPosition);
	echo(%angle);
	if (!$sprite.isTurning) {
		$sprite.isTurning = 1;
		$sprite.smoothRotate($sprite.getRotation(), %angle, 1);
	}
}

Does anyone have any inputs on this?

--
Hans
#2
09/07/2005 (2:40 am)
Example Request Thread.
Take a look at the above thread. I've got some code in there that handled the +-180 degree thing. It's not fantastic code by any means, but it works. :)
#3
09/07/2005 (3:38 am)
Sweet. Thanks, man. This works perfectly.

--
Hans