Can someone help with a math problem?

BlitzPlus Forums/BlitzPlus Programming/Can someone help with a math problem?

CloseToPerfect(Posted 2009) [#1]
I have a turret that rotates to face the mouse. This is simple enough if I want the turret to just face that direction atan2 will do that. But, what I want it to rotate it slowly.

I have a bit of code that works almost, haha. It will turn the turret CW or CCW depending on where the mouse is. The problem is when it crosses the 0 angle threshold.

Say for example the turret is at 5 degrees and the mouse is at 355 degrees. The turret will turn CW 350 degrees even though it is longer. CCW is only 10 degrees away.

I need a way to calculate the shortest route and move CW or CCW base on the answer.

I have tried several things and can't get it working right. I can't even work out in my mind what I need :(

Here is the base code.

;turn turrent
;find angle to turn to
calc = 360-ATan2(tankx- MouseX()  ,tanky-MouseY())
;set angle to 0 to 359
If calc>359 Then calc=calc-359
If calc<0 Then calc = 359+calc

;figure out if turn CW or CCW, which is closer
;turrentangle compared to calc


;turn CW
If calc > turrentangle Then 
	turrentangle = turrentangle + turrentspeed
;turn CCW	
ElseIf calc < turrentangle Then
	turrentangle = turrentangle - turrentspeed
EndIf


Thanks for any insight you can give.
CTP


CloseToPerfect(Posted 2009) [#2]
sorry guys, I worked it out.


;turn turrent
;find angle to turn to
calc = 360-ATan2(tankx- MouseX()  ,tanky-MouseY())
;set angle to 0 to 359
If calc>359 Then calc=calc-359
If calc<0 Then calc = 359+calc

;figure out if turn CW or CCW, which is closer
;turrentangle compared to calc
If calc<90 And turrentangle>270 Then 
	turrentangle = turrentangle + turrentspeed
ElseIf calc>270 And turrentangle<90 Then 
	turrentangle = turrentangle - turrentspeed
	;turn CW
ElseIf calc > turrentangle Then 
	turrentangle = turrentangle + turrentspeed
	;turn CCW	
ElseIf calc < turrentangle Then
	turrentangle = turrentangle - turrentspeed
EndIf


Please if anyone knows a easier way to do this plase tell me. I had to make to more conditional statements to handle it. Seems like there should be a simple math function to tell this but maybe not.


Warpy(Posted 2009) [#3]
There's a much easier way to do it!

First of all, the arguments of atan2 should be dy,dx, not dx,dy like you've got it. I haven't got blitzplus though, so maybe it's different.

Anyway, so you take work out your angle calc, which is where you want to point to, and you subtract turretangle from it to get 'anglediff'. You've got a few possibilities for what anglediff can be:

a) If it's in the range -180 to +180, you can use it straight away. This range covers an entire rotation and is the smallest range to do so, so you want andiff to end up in this range.

b) If it's less than -360 or bigger than +360, you need to add or subtract multiples of 360 until you get in the range -360 to +360. You can do this very quickly with the Mod operation.

c) Now, if andiff is still less than -180, add 360, so -270 would become +90. And if it's bigger than +180, subtract 360.

d) So now andiff gives you the shortest angle to turn to face 'calc'. If andiff is positive, you need to turn clockwise, and if it's negative you need to turn anti-clockwise. So you can use Sgn(andiff) just to get the sign of andiff, and multiply that by 'turretspeed' to turn at a constant rate.

I know this all sounds complicated, but this is just my mathematical explanation for why this method is correct. You can implement it in 4 lines:

andiff = (calc - turretangle) mod 360
if andiff < -180 Then andiff = andiff + 360
if andiff > 180 Then andiff = andiff - 360
turretangle = turretangle + sgn(andiff) * turretspeed



CloseToPerfect(Posted 2009) [#4]
Your right about dy,dx but hacking around with it like i was I was only able to get it to work dx,dy? Maybe because I was adjustingit by 360?

Anyway I have bee trying to implement the method your have shared with me, thanks by the way, and I get a curious problem. with the mouse pointer straight up at angle 0 the calc returns 90.

;find angle to turn to
calc = ATan2(tanky#-MouseY(),tankx#-MouseX())

andiff = (calc-turretangle) Mod 360
If andiff < -180 Then andiff = andiff + 360
If andiff > 180 Then andiff = andiff - 360
turretangle = turretangle + Sgn(andiff) * turretspeed

;make sure turretangle to be in the range of 0 to 359
If turretangle < 0 Then turretangle = 359+turretangle
If turretangle > 359 Then turretangle = turretangle-359

;draw layered image
DrawImage tankGFX(angle),tankx#,tanky#
DrawImage turretGFX(turretAngle),tankx#,tanky#

;data check
Color 0,0,0
Text 50,10,calc
Text 50,20,andif
Text 50,30,turretangle
Text 50,40,angle
Text 50,50,tankx#
Text 50,60,tanky#


I have tried making dy,dx = mouse-tank and tank-mouse, but I again made it work by hacking around with it because I dont really understand it :( and by adding 270 to the point to angle it works

calc = 270+ATan2(tanky#-MouseY(),tankx#-MouseX())


I am assuming angle 0 points up is this a wrong assumption? Does angle 90 point up? and is that why I have to adjust it by 270?

CTP


Floyd(Posted 2009) [#5]
You can find a description of the angle system here.

This was written for Blitz3D, hence the confusing reference to the y-axis pointing up in the 3d world.


GfK(Posted 2009) [#6]
Just a quick note which doesn't greatly help. Instead of:
If turretangle < 0 Then turretangle = 359+turretangle
If turretangle > 359 Then turretangle = turretangle-359
You can just use:
turretangle = turretangle Mod 360



CloseToPerfect(Posted 2009) [#7]
Thanks for the tip Gfk, Mod is another command I don't fully understand. Will have to play with it and check out how it returns.