Jump to content
Sign in to follow this  
johnnyboy

how to remove collections of objects at runtime for replayability

Recommended Posts

To make missions replayable, I like to make multiple unique collections of objects (enemy camps, road blocks, ambush setups, etc), and then at mission startup randomly choose a subset of the collections to exist for the mission session.   This makes the mission more re-playable and unpredictable (and fresh) each time you play.

 

In my Property of Mabunga mission, I defined 6 detailed pirate camps (and I may add 3 more).  Each camp is layed out with different buildings, patrols, vehicles, defender units, campfires, tables, chairs, garbage, etc.  And at runtime, scripts randomly remove 3 of the camps, so only 3 are left for the mission session.

 

Maybe a mission maker with a similar design goal will find the following technique useful.

 

1. Near the top of the init.sqf, define arrays to hold all the objects for each camp:

// Create arrays to hold objects defined for each camp
CAMP1_OBJECTS = [];
CAMP2_OBJECTS = [];
CAMP3_OBJECTS = [];
CAMP4_OBJECTS = [];
CAMP5_OBJECTS = [];
CAMP6_OBJECTS = [];
// Create arrays with one element per camp so we can shuffle and remove camps later
CAMPS = [CAMP1_OBJECTS, CAMP2_OBJECTS, CAMP3_OBJECTS, CAMP4_OBJECTS, CAMP5_OBJECTS, CAMP6_OBJECTS];
CAMP_INDEXES = [0, 1, 2, 3, 4, 5];

2. In the editor, place a statement in each camp object's init that will put that object in its respective array.  The example statement below would be placed in all the Camp 1 Objects' inits.  For Camp 2 you would change the array name to CAMP2_OBJECTS (Etc. for camp 3, 4, 5, and 6) .  At mission initialization, these object inits will load each separate Camp Objects array with its particular list of objects for that camp.  The statement is executed via Spawn which allows time for the global objects Array to be defined by the init.sqf.

 NUL=[this] spawn {sleep 1; CAMP1_OBJECTS pushback  (_this select 0)};

3. Put the following code in the init.sqf (somewhere after code shown in step 1).  This code shuffles the array of six camps (CAMPS), and deletes all objects for 3 of the camps, leaving the objects for the 3 other camps to be live during the mission.

[] spawn {
    if (!isServer)  exitwith {};
    // sleep a little to give time for all camp objects to be loaded into their arrays
    sleep 5;
    // shuffle the array of camp indexes 
    _tmp = CAMP_INDEXES call BIS_fnc_arrayShuffle;
    CAMP_INDEXES = _tmp;
    // Each iteration of this loop removes a camp and all of its objects, until only 3 camps left
    WHILE { count CAMP_INDEXES > 3} DO {
	_removeIndx = CAMP_INDEXES call BIS_fnc_selectRandom;
	_removeIndex = CAMP_INDEXES find _removeIndx;
        // delete all objects for camp
	{deleteVehicle _x;} foreach (CAMPS select _removeIndex);
	CAMPS deleteAt _removeIndex;
	CAMP_INDEXES deleteAt _removeIndex;
     };
};

And, "snip-snap, Bob's your Aunt!" as an old South African friend of mine used to say...

 

Another option for random location setups, is to define one collection of objects, and move it to a random set of positions/locations at runtime.  That's a better approach if you want to have the exact same collection of objects and exact same relative position of those objects.  But for my Pirate Camp needs, I wanted each camp to be unique, and to fit in with the terrain of the physical location of the camp, so the above described approach worked better.

 

I hope someone finds this useful.

  • Like 2

Share this post


Link to post
Share on other sites

My approach:

 

1. In editor place  markers where you want camps, with names beginning from pattern "CampMarker_UNIQUENAMEPART" and radius equal camp placing randomisation.

2. When mission initializing iterate over all markers with name beginning from "CampMarker_"

2.1 Check random chance to appearing this camp

2.2 Calculate random position in marker area - it will be the center of the camp

2.3 From CampTemplatePresets* select random preset with object composition for this camp

3.3 Dynamically create all objects of selected composition at camp origin

3.4 Add camp record [CampName, CampPosition,  [ArrayOfDynamicallyCreatedObjects]] to camps array for access during mission

 

4 CampTemplates format [[ObjectComposition1], [ObjectComposition2], [ObjectComposition3], ...]

4.1 ObjectComposition format [[ObjectPlacement1], [ObjectPlacement2], [ObjectPlacement3], ...]

4.1.1 ObjectPlacement format ["ObjectClassName", DistanceToCompositionOrigin, DirectionFromCompositionOriginToObject, ObjectDirection]

 

Functions to capture and spawn object compositions:

/*	Function create object composition template from objects of given type in given radius from given position
	Arguments: [TemplateOriginPosition, TemplateRadius, [ObjectTypesFilterArray]]
	Return: array of object placements [["ObjectClass", ObjectDistanceToTemplateOrigin, ObjectAzimuthFromTemplateOrigin, ObjectDirection]]	
	Usage: copyToClipboard (str ([getPos player, 30, ["ThingX", "Building"]] call Fn_CreateObjectCompositionTemplate));
*/
Fn_CreateObjectCompositionTemplate = {
	params ["_org", "_rad", "_cts"];
	private _ret = [];
	{
		{	private _dst = _org distance _x;
			if (_dst < _rad) then {
				_ret pushBack [typeOf _x, _dst, _org getDir _x, getDir _x]}
		} forEach allMissionObjects _x;
	} forEach _cts;	
	_ret
};


/*	Function spawn object composition from given template in given position and direction
	Arguments: [CompositionPlacementPosition, CompositionHeadingDirection, CompositionTemplateData]
	Return: array of created objects
	Usage: _campObjects = [getPos player, getDir player, campTemplate] call Fn_CreateObjectCompositionFromTemplate;
*/
Fn_CreateObjectCompositionFromTemplate = {
	params ["_org", "_hdg", "_cps"];
	private _ret = [];	
	{	_x params ["_cls", "_dst", "_rdr", "_dir"];	
		private _obj = _cls createVehicle [0,0,0];
		private _pos = _org getPos [_dst, _rdr + _hdg];
		_obj setPos _pos;
		_obj setDir (_dir + _hdg);
                _ret pushBack _obj;
	} forEach _cps;
	_ret
};

Usage:

removeAllActions player;
player addAction ["Pick Composition", {copyToClipboard str (
	[getPos player, 30, ["ThingX", "Building"]] call Fn_CreateObjectCompositionTemplate)}];

player addAction ["Spawn Composition", {
	[getPos player, getDir player, call compile copyFromClipboard] call Fn_CreateObjectCompositionFromTemplate}];

Action "Pick Composition" create composition from objects in 30m radius around player and place composition data to clipboard. "Spawn Composition" take composition data from clipboard and spawn composition objects with origin at player position and direction.

 

 

Camps initialization at mission begin:

CampCompositionTemplates = [ // Paste captured camp templates here
	[// example template 
		["Land_CampingTable_small_F",2.65883,27.4503,8.13856e-005],
		["Land_CampingChair_V1_F",1.6,52.8133,179.991],
		["FirePlace_burning_F",2.23064,345.909,360]
	]
];
Camps = [];
CampChanceToAppear = 1;

Fn_InitializeCamps = {
	{
		if (_x find "CampMarker_" == 0) then {
			if (random 1 < CampChanceToAppear) then {
				private _tpl = selectRandom CampCompositionTemplates;
				private _obj = [markerPos _x, random 360, _tpl] call Fn_CreateObjectCompositionFromTemplate;		
				Camps pushBack [markerText _x, markerPos _x, _obj];
			}
		}
	} forEach allMapMarkers;
};

And:

Fn_DeleteCamp = {
	private _cmp = _this;
	{deleteVehicle _x} forEach (_cmp select 2);
	Camps deleteAt (Camps find _cmp);
};

So it is simple way to dynamically create and delete camps at any time during mission

  • Like 2

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  

×