Jump to content
johnnyboy

JBOY Fly In Formation [Released]

Recommended Posts

Here's another script from my Property of Mabunga mission.  If you've tried that mission, please rate and comment on Steam.

 

With this script, you can make any object fly in V formation.  If you use the bird object ("seagull"), the script will play some duck quacking sounds also.  If the object is an air vehicle, it turns engine on.  This script is intended for ambience and cutscenes, as the flying objects have no AI.  Any object can fly, so if flying goats are your thing...have at it.



bird_Formation.jpg
jet_Formation.jpg
 

Warning:  This script is currently coded to fly at a single altitude, so if you pass in 50 meters as height, and point the formation at a 100 meter hill, it will fly into the hill.  It works fine if you know that limitation and use it accordingly.  It could be changed to modify Z velocity based on terrain ahead, but I don't plan on doing that any time soon.

How to use:
1. In the editor create an arrow marker to be the starting point of formation.
2. In a trigger or your init file, place a call to my script.  The video demo mission shown above had 5 calls to my script in the init.sqf (2 bird formations and 3 jet formations):
 

dmy = ["seagull", getMarkerPos "mrkDuckStart", markerDir "mrkDuckStart", 300, 10, 25, 20] execvm "Scripts\JBOY_BirdFormation.sqf";
sleep 6;
dmy = ["seagull", getMarkerPos "mrkDuckStart_1", markerDir "mrkDuckStart_1", 1000, 25, 20, 20] execvm "Scripts\JBOY_BirdFormation.sqf";
sleep 15;
dmy = ["B_Plane_CAS_01_F", getMarkerPos "mrkDuckStart_2", markerDir "mrkDuckStart_2", 7000, 15, 150, 400] execvm "Scripts\JBOY_BirdFormation.sqf";
sleep .2;
dmy = ["B_Plane_CAS_01_F", getMarkerPos "mrkDuckStart_2", markerDir "mrkDuckStart_2", 7000, 15, 150, 400] execvm "Scripts\JBOY_BirdFormation.sqf";
sleep .2;
dmy = ["B_Plane_CAS_01_F", getMarkerPos "mrkDuckStart_2", markerDir "mrkDuckStart_2", 7000, 15, 150, 400] execvm "Scripts\JBOY_BirdFormation.sqf";

3. Create a file in your mission directory called "JBOY_BirdFormation.sqf" and put this code in it:

//////////////////////////////////////////////////////////
// JBOY_BirdFormation.sqf 
// By: johnnyboy
// dmy = ["seagull", getMarkerPos "mrkDuckStart", 180,       1000,        10,        50         , 20] execvm "Scripts\JBOY_BirdFormation.sqf";
// dmy = [objType,   startPosition,               Direction, Iterations,  BirdCount, FlockHeight, speed] execvm "Scripts\JBOY_BirdFormation.sqf";
//
// Creates V formation of flying objects
//////////////////////////////////////////////////////////
// ducks fly at 30-50 kph
_objType     = _this select 0;
_startPos    = _this select 1;
_dir         = _this select 2;
_iterations  = _this select 3;
_birdCount   = _this select 4;
_flockHeight = _this select 5;
_speed       = _this select 6;

//_speed =  20;
_xx = 0;
_sleepTime = .1;
// **************************************************************************
// create leader physics object that we can use setvelocity on
// **************************************************************************
_obj = "Land_CanOpener_F" createVehicle [10,10000,0];
_obj setdir _dir;
_obj allowdamage false;

// **************************************************************************
// create bird leader object
// **************************************************************************
_birdLeader = _objType createVehicle [5,5,5];
_obj disableCollisionWith _birdLeader;
_birdLeader setDir getDir _obj;
_birdLeader attachTo [_obj, [0,0,0]];

// **************************************************************************
// Add all objects created to an array so we can delete them later
// **************************************************************************
_objArray = [];
_objArray pushBack _obj;
_objArray pushBack _birdLeader;
 sleep 5;
 
 // Get dimensions of object
 _bbr = boundingBoxReal _birdLeader;
_p1 = _bbr select 0;
_p2 = _bbr select 1;
_maxWidth = abs ((_p2 select 0) - (_p1 select 0));
//_maxLength = abs ((_p2 select 1) - (_p1 select 1));
//_maxHeight = abs ((_p2 select 2) - (_p1 select 2));

// turn engine on for air vehicles
if (_objType isKindOf "Air") then {
    player action["EngineOn", _birdLeader];
};
// **************************************************************************
// Create and attach all follower birds, calculating relative positions for V formation.
// Relative positions based on width of object.  Follower positions randomly tweaked
// a little so bird formation is not "too perfect".
// **************************************************************************
_offset = _maxWidth + (_maxWidth/10);  // space between birds 
for "_i" from 1 to _birdCount -1 do
{
    _bird = _objType createVehicle [5,5,5];
    if (_objType isKindOf "Air") then {
       player action["EngineOn", _bird];
    };
    _objArray pushBack _bird;
    _bird setDir getDir _obj;
    if ((_i mod 2) == 1) then 
    {  // Odd followers to the left
        _bird attachTo [_obj, [_offset*-1 + (random 10/10),_offset*-1, 0]];
     } else
    {  // Even followers to the right
       _bird attachTo [_obj, [_offset + (random 10/10),    _offset*-1, 0]];
       _offset = _offset + _maxWidth + (_maxWidth/10);
    };
};

// **************************************************************************
// Move the birds
// **************************************************************************
_obj setpos [_startPos select 0, _startPos select 1, _flockHeight];

while {_xx < _iterations} do
{
   _xx = _xx + 1;
   //_obj setVectorDirAndUP [[0.728425,0.68065,-0.078186], [0.00150812,0.112526,0.993648]];
   _obj setVelocity [_speed * sin(_dir), _speed * cos(_dir), 0];  
   sleep _sleepTime;
   if (_objType == "seagull") then {
        // Ducks quack periodically    
        _rand = floor(random 100);
        switch ( true )  do 
        {
           case (_rand < 3): { _birdLeader say3d "quack1"  };
           case (_rand < 6): { _birdLeader say3d "quack2"  };
           case (_rand < 9): { _birdLeader say3d "quack3"  };
      
          };
    };
};
// **************************************************************************
// Delete the birds
// **************************************************************************
{deleteVehicle _x;} forEach _objArray;

I just grabbed the duck noises off the web.  You can comment that code out it you want.  If you want the duck sounds, let me know, and I will upload this demo mission so you can pull all the files down.

  • Like 14

Share this post


Link to post
Share on other sites

Thank you for this.

I am trying to set up ambient flybys of a formation of (bomber) planes, and I was getting rather stuck. This seems exactly what I wished for!

Had a follow-up question: at the moment I am 'randomizing' it by setting up 4 different cases of starting positions and directions, and having the script pick one.

 

Did you have any luck on making it properly random? I'm imagining generating positions on the edge of a circle marker, but not quite sure how to implement it.

Share this post


Link to post
Share on other sites

Hwy Mike, I wrote this years ago, and don't recall the details.  It was strictly for V formations, and beware the warning in OP that height is fixed, so if you point them at a mountain they will fly into it.  So its good for only simple ambient fly bys.

Share this post


Link to post
Share on other sites

Thank you for the reply.

15 hours ago, Melody_Mike said:

Did you have any luck on making it properly random? I'm imagining generating positions on the edge of a circle marker, but not quite sure how to implement it.


I re-read my message, and must admit it wasn't very clear. Here's a sketch of what I mean:
Drawing-1.png
And I guess here's a sketch of code that might do it, to be pasted into initserver:

// Get terrain dimensions 
private _axis = worldSize / 2; 
private _center = [_axis, _axis , 0]; 
private _radius = sqrt 2 * _axis;

// Create marker
_mrkcenter = createMarkerLocal ["MrkDuckCenter", _center];
“MrkDuckCenter” setMarkerShapeLocal “ELLIPSE”;
"MrkDuckCenter" setMarkerSizeLocal [_axis, _axis];
"MrkDuckCenter" setMarkerDirLocal _theta;
"MrkDuckCenter" setMarkerAlphaLocal 0;

// Generate angle
private _theta = random 360;

// Convert to cartesian
private _x = _radius * cos( _theta );
private _y = _radius * sin( _theta );

// Set marker position and direction
"mrkDuckStart" setMarkerPos [ _x , _y ];
"mrkDuckStart" setMarkerDir ( _theta - 180 );

// Start script
_dmy = ["seagull", getMarkerPos "mrkDuckStart", markerDir "mrkDuckStart", 300, 10, 25, 20] execvm "Scripts\JBOY_BirdFormation.sqf";

There's probably a mistake here. I will have to test this later on my machine. There's also no looping. Either I wrap it into a " [] spawn { while {true} do {} }" code block, or perhaps tie it with a https://community.bistudio.com/wiki/Arma_3:_Event_Handlers#Deleted  event handler for the birds. To be continued...

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

×