Limit rotational direction
BlitzMax Forums/BlitzMax Programming/Limit rotational direction
| ||
Right, i have three varibles ...Speed:Float 'Speed to change directions at (could be anything) Current:Float 'Current direction (0 to 360) Wanted:Float 'Wanted direction (0 to 360) After a little bit of code, i have worked out this varibles value... iTurnDir:Int '=-1 anti-clockwise, 0 = no turn needed, 1 = clockwise What i want to do is add the speed to the current direction (or subtract, depending on iTurnDir) to make it reach the wanted direction. Now my question is, does anyone have a efficent and elegent solution to limit the current direction to the wanted direction with out over stepping it? Say for example, the solution needs to be able to deal with; 1. speed=10 current=10 wanted=200 iTurnDir=1 <- current will = 20 2. speed=100 current=300 wanted=10 iTurnDir=1 <- current will = wanted 3. speed=100 current=10 wanted=300 iTurnDir=-1 <- current will = wanted Now lets see what you lot can come up with :) |
| ||
| Any good? |
| ||
I remember writing something like this, it was surprisingly difficult. I was making a tank turret rotate towards the target by the closest method possible - this is the code, you can adapt it. Trust me, it takes ages to work this crap out - at least for someone as much of an amateur as myself. I hope people aren't about to ridicule me - I don't want them to look bad :PFunction matchAngle(c:craftController, TargetAngle#) c.c.rot = hMath.fixAngle(c.c.rot) 'Makes angle between 0 and 360 TargetAngle = hMath.fixAngle(TargetAngle) 'Makes angle between 0 and 360 'Rotates Ship Quickest Way to Appropriate Angle 'c.c is the ship 'c.c.rot = the ships current rotation 'c.turning is its intention to turn in a positive or negative direction If c.c.rot <> TargetAngle Then If Abs(c.c.rot - TargetAngle) < Abs(c.c.rotSpeed * .5 * DeltaT) Then c.c.rotSpeed = c.c.rotSpeed * .5 Else If c.c.rot - TargetAngle > 180 Then c.turning = 1 Else If TargetAngle - c.c.rot > 180 Then c.turning = -1 Else If c.c.rot > TargetAngle Then c.turning = -1 End If If c.c.rot < TargetAngle Then c.turning = 1 End If End If End If End If End If End Function |
| ||
Tom, yours brakes with ...Local angle# = 300 Local target# = 10 Local speed# = 60 Will, thats almost there, done that part myself. Thats how to calculate the "iTurnDir" value. Alos an aid when adding it to current direction as you can see.
Strict
Rem
'0 to 360
Local fRotation_Wanted:Float=90.0
Local fRotation_Current:Float=0.0
Local fRotation_Speed:Float=10.0
'Decide on direction from current to wanted
Local iTurnDir:Int=0 'Presume no direction is needed
If fRotation_Current<>fRotation_Wanted 'Is a direction needed?
'Need to rotate it towards
If fRotation_Current>180
'Upper half
If fRotation_Wanted>=(fRotation_Current-180) And (fRotation_Wanted<fRotation_Current)
'Wanted direction is lower!
iTurnDir=-1
Else
'Wanted direction must be higher (cause its not lower!)
iTurnDir=1
EndIf
Else
'Lower half
If (fRotation_Wanted>=fRotation_Current) And fRotation_Wanted<(fRotation_Current+180)
'Wanted direction is higher
iTurnDir=1
Else
'Wanted direction must be lower (cause its not higher)
iTurnDir=-1
EndIf
EndIf
EndIf
'Add in the rotation towards wanted
fRotation_Current = fRotation_Current + (Float(iTurnDir)*fRotation_Speed)
'Limit current to 0 to 360
fRotation_Current = fRotation_Current Mod 360.0
If fRotation_Current < 0 Then fRotation_Current :+360
'*** now check to see if we didt overstep wanted ***
Im just after a smart solution to the limit part of the problem! |
| ||
Well i think i have solved it myself ...
Strict
'0 to 360
Global fRotation_Current:Float
Global fRotation_Wanted:Float
Global fRotation_Speed:Float
'Force overstep into wrap around
fRotation_Current:Float=330.0
fRotation_Wanted:Float=310.0
fRotation_Speed:Float=7.0
Global iTurnDir:Int
'Testcode
Print " "
Print ">. "+fRotation_Current+" -> "+fRotation_Wanted
Local iCount:Int=0
While (fRotation_Current<>fRotation_Wanted) And (iCount<100)
CalcDir()
AddAndLimit()
iCount:+1
Print iCount+". "+fRotation_Current+" -> "+fRotation_Wanted+" "+iTurnDir
Wend
'Decide on direction from current to wanted
Function CalcDir()
iTurnDir:Int=0 'Presume its no direction
If fRotation_Current<>fRotation_Wanted 'Is a direction needed?
'Need to rotate it towards
If fRotation_Current>180
'Upper half
If fRotation_Wanted>=(fRotation_Current-180) And (fRotation_Wanted<fRotation_Current)
'Wanted direction is lower!
iTurnDir=-1
Else
'Wanted direction must be higher (cause its not lower!)
iTurnDir=1
EndIf
Else
'Lower half
If (fRotation_Wanted>=fRotation_Current) And fRotation_Wanted<(fRotation_Current+180)
'Wanted direction is higher
iTurnDir=1
Else
'Wanted direction must be lower (cause its not higher)
iTurnDir=-1
EndIf
EndIf
EndIf
End Function
Function AddAndLimit()
If fRotation_Current<>fRotation_Wanted
'Movement needed ...
If iTurnDir=1
'Clockwise
fRotation_Current = fRotation_Current + fRotation_Speed
If fRotation_Wanted<180.0 And fRotation_Current>180.0
'Unwrap the 360 limit
If fRotation_Current>=(fRotation_Wanted+360.0) Then fRotation_Current=(fRotation_Wanted+360.0)
Else
'Simple as its in range
If fRotation_Current>=fRotation_Wanted Then fRotation_Current=fRotation_Wanted
EndIf
Else
'Anti-clockwise
fRotation_Current = fRotation_Current - fRotation_Speed
If fRotation_Wanted>180.0 And fRotation_Current<180.0
'Unwrap the 360 limit
If fRotation_Current<=(fRotation_Wanted-360.0) Then fRotation_Current=(fRotation_Wanted-360.0)
Else
'Simple as its in range
If fRotation_Current<=fRotation_Wanted Then fRotation_Current=fRotation_Wanted
EndIf
EndIf
'Limit current to 0 to 360
fRotation_Current = fRotation_Current Mod 360.0
If fRotation_Current < 0 Then fRotation_Current :+360
EndIf
End Function
Posted the code, so that i might be usefull to others ... |
| ||
| Well upon further investigation, the code i posted above does not do whats required. However, i have another idea to pull off what i want.. stay tuned! |
| ||
Well i have sorted it this time ...
Strict
'0 to 360
Global fRotation_Current:Float
Global fRotation_Wanted:Float
Global fRotation_Speed:Float
'Force overstep into wrap around
fRotation_Current:Float=10.0
fRotation_Wanted:Float=300.0
fRotation_Speed:Float=15.0
Global iTurnDir:Int
Global fTurnAngle:Float
'Testcode
Print " "
Print ">. "+fRotation_Current+" -> "+fRotation_Wanted
Local iCount:Int=0
While (fRotation_Current<>fRotation_Wanted) And (iCount<100)
CalcDir()
iCount:+1
Print iCount+". "+fRotation_Current+" -> "+fRotation_Wanted+" "+iTurnDir
Wend
'Decide on direction from current to wanted
Function CalcDir()
iTurnDir:Int=0 'Presume its no direction
If fRotation_Current<>fRotation_Wanted 'Is a direction needed?
'Need to rotate it towards
If fRotation_Current>180
'Upper half
If fRotation_Wanted>=(fRotation_Current-180) And (fRotation_Wanted<fRotation_Current)
'Wanted direction is lower!
iTurnDir=-1
Else
'Wanted direction must be higher (cause its not lower!)
iTurnDir=1
EndIf
Else
'Lower half
If (fRotation_Wanted>=fRotation_Current) And fRotation_Wanted<(fRotation_Current+180)
'Wanted direction is higher
iTurnDir=1
Else
'Wanted direction must be lower (cause its not higher)
iTurnDir=-1
EndIf
EndIf
EndIf
Local fTurnSpeed:Float = fRotation_Speed
If iTurnDir<>0
'Calculate how many angles inbetween
fTurnAngle=Abs(fRotation_Wanted-fRotation_Current)
If fTurnAngle>180.0
'Need to correct it
fTurnAngle:-180 'Put it into the correct half
fTurnAngle=180-fTurnAngle 'Invert it
EndIf
'Limit turning speed to no bigger then the angle we need to go
If fTurnSpeed>fTurnAngle Then fTurnSpeed=fTurnAngle
EndIf
'Rotate it
fRotation_Current = fRotation_Current + (fTurnSpeed * Float(iTurnDir))
'Limit current to 0 to 360
fRotation_Current = fRotation_Current Mod 360.0
If fRotation_Current < 0 Then fRotation_Current :+360
End Function
There must be a million different ways to do this! |
| ||
| Sorry to drudge up this old thread, I recently ran into this issue and thought i would post the solution I found for those in the future. direction :+ sgn(direction-(sgn(direction-target)*180)-target)*1 direction is the current angle and target is the desired angle. the *1 at the end is the stepping value. (I found this code on the net but alas i cant remember where to give credit) |