OFPEC Forum

Editors Depot - Mission Editing and Scripting => OFP - Editing/Scripting General => Topic started by: Blanco on 10 Jun 2005, 02:45:47

Title: Find the shortest way...
Post by: Blanco on 10 Jun 2005, 02:45:47
Hello,

I hope I can explain this....

I have a script to make a object turn (via setdir) in a random direction between a maximum left & right arc.
Suppose my object's direction is 313 and the max step is 80 degrees, than the object can turn between  azimuth 33 & 233...

Because :
1)
313 - 80 = 233
2)
313 + 80 = 393, but I have to correct this so the result stay between 360 degrees. So 393 -360 = 33

So far so good, that works fine.
The problem is when the old heading is below 360 degrees and the new heading is above 360 degrees, the object turns counterclockwise, but the shortest way is clockwise.
How can I calculate this so the object always takes the shortest turn to get there?

Code: [Select]
_mg = _this select 0
_mainhdg = getdir _mg


_step = 80

;calculate the random heading the first time
_newhdg = (_mainhdg + ((random _step) - (random _step)))
? _newhdg < 0: _newhdg = _newhdg + 360
? _newhdg > 360: _newhdg = _newhdg - 360


#searchloop
? (getdir _mg - _newhdg) < 10 and (getdir _mg - _newhdg) > - 10: goto "pauze"
? (getdir _mg - _newhdg) > 0: _mg setdir ((getdir _mg) - 1)
? (getdir _mg - _newhdg) < 0: _mg setdir ((getdir _mg) + 1)

player globalchat format ["MH=%1   NH =%2  DIR= %3",_mainhdg,_newhdg,getdir _mg]
~0.09
goto "searchloop"

#pauze
_newhdg = (_mainhdg + ((random _step) - (random _step)))
?_newhdg > 360 : _newhdg = _newhdg - 360
?_newhdg < 0 : _newhdg = _newhdg + 360
~2 + random 2
goto "searchloop"

Actually, I think this is a shitty code, I'm sure this can be done easier, but I'm bad with math... :-\
Please help me out.


Title: Re:Find the shortest way...
Post by: Fragorl on 10 Jun 2005, 12:21:24
Blast... I got around this exact problem a while back, can't think what i did with the code... I'll have a think and see if i can remember what i did. It wasnt over difficult at any rate.
Title: Re:Find the shortest way...
Post by: THobson on 10 Jun 2005, 12:31:04
try something like this (note: I have made up the names of some variables and see that I have used _step and so have you but for something else):



Code: [Select]
_change = _newDir - _oldDir

if (abs(_change) > (abs (_change + 360) % 360)) then {_change = (_change + 360) % 360}

_step = _change/abs(_change)


#loop

_mg setDir ((getDir _mg) + _step)

if (abs((getDir _mg) - _newDir) > abs(_step)) then {goto"loop"}

exit



EDIT:

Instead of the loop you could use a while:


Code: [Select]
_change = _newDir - _oldDir

if (abs(_change) > (abs (_change + 360) % 360)) then {_change = (_change + 360) % 360}

_step = _change/abs(_change)


while {abs((getDir _mg) - _newDir) > abs(_step)} do {_mg setDir ((getDir _mg) + _step)}

exit

Title: Re:Find the shortest way...
Post by: Fragorl on 10 Jun 2005, 13:25:09
Yes, I think THobson has got it there. Abs and the modulus stir vague memories...

This topic reminds me of a function I've been meaning to submit, ClockwiseOf.sqf (http://www.ofpec.com/editors/funcref.php?letter=C#ClockwiseOf). It doesn't seem directly applicable to your situation, but then again it's sort of related. Anyhow, it's in the funcs depot now.

And completely unrelated to this topic, i just found out that in a script, any variables you initialise within the curly braces of an 'if... then {}' clause (or a while, or anything else) are local to that clause only. I know that this is how it works in java, but it's interesting to see that it happens in FP script too. For example, try this:

if (true) then {myVar = 5; hint format["%1",myVar];}
~1
hint format["%1",myVar]

Title: Re:Find the shortest way...
Post by: Mr.Peanut on 10 Jun 2005, 13:38:13
Um... correct me if I'm wrong but that snippet by THobson always returns a positive value for _step.
Title: Re:Find the shortest way...
Post by: THobson on 10 Jun 2005, 13:47:15
Peanut - it shouldn't

Try putting

_newDir = 5
_oldDir = 10

_change = -5

5 is < 355 so _change stays as -5

-5/(abs(-5))  = -1
 
Title: Re:Find the shortest way...
Post by: Mr.Peanut on 10 Jun 2005, 13:58:22
Okay, I was wrong about that, but try

_newDir = 340
_oldDir = 10


_change = 330

_step = 1,

which is the wrong way.




Title: Re:Find the shortest way...
Post by: Mr.Peanut on 10 Jun 2005, 14:22:58
Blanco: here's my own crappy, inelegant code:

Code: [Select]
_mg = _this select 0
_mainhdg = getdir _mg

;search parameters
_step = 80
_twostep = _step * 2
_tol = 10
_inc = 1

;calculate the random heading the first time
_newhdg = (_mainhdg + _step - (random _twostep))
;convert heading to 0-360
_newhdg = (_newhdg mod 360)
? _newhdg < 0:_newhdg = _newhdg + 360

#searchloop
_mgdir = getdir _mg
? (abs(_mgdir - _newhdg) < _tol): goto "pauze"
if (_mgdir > _newhdg) then {goto "skip1"}
_rturn = _mgdir - newhdg
_lturn = (_mgdir + 360) - _newhdg
goto "skip2"
#skip1
_rturn = (_newhdg + 360) - _mgdir
_lturn = _newhdg - _mgdir
#skip2
if (abs(_lturn) < abs(_rturn)) then {_mgdir = _mgdir - _inc} else {_mgdir = _mgdir + _inc}
;convert heading to 0-360
_mgdir = (_mgdir mod 360)
? _mgdir < 0:_mgdir = _mgdir + 360
;done
_obj setdir _mgdir
player globalchat format ["MH=%1  NH =%2  DIR= %3",_mainhdg,_newhdg,getdir _obj]
~0.09
goto "searchloop"

#pauze
_newhdg = (_mainhdg + _step - (random _twostep))
_newhdg = (_newhdg mod 360)
?_newhdg < 0:_newhdg = _newhdg + 360
~2 + random 2
goto "searchloop"
Title: Re:Find the shortest way...
Post by: Mr.Peanut on 10 Jun 2005, 14:24:35
So Fragorl,

As long as you declare the variable first, then you are safe?
i.e.:

myVar = 0
if (true) then {myVar = 5; hint format["%1",myVar];}
~1
hint format["%1",myVar]



if (true) then {myVar = 5; hint format["%1",myVar];}
~1
hint format["%1",myVar]
Title: Re:Find the shortest way...
Post by: Blanco on 10 Jun 2005, 14:25:36
Thx, it seems to work but I have to use the loop method because I need the delay and don't know how I can implement that delay in the while-do thingy. (it's chinese 4 me)

I need it for a scripted searchlight script (based on Mgspot.sqs from Sui) using the light of a machinegun. When the player runs through the lightbeam, the gunner sounds the alarm and try to kill you. Once spotted, the light follows whereever you go.
Not really fullproof because it still follows you when you hide behind an obstacle or when you are far away,... I need a LOS script for that.  :-\
I have an idea to solve this without a LOS script, but it requires lots of testing.

Thx alot all of you.


 

Title: Re:Find the shortest way...
Post by: THobson on 10 Jun 2005, 17:33:53
Well spotted Mr. Peanut.  That will teach me not to just dash off a script.  Here is a better version:

Code: [Select]
_change = _newDir - _oldDir

if (abs(_change) > (abs (_change + 360) % 360)) then {_change = (_change + 360) % 360}
if (_change > 180) then {_change = _change - 360}
if (_change < -180) then {_change = _change + 360}

_step = _change/abs(_change)


#loop

_mg setDir ((getDir _mg) + _step)

if (abs((getDir _mg) - _newDir) > abs(_step)) then {goto"loop"}

exit



Title: Re:Find the shortest way...
Post by: Fragorl on 11 Jun 2005, 00:44:52
So Fragorl,

As long as you declare the variable first, then you are safe?
i.e.:

myVar = 0
if (true) then {myVar = 5; hint format["%1",myVar];}
~1
hint format["%1",myVar]

Exactly. In that situation, you are safe. For both hints, you get out the value '5'. This works identically to java, and is a sensible way to do it when you think about it.

I will make a note in the command reference.
Title: Re:Find the shortest way...
Post by: THobson on 11 Jun 2005, 08:46:06
A good additon to the knowledge base.  I don't know java, but I had come across what I then saw as the problem of not being able to initialise a new variable in an if statement.  I had not realised the variable was being created, but only with a very limited scope.  I just knew that it didn't exist after the statement so I now intialise them before the if statement, which often has a side effect of not requiring an else caluse.  What I started writing as:

if (condition) then {_var = a} else {_var = b}

I now write as:

_var = b
if (condition) then {_var = a}