Due to popular demand(from my fan club, i.e. the dude in the mirror) I'm posting this code here. In 2D, this code will turn(a line in this example) toward the mouse at 1 degree per frame maximum, this is useful for homing missiles, basic AI and what not.
Set Display Mode 800 , 600 , 32 , 0
Sync On
Sync Rate 100
ObserverX As Float
ObserverY As Float
ObserverYRot As Float
Angle As Float
DistanceX As Float
DistanceY As Float
EulerAngle As Float
LocalAngle As Float
TurnRate As Float = 1.0
YRot As Float
Do
CLS
Inc Angle , 0.5
// Move observer around
ObserverX = 400.0 + Sin(Angle) * 200.0
ObserverY = 300.0 + Cos(Angle) * 200.0
// Draw observer and target
Ink RGB(55,55,155),0
Circle MouseX() , MouseY() , 5
Circle ObserverX , ObserverY , 10
// Position target(mouse)
DistanceX = MouseX() - ObserverX
DistanceY = MouseY() - ObserverY
// Find global angle between observer and target
EulerAngle = AtanFull( DistanceX , DistanceY )
// Subtract current angle to find local angle
LocalAngle = Wrapvalue( EulerAngle - ObserverYRot )
// Is the other way faster?
If LocalAngle > 180.0
LocalAngle = -(360.0 - LocalAngle)
Endif
YRot = LocalAngle
// Clamp rotational speed
If YRot > TurnRate Then YRot = TurnRate
If YRot < -TurnRate Then YRot = -TurnRate
ObserverYRot = Wrapvalue( ObserverYRot + YRot )
Ink RGB(100,100,100),0
Line ObserverX , ObserverY - 20 , ObserverX , ObserverY
Line ObserverX , ObserverY , MouseX() , MouseY()
Text ObserverX - 30 , ObserverY + 30 , "EulerY: " + Str$( EulerAngle , 2 )
Ink RGB(255,255,255),0
Text ObserverX + 30 , ObserverY - 30 , "Local: " + Str$( LocalAngle , 2 )
Line ObserverX , ObserverY , ObserverX + Sin(ObserverYRot) * 20.0 , ObserverY + Cos(ObserverYRot) * 20.0
Line ObserverX , ObserverY , ObserverX + Sin(EulerAngle) * 20.0 , ObserverY + Cos(EulerAngle) * 20.0
Sync
Loop
This is the same code but showing how you'd implement a missile, or something that follows a point with a limited turn speed:
Set Display Mode 800 , 600 , 32 , 0
Sync On
Sync Rate 100
ObserverX As Float
ObserverY As Float
ObserverYRot As Float
DistanceX As Float
DistanceY As Float
EulerAngle As Float
LocalAngle As Float
TurnRate As Float = 1.0
YRot As Float
Do
CLS
// Move observer around
ObserverX = ObserverX + Sin(ObserverYRot) * 3.0
ObserverY = ObserverY + Cos(ObserverYRot) * 3.0
// Draw observer and target
Ink RGB(55,55,155),0
Circle MouseX() , MouseY() , 5
Circle ObserverX , ObserverY , 10
// Position target(mouse)
DistanceX = MouseX() - ObserverX
DistanceY = MouseY() - ObserverY
// Find global angle between observer and target
EulerAngle = AtanFull( DistanceX , DistanceY )
// Subtract current angle to find local angle
LocalAngle = Wrapvalue( EulerAngle - ObserverYRot )
// Is the other way faster?
If LocalAngle > 180.0
LocalAngle = -(360.0 - LocalAngle)
Endif
YRot = LocalAngle
// Clamp rotational speed
If YRot > TurnRate Then YRot = TurnRate
If YRot < -TurnRate Then YRot = -TurnRate
ObserverYRot = Wrapvalue( ObserverYRot + YRot )
Ink RGB(100,100,100),0
Line ObserverX , ObserverY - 20 , ObserverX , ObserverY
Line ObserverX , ObserverY , MouseX() , MouseY()
Text ObserverX - 30 , ObserverY + 30 , "EulerY: " + Str$( EulerAngle , 2 )
Ink RGB(255,255,255),0
Text ObserverX + 30 , ObserverY - 30 , "Local: " + Str$( LocalAngle , 2 )
Line ObserverX , ObserverY , ObserverX + Sin(ObserverYRot) * 20.0 , ObserverY + Cos(ObserverYRot) * 20.0
Line ObserverX , ObserverY , ObserverX + Sin(EulerAngle) * 20.0 , ObserverY + Cos(EulerAngle) * 20.0
Sync
Loop
The angle between the grey lines is the Euler(global) angle between the observer(sphere) and the target(mouse), angle between the white lines is the local angle between the observer's direction to the target.