Jump to content
Ibragim A

The principle of the traveling salesman problem for path calculating

Recommended Posts

Hi, I hope that someone can tell me some concept with which it will be possible to calculate the path from one point to another bypassing enemies.

Generally speaking, the task is to calculate the path so that it passes along points that are distant from the enemy at a certain distance.

Can I use markers or triggers for this as zones that the calculating needs to bypass?

Can the principle of the traveling salesman problem be used and how?

Is there a command that forces the group to keep a certain distance from the enemy or objects?

 

What solution would you suggest?

 

p.png?fv_content=true&size_mode=5

Share this post


Link to post
Share on other sites

The question is what you really want to do...

If you want to bypass an enemy then give your unit a waypoint which is distant to that enemy and let it go.

 

If you need a path for some reason then use 

calculatePath

You can try that command directly from unit to goal using STEALTH behaviour as parameter.

But you could also do 2 calculations. First from unit to a enemy-distant-point and second from that point to the goal...

 

Idk if that helps cause u did not really tell what u want to do!

 

Edit: Also, if you have mission editing questions, then post it in arma-3-mission-editing-scripting section of the forum next time, pls.

Edited by sarogahtyp

Share this post


Link to post
Share on other sites
25 minutes ago, sarogahtyp said:

The question is what you really want to do...

If you want to bypass an enemy then give your unit a waypoint which is distant to that enemy and let it go.

 

If you need a path for some reason then use 

calculatePath

You can try that command directly from unit to goal using STEALTH behaviour as parameter.

But you could also do 2 calculations. First from unit to a enemy-distant-point and second from that point to the goal...

 

Idk if that helps cause u did not really tell what u want to do!


Yes, I forgot to explain what it is for.

In short, I want to create a function that will calculate the path for the AI group from point A to point B bypassing all known enemies.

 

The path should be calculated automatically, not manually, when the player adds waypoints himself.

 

The player only sets the starting point (position of the AI group) and the finish point (to which the AI group moves).

 

The group's goal is to bypass all enemies on its way, within a radius of 200 meters as an example.

 

The calculation can also be by sectors, for example, the movement of a group can be from one sector, in which there is no enemy, to another, followed by a recalculation.

 

The main criterion for me is that the AI group calculates the path to the finish line between the opponents known to it at a given distance.

===

There is such command setConvoySeparation. It forces the cars in one convoy to keep at a certain distance. If there was a similar command for men, I would use it on the group leader and on the enemy, and the group leader would go around the enemy at a given distance. I hope I made you understand exactly what I mean.

Share this post


Link to post
Share on other sites

The simplest solution I have found is "the rule of the right hand".

 

But there are some rather difficult situations in which this rule does not work.
p.jpeg?fv_content=true&size_mode=5

Share this post


Link to post
Share on other sites

I m not aware of any command that would be really usefull for this.

 

This means if you want this then you need to script it completly except for the partial path calculation where you would use calculatePath as described in my last post.

Share this post


Link to post
Share on other sites
4 minutes ago, sarogahtyp said:

I m not aware of any command that would be really usefull for this.

 

This means if you want this then you need to script it completly except for the partial path calculation where you would use calculatePath as described in my last post.

Exactly, that's why I want someone to suggest some concept of calculation to me.

Share this post


Link to post
Share on other sites

p.png?fv_content=true&size_mode=5p.png?fv_content=true&size_mode=5

 

The calculation of the path using the calculatePath command takes into account buildings in the path of the unit.

On the screenshot you can see that there are two large factories on the way, and the path that has been entered goes around the first of them on the left, but he does not notice the second.

Is there any way to tweak this?

To solve my problem, it would be possible to create a huge invisible building at the coordinates of the enemy, which would be removed immediately after calculating the path, but only if the calculation function learns to take into account all buildings on the way.

 

Here is the script used in this test:

private _agent = createAgent [typeOf player, position player, [], 0, "NONE"]; 
private _car = "B_Quadbike_01_F" createVehicle position player; 
_agent moveInDriver _car; 
_agent addEventHandler ["PathCalculated", 
{  
 {  
  private _marker = createMarker ["marker" + str _forEachIndex, _x];  
  _marker setMarkerType "mil_dot";  
  //_marker setMarkerText str _forEachIndex;  
 }  
 forEach (_this select 1); 
}]; 
_agent setDestination [player getRelPos [300, 0], "LEADER PLANNED", true];

 

Share this post


Link to post
Share on other sites

p.png?fv_content=true&size_mode=5

 

The other code worked well and found a way around the two factories.

(calculatePath ["man","safe",position player,getMarkerPos "marker_13"]) addEventHandler ["PathCalculated", { 
 { 
  private _marker = createMarker ["marker" + str _forEachIndex, _x]; 
  _marker setMarkerType "mil_dot"; 
  //_marker setMarkerText str _forEachIndex; 
 } forEach (_this select 1); 
}];

 

Share this post


Link to post
Share on other sites

Is there a way to make the calculatePath command treat markers or triggers as buildings?

Share this post


Link to post
Share on other sites
20 hours ago, sarogahtyp said:

Also, if you have mission editing questions, then post it in arma-3-mission-editing-scripting section of the forum next time, pls.

 

This is good advice. You will receive more relevant views in the forum where the nifty-scripty types hang out.

 

You can report your own post (top right corner of your first post) with a message asking to move it to the correct forum.

  • Like 1

Share this post


Link to post
Share on other sites
1 minute ago, Harzach said:

 

This is good advice. You will receive more relevant views in the forum where the nifty-scripty types hang out.

 

You can report your own post (top right corner of your first post) with a message asking to move it to the correct forum.

Thank you, I will do it.

Share this post


Link to post
Share on other sites

So, I solved this problem and wrote out the script in a separate template for review. This script works like this:
The group goes from point A to point B and on the way bypasses those enemies whom it notices and who stand in its way.
Upon contact, the group leaves the enemy's zone and bypasses it along a shorter path.
If there are several enemies on the way of the group at once, the group bypasses them all in the most convenient way.
If Endpoint B is in the enemy's zone, the group looks for the nearest convenient place at a safe distance and stops at him.
p.png?fv_content=true&size_mode=5

 

Download template:
https://www.dropbox.com/s/db2udildg7lst2w/PC_TEST_RECON.Altis.zip?dl=0

 

Scripts:

1 - make file in your EDEN mission folder and name it for example sqripts_and_variables.sqf

Put in it this script:

// Icon:

group_2 addGroupIcon ["n_recon"];
setGroupIconsVisible [true,true];			
group_2 setGroupIconParams [[0,0.5,0,1], "Recon group", 1, true]; 

// AUTOCOMBAT:

{_x disableAI "AUTOCOMBAT"} forEach (units group_2);

// Variables:

PC_RECON_MOVING_DIST = 200;
PC_ENEMY_SIDE = "EAST";

// Scripts and Functions:

PC_fn_forget_all_targets = 
	{
		params ["_leader"];
		
		_targets = _leader targets [true, 500, [], 0];
			{ 
				group _leader forgetTarget _x; 
			} forEach _targets;
	};
	
PC_fn_recon_path_do_not_intersect_enemy_zones = 
	{
		params ["_start_pos", "_end_pos", "_radius", "_enemies"];
		
		_do_not_intersect = true;	
		
		if (count _enemies < 1) exitWith 
			{
				_do_not_intersect;				
			};
			
			{
				_enemy = _x;
				
				_nearest_position = [_start_pos, _end_pos, position _enemy, true] call BIS_fnc_nearestPoint;
				
				if (_nearest_position distance2D _enemy < _radius) then 
					{						
						if ((_start_pos distance2d _nearest_position) + (_end_pos distance2d _nearest_position) > (_start_pos distance2d _end_pos)+1) then 
							{
								switch (true) do
									{
										case (_start_pos distance2d _nearest_position < _radius): 	
											{ _do_not_intersect = false; };
										case (_end_pos distance2d _nearest_position < _radius): 	
											{ _do_not_intersect = false; };
									};
							} else 
								{
									_do_not_intersect = false; 
								};
					};				
			} forEach _enemies;
			
		_do_not_intersect;
	};
	
PC_direct_fn_allies_recon = 
	{
		params ["_group","_action_position"];
		
		private _leader = leader _group;
		private _name = format ["%1_PC_WP_NAME_recon_%2", _group, (count waypoints _group)];
				
		private _wp1 = group _leader addWaypoint [_action_position, 0, (count waypoints _leader) + 1];		
		_wp1 setWaypointName _name;
		_wp1 setWaypointType "SCRIPTED";
		
		_group setFormation "FILE";
		waitUntil {formation _group in ["FILE"]};
				
		_script = [_leader, _action_position] spawn PC_direct_fn_allies_are_reconing;
		
		private _wp1 = group _leader addWaypoint [_action_position, 0, (count waypoints _leader) + 1];		
		_wp1 setWaypointName _name;
		_wp1 setWaypointType "MOVE";
		//_wp1 setWaypointBehaviour "STEALTH"; 
		//_wp1 setWaypointForceBehaviour true;
		_wp1 setWaypointCombatMode "GREEN";
		_wp1 setWaypointFormation "DIAMOND";
		//_wp1 setWaypointSpeed "NORMAL";
		_wp1 setWaypointStatements ["true", "group this setVariable ['PC_AI_isReconing', false, true]; "];		
	};
	
PC_direct_fn_allies_are_reconing = 
	{
		params ["_recon","_action_position"];		
		
		_group = leader _recon;
		_merged_enemies_on_the_path = [];
		
		/// Подготовка отделения:
		
			{
				//_x setUnitPos "MIDDLE";
				//_x setBehaviour "STEALTH";
				_x setBehaviour "AWARE"; 
				_x setCombatMode "GREEN";
				_x setUnitTrait ["audibleCoef", (_x getUnitTrait "audibleCoef")/2];
				_x setUnitTrait ["camouflageCoef", (_x getUnitTrait "camouflageCoef")/2];
				_x disableAI "AUTOCOMBAT";
			} forEach units group _recon;

		group _recon setVariable ["PC_AI_isReconing", true, true];
		group _recon setVariable ["PC_AI_recon_at_his_last_temperary_point", false, true];
		group _recon setVariable ["PC_AI_recon_path", [], true]; 
		
		[_recon] call PC_fn_forget_all_targets;
		
		_goal_waypoint = []; 
						
			{
				if (
					(waypointPosition _x distance2d _action_position < 5)
					&&
					((waypointName _x) find "_recon_" != -1)
					) exitWith 
						{
							_goal_waypoint = _x;
						};
			} forEach waypoints (group _recon);
		
		/// Цикл разведки:
				
		while {group _recon getVariable "PC_AI_isReconing"} do /// Основной цикл разведки
			{				
				/// Фиксация известных группе врагов:
				
				_all_known_targets_before = _recon targets [true];
				
				_all_enemy_leaders = _all_known_targets_before apply { (leader group _x) };
				_all_enemy_leaders = _all_enemy_leaders arrayIntersect _all_enemy_leaders;
			
				/// Получение временных мар точек из переменной PC_AI_recon_path:
				
				if (count (group _recon getVariable ["PC_AI_recon_path", []]) > 0 ) then 
					{
						/// Есть обходной путь, ставим временные мар точки:					
							
						_goal_waypoint_index = _goal_waypoint select 1;

						_first_temporary_waypoint_index = 0;
						
						for "_i" from 0 to (count (group _recon getVariable ["PC_AI_recon_path", []]))-1 do 
							{
								_name = format ["%1_PC_WP_NAME_temporary_%2", _group, _i];
								
								_wp1 = group _recon addWaypoint [(group _recon getVariable ["PC_AI_recon_path", []]) select _i, 0, _goal_waypoint_index + 1 + _i];		
								_wp1 setWaypointName _name;
								_wp1 setWaypointType "MOVE";
								
								/// Получаем индекс первой временной точки:							
								
								if (_i == 0) then 
									{
										_first_temporary_waypoint_index = _goal_waypoint_index + 1; 
										group _recon setCurrentWaypoint [group _recon, _first_temporary_waypoint_index];										
									};
								
								/// Если это последняя временная точка:
								
								if (_i == (count (group _recon getVariable ["PC_AI_recon_path", []]))-1) then 
									{									
										_wp1 setWaypointStatements ["true", "(group this) setVariable ['PC_AI_recon_at_his_last_temperary_point', true, true]"];
										
										/// Если эта последняя временная точка должна стать завершением разведки:
										
										if !([_action_position, _action_position, PC_RECON_MOVING_DIST, _merged_enemies_on_the_path] call PC_fn_recon_path_do_not_intersect_enemy_zones) then 
											{												
												_wp1 setWaypointStatements ["true", "[(group this), (currentWaypoint (group this))+1] setWaypointPosition [position this, 0];"];
											};											
											
										/// После создания всех временных маршрутных точек переводим группу на первую временную точку:
										
										group _recon setCurrentWaypoint [group _recon, _first_temporary_waypoint_index];
									};
								/*	
								_marker = createMarker ["enemy_marker_" + (str time) + "_" + (str _i), (group _recon getVariable ["PC_AI_recon_path", []]) select _i];
								_marker setMarkerType "Contact_pencilCircle2";
								_marker setMarkerColor "ColorBlue";
								_marker setMarkerText format ["%1", _i + 1];*/
							};						
					};				
				
				/// Цикл ожидания для повтора вычисления пути или выхода из разведки:								
				
				waitUntil 
					{
						sleep 1;
						
						_recon = leader _group;
						
						/// Проверка, каких врагов группа видит:

						_all_targets = (nearestObjects [_recon, ["Land","Air"], 300]) select 
							{
								(alive _x) 
								&& 
								(side group _x isEqualTo PC_ENEMY_SIDE) 
								&& 
								([position _recon, getDir _recon, 180, position _x] call BIS_fnc_inAngleSector) 
								&& 
								(([objNull, "IFIRE"] checkVisibility [eyePos _recon, eyepos _x] > 0.0001))
							};
										
						if (count _all_targets > 0) then
							{
								{
									_target = _x;
									_recon reveal [_target, 2];
									leader group _recon reveal [_target, 2];								
								} forEach _all_targets;								
							};
						
						_all_known_targets = _recon targets [true];
						_all_enemy_leaders = [];
						
						if (count _all_known_targets > 0) then 
							{
								_all_enemy_leaders = _all_known_targets apply { (leader group _x) };								
								_all_enemy_leaders = _all_enemy_leaders arrayIntersect _all_enemy_leaders;
							};						
						
						/// Условия выхода из ожидания:
						 
						!(group _recon getVariable "PC_AI_isReconing") /// Группа отозвана или закончила разведку
						||
						(if (count _all_known_targets_before > 0) then {({if !(_x in _all_known_targets_before) exitWith {true}; false} forEach (_recon targets [true]))} else {if (count (_recon targets [true]) > 0) then {true} else {false}})   /// Появился новый враг
						||
						(group _recon getVariable ["PC_AI_recon_at_his_last_temperary_point", false]); /// Разведчики дошли до последней временной точки
					};
					
				/// Удаляем все маркеры старых маршрутов:
				
					{
						if ((_x find "enemy_marker_" != -1) || (_x find "goal_marker_" != -1)) then 
							{
								deleteMarker _x;
							};
					} forEach allMapMarkers;
					
				/// Если это обход противника, в зоне которого конечное назначение:
				
				if ((group _recon getVariable ["PC_AI_recon_at_his_last_temperary_point", false]) && (_recon distance2d (waypointPosition _goal_waypoint) < 10)) then 
					{
						group _recon setVariable ["PC_AI_isReconing", false, true]; 
					};
				
				/// Удаление временных маршрутных точек:
				
				_group_waypoints = waypoints group _recon;
				reverse _group_waypoints;
					{
						if (waypointName _x find "_temporary" != -1) then 
							{
								deleteWaypoint _x;
							};
					} forEach _group_waypoints;				
				
				group _recon setVariable ["PC_AI_recon_at_his_last_temperary_point", false, true];
				group _recon setVariable ["PC_AI_recon_path", [], true];			
				
				/// Если разведку отменили или разведка дошла до своей конечной цели:
				
				if !(group _recon getVariable "PC_AI_isReconing") exitWith 
					{
						/// Выход из разведки: 						
					};				

				/// Начинается проверка:				
				/// Определение врагов на глаз плюс всех известных до этого целей:				
				
				_all_targets = (nearestObjects [_recon, ["Land","Air"], 300]) select 
					{
						(alive _x) 
						&& 
						(side group _x isEqualTo PC_ENEMY_SIDE) 
						&& 
						([position _recon, getDir _recon, 180, position _x] call BIS_fnc_inAngleSector) 
						&& 
						(([objNull, "IFIRE"] checkVisibility [eyePos _recon, eyepos _x] > 0.0001))
					};
								
				if (count _all_targets > 0) then
					{
						{
							_target = _x;
							_recon reveal [_target, 2];
							leader group _recon reveal [_target, 2];								
						} forEach _all_targets;								
					};
				
				_all_known_targets = _recon targets [true];
				
				/// Если известны враги, находим путь для их обхода:
				
				if (count _all_known_targets > 0) then 
					{
						_all_enemy_leaders = _all_known_targets apply { (leader group _x) };
						
						_all_enemy_leaders = _all_enemy_leaders arrayIntersect _all_enemy_leaders;
						_all_enemy_leaders_and_distance = _all_enemy_leaders apply { [_x distance (leader group _recon), _x] };
						_all_enemy_leaders_and_distance sort true;
						_closest_enemy = _all_enemy_leaders_and_distance select 0 select 1;
								
						_recon_dir_to_end = _recon getDir _action_position;
						_recon_dir_to_closest_enemy = _recon getDir _closest_enemy;
						
						/// Проверяем, есть ли кто-то из этих врагов на пути группы:																		
								
						if ([position _recon, _action_position, PC_RECON_MOVING_DIST, _all_enemy_leaders] call PC_fn_recon_path_do_not_intersect_enemy_zones) exitWith 
							{
								/// Нет пересечения с опасными зонами. Повторение цикла:								
							};	
						
						/// Создаем массив с точками вокруг всех известных врагов.
						
						_all_positions_around_enemies_and_distance_to_recon = [];
						
							{
								_enemy_pos = (_x select 1);
								
								for "_i" from 0 to 7 do 
									{
										_pos = _enemy_pos getPos [PC_RECON_MOVING_DIST + (PC_RECON_MOVING_DIST/10), _recon_dir_to_end + (45*_i)];
										
										_all_positions_around_enemies_and_distance_to_recon = _all_positions_around_enemies_and_distance_to_recon + [[_recon distance2d _pos, _pos]];
									};
								
							} forEach _all_enemy_leaders_and_distance;
						
						/// Убираем из массива те точки, которые попадают в радиус других врагов:
						
						_merged_positions = [];
						
							{								
								_pos = (_x select 1);
								
								if ({if (_pos distance2d _x < PC_RECON_MOVING_DIST) exitWith {true}; false} forEach _all_enemy_leaders) then 
									{
										_merged_positions = _merged_positions + [_x];
									};
									
							} forEach _all_positions_around_enemies_and_distance_to_recon;
						
						_all_positions_around_enemies_and_distance_to_recon = _all_positions_around_enemies_and_distance_to_recon - _merged_positions;
												
						/// Вычисляем тех врагов, через которых проходит путь:
						
						_enemy_leaders_on_the_path = [];
						
							{
								if !([position _recon, _action_position, PC_RECON_MOVING_DIST, [_x]] call PC_fn_recon_path_do_not_intersect_enemy_zones) then 
									{
										_enemy_leaders_on_the_path = _enemy_leaders_on_the_path + [_x];
									};
							} forEach _all_enemy_leaders;
							
						/// Из них ближайший:
						
						_enemy_leaders_on_the_path_and_distance = _enemy_leaders_on_the_path apply {[_x distance2d _recon, _x]};
						_enemy_leaders_on_the_path_and_distance sort true;
						_closest_enemy_on_the_path = _enemy_leaders_on_the_path_and_distance select 0 select 1;
						
						/// Проверяем, кто из врагов приклеен зоной к первому врагу на пути:
						
						_merged_enemies_on_the_path = [_closest_enemy_on_the_path]; 
						
							{
								_leader = (_x select 1);
								
								if ({if (_leader distance2d _x < (PC_RECON_MOVING_DIST*2)) exitWith {true}; false} forEach _merged_enemies_on_the_path) then 
									{
										_merged_enemies_on_the_path = _merged_enemies_on_the_path + [_leader];
									};
									
								sleep 0.1;
								
							} forEach _all_enemy_leaders_and_distance;
						
						_merged_enemies_on_the_path = _merged_enemies_on_the_path arrayIntersect _merged_enemies_on_the_path;
						
						/// Удаляем те точки, которые не от этих врагов:
						
						_positions_not_merged = [];
						
							{
								_pos = (_x select 1);
								
								if ({if ((_pos distance2d _x) < (5 + PC_RECON_MOVING_DIST + (PC_RECON_MOVING_DIST/10))) exitWith {false}; true} forEach _merged_enemies_on_the_path) then 
									{
										_positions_not_merged = _positions_not_merged + [_x];
									};
							} forEach _all_positions_around_enemies_and_distance_to_recon;
						
						_all_positions_around_enemies_and_distance_to_recon = _all_positions_around_enemies_and_distance_to_recon - _positions_not_merged;
						
						///Тест: создаем маркеры:
						
							{
								_marker = createMarker ["enemy_marker_" + (str time) + (str _forEachIndex), (_x select 1)];
								_marker setMarkerType "mil_dot_noShadow";
								_marker setMarkerColor "ColorBlack";
								//_marker setMarkerAlpha 1;								
							} forEach _all_positions_around_enemies_and_distance_to_recon;
						
						sleep 0.001;
												
						
						/// Пересечение с опасными зонами. Определяем те точки, до которых группа дойдет не пересекая опасные сектора:
												
						_closest_point = [];
						_farest_point = [];
						
						if ({if (_recon distance2d _x < PC_RECON_MOVING_DIST + (PC_RECON_MOVING_DIST/10)) exitWith {true}; false} forEach _all_enemy_leaders) then 
							{
								/// Группа оказалась в опасном секторе. Отходит к ближайшей позиции за радиус опасного сектора:
								
								_all_positions_around_enemies_and_distance_to_recon sort true;
								
								_closest_point = _all_positions_around_enemies_and_distance_to_recon select 0 select 1;
								/*
								_marker = createMarker ["enemy_marker_" + (str time), _closest_point];
								_marker setMarkerType "mil_dot_noShadow";
								_marker setMarkerColor "ColorRed";*/
								
							} else 
								{
									/// Группа вне опасного сектора. Ищет наиболее дальнюю позицию от разведчика с учетом не пересечения опасных зон:
									
									_all_positions_around_enemies_and_distance_to_recon sort false;
									
										{
											_pos = (_x select 1);
														
											if ([position _recon, _pos, PC_RECON_MOVING_DIST, _all_enemy_leaders] call PC_fn_recon_path_do_not_intersect_enemy_zones) exitWith 
												{
													/// эта точка дальше всего от группы и не пересекает опасную зону:
													
													_farest_point = _pos;
													/*
													_marker = createMarker ["enemy_marker_" + (str time), _farest_point];
													_marker setMarkerType "mil_dot_noShadow";
													_marker setMarkerColor "ColorBlue";*/
												};								
								
										} forEach _all_positions_around_enemies_and_distance_to_recon;									
								};
						
						/// Проверка, не пройдет ли группа от ближайшей или наиболее дальней точки сразу к цели:
						
						switch (true) do
							{
								case (count _closest_point > 0): 
									{
										if ([_closest_point, _action_position, PC_RECON_MOVING_DIST, _all_enemy_leaders] call PC_fn_recon_path_do_not_intersect_enemy_zones) exitWith	
											{
												/// Нет пересечения с опасными зонами:
											
												group _recon setVariable ["PC_AI_recon_path", [_closest_point], true];												
											};	
									};
								case (count _farest_point > 0): 
									{										
										if ([_farest_point, _action_position, PC_RECON_MOVING_DIST, _all_enemy_leaders] call PC_fn_recon_path_do_not_intersect_enemy_zones) exitWith	
											{
												/// Нет пересечения с опасными зонами:
											
												group _recon setVariable ["PC_AI_recon_path", [_farest_point], true];
											};	
									};
							};						
							
						if (count (group _recon getVariable ["PC_AI_recon_path", []]) > 0) exitWith 
							{
								/// Есть путь. Возвращение назад к началу цикла:								
							};						
						
						/// Группа не может пройти через ближайшую или наиболее дальнюю точку сразу до цели. Определение двух ближайших точек по обе стороны от группы:
						
						_all_positions_around_enemies_and_distance_to_recon sort true;
						
						_closest_position = _all_positions_around_enemies_and_distance_to_recon select 0 select 1;						
						
						//---------- TEST
						/*
						_marker = createMarker ["enemy_marker_" + (str time), _closest_position];
						_marker setMarkerType "mil_dot_noShadow";
						_marker setMarkerColor "ColorGreen";
						*/
						//----------
						
						_fake_object = createVehicle ["Land_InvisibleBarrier_F", position _recon, [], 1, "CAN_COLLIDE"];
						_fake_object setDir (_recon getDir _action_position);						
						
						_left_side_positions = [];
						_right_side_positions = [];
						
						_all_positions_around_enemies_and_distance_to_recon = _all_positions_around_enemies_and_distance_to_recon - [_closest_position];
						
						/// Здесь, если зона врага пересекается всего в одной точке, выход с путем из одной точки:
						
						if (count _all_positions_around_enemies_and_distance_to_recon < 1) exitWith 
							{
								group _recon setVariable ["PC_AI_recon_path", [_closest_position], true];
							};
						
						/// Если путь состоит из больше, чем одной точки:
						
							{
								_pos = (_x select 1);
								
								if (_fake_object getRelDir _pos < 180) then 
									{
										_right_side_positions = _right_side_positions + [_pos];
									} else 
										{
											_left_side_positions = _left_side_positions + [_pos];
										};
							} forEach _all_positions_around_enemies_and_distance_to_recon;
												
						sleep 0.001;						
						
						deleteVehicle _fake_object;
					
						/// Ищем позицию на второй стороне зоны:
						
						_position_on_other_side = [];
						
						_all_positions_around_enemies_and_distance_to_recon_and_to_line = _all_positions_around_enemies_and_distance_to_recon apply {[(([position _recon, _action_position, (_x select 1), true] call BIS_fnc_nearestPoint) distance2d (_x select 1))] + _x};
						_all_positions_around_enemies_and_distance_to_recon_and_to_line sort true;
						
						_all_positions_around_enemies_and_distance_to_recon_and_to_line resize 4;
						
						_all_positions_around_enemies_and_distance_to_recon_and_to_line = _all_positions_around_enemies_and_distance_to_recon_and_to_line apply {[(_x select 1),(_x select 2)]};
						_all_positions_around_enemies_and_distance_to_recon_and_to_line sort false;
						
						_position_on_other_side = _all_positions_around_enemies_and_distance_to_recon_and_to_line select 0 select 1;
						
						//---------- TEST
						/*
						_marker = createMarker ["enemy_marker_" + (str time), _position_on_other_side];
						_marker setMarkerType "mil_dot_noShadow";
						_marker setMarkerColor "ColorYellow";
						*/
						//----------
							
						/// Вычисление пути с двух сторон:

						_left_side_positions = _left_side_positions + [_position_on_other_side];
						_right_side_positions = _right_side_positions + [_position_on_other_side];
						
						_left_side_positions = _left_side_positions arrayIntersect _left_side_positions;
						_right_side_positions = _right_side_positions arrayIntersect _right_side_positions;
						
						_left_side_positions_and_distances = _left_side_positions apply {[(_x distance2D _closest_position), _x]};
						_left_side_positions_and_distances sort true;
						_first_left_side_position = _left_side_positions_and_distances select 0 select 1;
						
						_right_side_positions_and_distances = _right_side_positions apply {[(_x distance2D _closest_position), _x]};
						_right_side_positions_and_distances sort true;
						_first_right_side_position = _right_side_positions_and_distances select 0 select 1;
						
						_left_path = [_closest_position, _first_left_side_position];
						_right_path = [_closest_position, _first_right_side_position];
						
						_left_path_dist = 0;
						_right_path_dist = 0;
						
							{
								if (_forEachIndex == ((count _right_side_positions)-1)) exitWith {};
								
								private _last_pos = _right_path select ((count _right_path)-1);
								
								private _pos_array = _right_side_positions select {!(_x in _right_path)};
								
								_pos_array = _pos_array apply {[(_x distance2D _last_pos), _x]};
								
								_pos_array sort true;
								
								private _new_pos = _pos_array select 0 select 1;
								
								_right_path = _right_path + [_new_pos];
								
								_right_path_dist = _right_path_dist + (_last_pos distance2d _new_pos);
								
							} forEach _right_side_positions;
							
							{
								if (_forEachIndex == ((count _left_side_positions)-1)) exitWith {};
								
								private _last_pos = _left_path select ((count _left_path)-1);
								
								private _pos_array = _left_side_positions select {!(_x in _left_path)};
								
								_pos_array = _pos_array apply {[(_x distance2D _last_pos), _x]};
								
								_pos_array sort true;
								
								private _new_pos = _pos_array select 0 select 1;
								
								_left_path = _left_path + [_new_pos];
								
								_left_path_dist = _left_path_dist + (_last_pos distance2d _new_pos);
								
							} forEach _left_side_positions;		
						
						/// Определяем, с какой стороны обходить:
						
						_path = [];
						
						if (_left_path_dist > _right_path_dist) then 
							{
								_path = _right_path;
							} else 
								{
									_path = _left_path;
								};
								
						/// Если конечная точка не находится в зоне врага, отрезаем от пути те точки, которые можно сократить:
						
						_shorten_path = _path;
						
						/// Наиболее далекая точка:
						
							{
								_pos = _x;
								
								if ([_action_position, _pos, PC_RECON_MOVING_DIST, _all_enemy_leaders] call PC_fn_recon_path_do_not_intersect_enemy_zones) exitWith 
									{
										_index = _shorten_path find _pos;
										
										_shorten_path resize (_index + 1);
									};
							} forEach _path;
						
						reverse _shorten_path;
						
						/// Наиболее близкая точка:
						
							{
								_pos = _x;
								
								if ([position _recon, _pos, PC_RECON_MOVING_DIST, _all_enemy_leaders] call PC_fn_recon_path_do_not_intersect_enemy_zones) exitWith 
									{
										_index = _shorten_path find _pos;
										
										_shorten_path resize (_index + 1);
									};
							} forEach _shorten_path;
							
						reverse _shorten_path;
						
						/// Проверка, не находится ли конечное место разведки в зоне известных врагов, с которыми пересекается путь:
						
						if !([_action_position, _action_position, PC_RECON_MOVING_DIST, _merged_enemies_on_the_path] call PC_fn_recon_path_do_not_intersect_enemy_zones) then 
							{		
								_shorten_path_to_cut = _shorten_path;
								_shorten_path_to_cut_1 = _shorten_path;
								
								_shorten_path_to_cut_and_distances = _shorten_path_to_cut apply {[(_x distance2d _action_position), _x]};
								_shorten_path_to_cut_and_distances sort true;
								_position_with_shortes_distance = _shorten_path_to_cut_and_distances select 0 select 1;
								
									{
										if (_x isEqualTo _position_with_shortes_distance) exitWith 
											{
												_shorten_path resize (_forEachIndex + 1);
											};
									} forEach _shorten_path_to_cut_1;								
							};
						
						
						/// TEST			
							
							{								
								_marker = createMarker ["enemy_marker_" + (str time) + (str _forEachIndex), _x];
								_marker setMarkerType "Contact_pencilCircle2";
								_marker setMarkerColor "ColorWhite";
								_marker setMarkerText str (_forEachIndex +1);
								//_marker setMarkerAlpha 1;								
							} forEach _shorten_path;
						sleep 0.001;
						
						
						/// Есть путь. Возврашение к началу цикла:
						
						group _recon setVariable ["PC_AI_recon_path", _shorten_path, true];
						
					} else 
						{
							/// Враги не известны, продолжаем движение
						};			
			}; 
		
		/// Выход из маршрутной точки:
		
		_group setVariable ["PC_AI_recon_at_his_last_temperary_point", false, true];
		_group setVariable ["PC_AI_recon_path", [], true];
		
			{
				_x setUnitPos "AUTO";
				//_x setBehaviour "STEALTH";
				_x setBehaviour "AWARE";
				//_x setCombatMode "GREEN";
				_x setUnitTrait ["audibleCoef", (_x getUnitTrait "audibleCoef")*2];
				_x setUnitTrait ["camouflageCoef", (_x getUnitTrait "camouflageCoef")*2];
			} forEach units group _recon;
	};

2 - call this script from init.sqf:

[] call compile preprocessfilelinenumbers "sqripts_and_variables.sqf";

3 - call recon action from ingame as you wish:

// group_2 - recon group name
// getMarkerPos "m_1" - end position

[group_2,getMarkerPos "m_1"] spawn PC_direct_fn_allies_recon;

 

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

×