Hi All,
I’m doing a space sim and was having a hard time getting formation flying to work. A lot of the suggestions I read pointed towards boids but it wasn’t the path that I wanted to take. After a bit of wrestling yesterday I prototyped a system that enables formation flying without having to parent/unparent game objects or work with boids.
It consists of a FlightController which simply assigns flight leaders and flight members, and a follow function in a movement controller assigned to each ship GameObject. This is very rough and still in the early prototype phase (a lot of stuff is hardcoded still) but I wanted to get it out there so people trying to handle similar tasks had something to reference.
Right now I’m using each ships “flight position” to determine what their lateral offset from the flight leader should be.
FlightController.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class FlightController : MonoBehaviour {
public List<Transform> ships = new List<Transform>();
public Transform currentLeader;
// Use this for initialization
void Start () {
//Get a List of all Ships this Flight Controller is Responsible For
GameObject[] gos = GameObject.FindGameObjectsWithTag("Ship");
foreach(GameObject go in gos)
{
if(go.GetComponent<FighterAI>().faction.ToString() == "Imperial")
{
ships.Add(go.transform);
}
}
//Sort List by Name ie Alpha 1, Alpha 2, ect
ships.Sort(
delegate(Transform i1, Transform i2)
{
return i1.name.CompareTo(i2.name);
}
);
}
// Update is called once per frame
void Update () {
setLeadersAndFollowers();
}
// Creates 3 ship flight groups out of the list. Ships assigned a leader will enter Follow state. Ships without leader will enter
// Patrol state.
void setLeadersAndFollowers()
{
int j = 1;
for(int i=0; i<ships.Count; i++)
{
if(i%3==0)
{
currentLeader = ships[i];
j=1;
} else {
ships[i].GetComponent<FighterAI>().flightLeader = currentLeader;
ships[i].GetComponent<FighterAI>().flightPosition = j;
j++;
}
}
}
}
Follow function inside ship movement controller
// Follows Flight Leader in Patrol
public void FollowTarget(Transform target, int xOffset)
{
// Sets the ship back and to the right or left of the leader
Vector3 targetPosition = target.position + (target.right * xOffset) + (target.forward * Math.Abs(xOffset) * -1);
float distance = Vector3.Distance(targetPosition,transform.position);
//Ensures we never actually hit our targetPosition, we'll always be at least 20 units away
//We need this so that Quaternion.RotateTowards doesn't create weird rotations
if(distance < 20 ) {
_myShip.currSpeed = 0;
} else if(distance > 20 distance < 40) {
_myShip.currSpeed = 2 * target.GetComponent<Ship>().currSpeed;
} else {
_myShip.currSpeed = 2 * _myShip.maxSpeed;
}
//Rotate Towards Target
Quaternion newRotation = Quaternion.LookRotation(targetPosition - transform.position);
transform.rotation = Quaternion.RotateTowards(transform.rotation, newRotation, _myShip.manuverability * Time.deltaTime);
//Bank Towards Target
Vector3 tarPosition = (targetPosition - transform.position);
float dir = Vector3.Dot(tarPosition.normalized, transform.right.normalized);
//Add a bit of dampening
if(Math.Abs(dir) > _myShip.bankDampening) {
transform.Rotate(0,0, -dir * _myShip.bank * Time.deltaTime);
}
//Move Towards Target
transform.position += transform.forward * _myShip.currSpeed * Time.deltaTime;
}
Hope this helps somebody else!
Happy developing!