Jump to content
Sign in to follow this  
ArmAIIholic

BIS_fnc_findSafePos ?

Recommended Posts

--[sOLVED]-- :D

Simple and straight question - what does this function do if it doesn't find safePos?

Here is the copy of the code from BIS fnc help inside the game (click spoiler).

Bonus questions:

What is this configFile >> "CfgWorlds" >> worldName >> "Armory" >> "positionStart" ?

What is that position? (assuming I don't provide some default position?)

What is the blacklist?

Thanx in advance.

scriptName "Functions\misc\fn_findSafePos.sqf";
/*
File: findSafePos.sqf
Author: Joris-Jan van 't Land

Description:
Function to retrieve and dynamic position in the world according to several parameters.

Parameter(s):
_this select 0: center position (Array)
					Note: passing [] (empty Array), the world's safePositionAnchor entry will be used.
_this select 1: minimum distance from the center position (Number)
_this select 2: maximum distance from the center position (Number)
					Note: passing -1, the world's safePositionRadius entry will be used.
_this select 3: minimum distance from the nearest object (Number)
_this select 4: water mode (Number)
					0: cannot be in water
					1: can either be in water or not
					2: must be in water
_this select 5: maximum terrain gradient (average altitude difference in meters - Number)
_this select 6: shore mode (Number):
					0: does not have to be at a shore
					1: must be at a shore
_this select 7: (optional) blacklist (Array of Arrays):
					(_this select 7) select X: Top-left and bottom-right coordinates of blacklisted area (Array)
_this select 8: (optional) default positions (Array of Arrays):
					(_this select 8) select 0: default position on land (Array)
					(_this select 8) select 1: default position on water (Array)

Returns:
Coordinate array with a position solution.

TODO:
* Maybe allow passing several combinations of position, min and max dist ... so that you can 
avoid several things?
* Interpretation of minDist / maxDist is wrong. It's not true distance that is used. Too bad?
*/

scopeName "main";

private ["_pos", "_minDist", "_maxDist", "_objDist", "_waterMode", "_maxGradient", "_shoreMode", "_defaultPos", "_blacklist"];
_pos = _this select 0;
_minDist = _this select 1;
_maxDist = _this select 2;
_objDist = _this select 3;
_waterMode = _this select 4;
_maxGradient = _this select 5;
_shoreMode = _this select 6;

if (_shoreMode == 0) then {_shoreMode = false} else {_shoreMode = true};

_blacklist = [];
if ((count _this) > 7) then 
{
_blacklist = _this select 7;
};

_defaultPos = [];
if ((count _this) > 8) then 
{
_defaultPos = _this select 8;
};

//See if default world values should be used.
if ((count _pos) == 0) then 
{
_pos = getArray(configFile >> "CfgWorlds" >> worldName >> "safePositionAnchor");
};
if ((count _pos) == 0) exitWith {debugLog "Log: [findSafePos] No center position was passed!"; []}; //TODO: instead return defaults below.

if (_maxDist == -1) then 
{
_maxDist = getNumber(configFile >> "CfgWorlds" >> worldName >> "safePositionRadius");
};

//TODO: Validate parameters.

private ["_newPos", "_posX", "_posY"];
_newPos = [];
_posX = _pos select 0;
_posY = _pos select 1;


//Limit the amount of attempts at finding a good location.
private ["_attempts"];
_attempts = 0;
while {_attempts < 1000} do
{
private ["_newX", "_newY", "_testPos"];
_newX = _posX + (_maxDist - (random (_maxDist * 2)));
_newY = _posY + (_maxDist - (random (_maxDist * 2)));
_testPos = [_newX, _newY];

//Blacklist check.
//TODO: Do not use function when the blacklist is empty?
if (!([_testPos, _blacklist] call BIS_fnc_isPosBlacklisted)) then
{
		if ((_pos distance _testPos) >= _minDist) then
		{
			if (!((count (_testPos isFlatEmpty [_objDist, 0, _maxGradient, _objDist max 5, _waterMode, _shoreMode, objNull])) == 0)) then 
			{
				_newPos = _testPos;
				breakTo "main";
			};
		};
};

_attempts = _attempts + 1;
};

//No position was found, use defaults.
if ((count _newPos) == 0) then
{
if (_waterMode == 0) then
{
	if ((count _defaultPos) > 0) then 
	{
		_newPos = _defaultPos select 0;
	} 
	else 
	{
		//Use world Armory default position:
		_newPos = getArray(configFile >> "CfgWorlds" >> worldName >> "Armory" >> "positionStart");
	};
}
else
{
	if ((count _defaultPos) > 1) then 
	{
		_newPos = _defaultPos select 1;
	} 
	else 
	{
		//Use world Armory default water position:
		_newPos = getArray(configFile >> "CfgWorlds" >> worldName >> "Armory" >> "positionStartWater");
	};
};
};

if ((count _newPos) == 0) then 
{
//Still nothing was found, use world center positions.
_newPos = getArray(configFile >> "CfgWorlds" >> worldName >> "centerPosition");
};

_newPos

--EDIT--

I found something very interesting about BIS location functions. There is also something about findSafePos...

Trexian:

Yeah, I've started using that findSafePos function to find spawn locations.

That config line basically finds the entry "safeAnchorPosition" (pretty obvious). My understanding of that is that it is more or less the center of the map, or maybe the middle of the land mass for the map.

I think the function just uses that as a starting point if no other point is passed to it.

I'm trying to sort out the max gradient element, myself. Otherwise, it is a pretty helpful function.

[...]

I found this line in the taskpatrol function with the gradient element defined and have been using it with no problems.

[...]

Ah right - I remember seeing that, but it didn't click that it was a conversion from 60 degrees to radians: 60 * (pi / 180).

Edited by ArmAIIholic

Share this post


Link to post
Share on other sites

It uses the position of the "Armoury". If that isn't here it uses the centerPosition, which os roughly the center of the "island".

configFile >> "CfgWorlds" >> worldName >> "Armory" >> "positionStart" is probably the position that is defined as the start position if you run the Armoury from inside the game.

The blacklist seems to be coordinates which form a rectangle that defines an area you do not wish to get a position from.

Edited by Muzzleflash

Share this post


Link to post
Share on other sites

Ok, thanx man. I though it is something like that. And the Trexian quote indicates that as well.

I was wondering if it starts from the center of the island does it have "tendency" to search toward position that user originally specified, if you understand what I mean.

It wouldn't be useful to place unit or waypoint near the center of the island just for a sake of placing it.... I think it would be completely useless.

However, this is just "philosophically" because I don't know the facts, I am trying to think like a programmer that made it -- why not returning just false value if there is no such point instead of finding point in the middle of nowhere?

On the other hand, searching the whole island for such point would take huge amount of CPU time... There must be a "purpose", "meaning" etc.

These are my thoughts...

Share this post


Link to post
Share on other sites
I was wondering if it starts from the center of the island does it have "tendency" to search toward position that user originally specified, if you understand what I mean.

It doesn't start searching from the center unless you don't pass it a position to go from. It starts from the point you give it, then it finds a position in a square with the "radius" of the maxDist. If the position is farther away than minDist and some other checks pass (eg. blackbox, water......) it found a position. Actually it appears in can find a position in the corner of that square where the distance is larger than maxdist.

If it doesn't find a position, it reverts to the default passed positions. If those don't work it checks if the map has a Armory position. If it doesn't then it uses the maps centerPosition.

It wouldn't be useful to place unit or waypoint near the center of the island just for a sake of placing it.... I think it would be completely useless.

I agree with you; I think

However, this is just "philosophically" because I don't know the facts, I am trying to think like a programmer that made it -- why not returning just false value if there is no such point instead of finding point in the middle of nowhere?

I agree; I think it's better to return false or something like that to indicate no desired position was found. Then the calling script can decide what to do.

On the other hand, searching the whole island for such point would take huge amount of CPU time... There must be a "purpose", "meaning" etc.

I'm not sure where you are going here?

This script itself is not very cpu-intensive; it makes a maximum of 1000 point checks with a square and some rectangles that blacklist and a few checks.

Share this post


Link to post
Share on other sites

Thanx it's clear now. I found part where it says how the script picks new point in every attempt. Since there is the finite number of attempts I guess it's not CPU-intensive.

That's because sampling area depends on max distance.

And it is very interesting for next dilemma: is it better to set large or small maximum distance - because new point is at (random (_maxDist * 2)). That actually means large sampling zone, but lower "density of samples". The probability for skipping the important point is higher.

P.S. I want to fully understand the process, before doing something. My brain is always on the run.

Share this post


Link to post
Share on other sites

Yes I can see the dilemma too. However, I think that in most cases it will not be a problem and a valid position will be found, assuming you give it some reasonable parameters. The terrain in Arma is quite open; I think the chance of it not finding an important position is very small.

There's no doubt that if you or I were to make this script it would most likely end up different than this (i'm not saying this is bad).

One way you could compensate is: say you want to a check roughly for every 20m^2. Then you just make that number of attempts. Eg. for a circle you just calculate the area first. Then you get the number of attempts:

_attempts = ceil (_area / 20);

For a 100m radius circle this would be roughly 1500 attempts. You'll still want to make it random since else the spawning would always be the exact same spot. A good idea in this example might actually be, to not use equal distribution since you get more positions in the center.

Share this post


Link to post
Share on other sites

hehe

I found the best way is just to experiment with it in any particular mission, until you get the results you want. :) There have been times when I've abandoned the findSafePos because it doesn't give me good results. Other times, it does exactly what I want.

I have also experimented with the config areas for openAreas (can't quite remember exactly). That'll be areas defined in the config as relatively free from obstructions. That can be helpful sometimes. Alot depends on what exactly you are trying to accomplish. Spawning soldiers is easier than spawning tanks. :)

Share this post


Link to post
Share on other sites
Spawning soldiers is easier than spawning tanks. :)

That's why I won't search for safe pos for soldiers, but for tanks I will have "backup" pos, something like camp / base. Thanx.

Muzzleflash thanx for keeping my brain wheels turning :D

Share this post


Link to post
Share on other sites

uhm, guys... isFlatEmpty exists. Use it and don't miss the precizePos parameter. Also selectBestPlaces comes in handy every now and then.

Sure, there are some minor problems with these commands (such as ponds, which aren't seen as water) but these are really some lovely/expressive commands to retrieve a position that matches your demands.

Share this post


Link to post
Share on other sites

Thanx ruebe for help. After studying these functions, I've chosen findSafePos for several reasons:

1) My spawning script already searches for position that is not in water and this way I can double check water and ponds when searching.

2) I don't have to check the output therefore I can put default spawning location = base, so if there is no safe position vehicles will spawn at the base which will be near the road, so they are ready to travel long distances (if needed of course).

I got it working, so basically this question (above) / thread is solved.

Thank you all

Edited by ArmAIIholic

Share this post


Link to post
Share on other sites

I found on my skin what does it mean

_this select 8: (optional) default positions (Array of Arrays):
					(_this select 8) select 0: default position on land (Array)
					(_this select 8) select 1: default position on water (Array)

(Array of Arrays) :yay:

I was trying to find suitable ground location for spawning with safe position already know, but I didn't put [_safepos] which lead to an error and stopped the script.

_groundloc = getMarkerPos "some_point";

_safepos = getMarkerPos "some_point";

_groundloc = [_groundloc,0,15,10,0,50*(pi/180),0,[],[_safepos]] call BIS_fnc_findSafePos;

Now I know that it IS an array in array :yay:

Share this post


Link to post
Share on other sites

Anyone noticed that BIS_fnc_findSafePos often returns the centre of the map? I've got it happening once every 10 or so uses, haven't worked out what is causing it.

Share this post


Link to post
Share on other sites

I didn't find any problems with my scripts and WICT. It is always spawning where it suppose to, I didn't even find that it is using info from array [_safepos].

The BIS_fnc_findSafePos is suppose to use the center of the map if it fails with everything else.

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×