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) |