How can I add/remove more squads to the existing current formation and also squad members to each existing squad/s at runtime ?

diplomaticimmunity 1 Reputation point
2021-11-14T23:38:56.317+00:00
using System;  
using System.Collections;  
using System.Collections.Generic;  
using System.Linq;  
using UnityEngine;  
  
public class Formations : MonoBehaviour  
{  
	enum Formation  
	{  
		Square, Circle, Triangle  
	}  
  
	public GameObject squadMemberPrefab;  
	public GameObject squadPrefab;  
  
	[Header("Main Settings")]  
	[Space(5)]  
	[Range(1, 20)]  
	public int numberOfSquads = 1;  
	[Range(1, 100)]  
	public int numberOfSquadMembers = 20;  
	[Range(0, 4)]  
	public int columns = 4;  
	public int gaps = 10;  
	public int circleRadius = 10;  
	public float yOffset = 0;  
	[Range(3, 50)]  
	public float moveSpeed = 3;  
	[Range(3, 50)]  
	public float rotateSpeed = 1;  
	public float threshold = 0.1f;  
	public bool randomSpeed = false;  
	[Range(1, 100)]  
	public int randSpeedMin = 1;  
	[Range(1, 100)]  
	public int randSpeedMax = 1;  
	public bool startRandomFormation = false;  
	public string currentFormation;  
	public SquadsGenerator squadsGenerator;  
  
	private Formation formation;  
	private List<Quaternion> quaternions = new List<Quaternion>();  
	private List<Vector3> newpositions = new List<Vector3>();  
	private bool move = false;  
	private bool squareFormation = false;  
	private List<GameObject> squadMembers = new List<GameObject>();  
	private float[] step;  
	private int[] randomSpeeds;  
	private int index = 0;  
	private bool ready = false;  
	private GameObject[] squads;  
	private Vector3 startVector;  
	private Vector3 total;  
	private List<Vector3> endpositions = new List<Vector3>();  
	private int oldnumberofsquadmembers = 0;  
  
	public void InitFormations()  
	{  
		if (startRandomFormation)  
		{  
			formation = (Formation)UnityEngine.Random.Range(0, Enum.GetNames(typeof(Formation)).Length);  
		}  
		else  
		{  
			formation = Formation.Square;  
		}  
  
		squads = GameObject.FindGameObjectsWithTag("Squad");  
		for (int i = 0; i < squads.Length; i++)  
		{  
			foreach (Transform squadMember in squads[i].transform)  
			{  
				squadMembers.Add(squadMember.gameObject);  
			}  
		}  
  
		foreach (GameObject unit in squadMembers)  
		{  
			if (unit != null)  
			{  
				total += unit.transform.position;  
			}  
		}  
  
		Vector3 center = total / squadMembers.Count;  
		//Vector3 endPos = GameObject.Find("Cube").transform.position;  
		foreach (GameObject unit in squadMembers)  
		{  
			startVector = unit.transform.position - center;  
			endpositions.Add(/*endPos+*/ startVector);  
		}  
  
		currentFormation = formation.ToString();  
		ChangeFormation();  
  
		randomSpeeds = RandomSpeeds(randSpeedMin, randSpeedMax, squadMembers.Count);  
		step = new float[squadMembers.Count];  
  
		ready = true;  
	}  
  
	private void Start()  
	{  
		oldnumberofsquadmembers = numberOfSquadMembers;  
  
		squadsGenerator.GenerateSquads(numberOfSquads, numberOfSquadMembers,  
			squadMemberPrefab, squadPrefab);  
  
		InitFormations();  
	}  
  
	// Update is called once per frame  
	void Update()  
	{  
		if (ready == true)  
		{  
			if (Input.GetKeyDown(KeyCode.C))  
			{  
				randomSpeeds = RandomSpeeds(randSpeedMin, randSpeedMax, squadMembers.Count);  
				foreach (int speedV in randomSpeeds)  
				{  
					if (index == randomSpeeds.Length)  
						index = 0;  
  
					step[index] = speedV * Time.deltaTime;  
					index++;  
				}  
  
				ChangeFormation();  
			}  
  
			if (move == true)  
			{  
				MoveToNextFormation();  
			}  
		}  
	}  
  
	private void ChangeFormation()  
	{  
		switch (formation)  
		{  
			case Formation.Square:  
				FormationSquare();  
				break;  
  
			case Formation.Circle:  
				FormationCircle();  
				break;  
  
			case Formation.Triangle:  
				FormationTriangle();  
				break;  
		}  
	}  
  
	private void FormationTriangle()  
	{  
		newpositions = new List<Vector3>();  
  
		int height = Mathf.CeilToInt((Mathf.Sqrt(8 * squadMembers.Count + 1f) - 1f) / 2);  
		int slots = (int)(height * (height + 1f) / 2f);  
  
		float verticalModifier = 1.25f;  // * 1.25f to increase horizontal space  
		float horizontalModifier = 0.8f; // * 0.8f to decrease "vertical" space  
  
		float width = 0.5f * (height - 1f);  
		Vector3 startPos = new Vector3(width * horizontalModifier, 0f, (float)(height - 1f) * verticalModifier);  
  
		int finalRowCount = height - slots + squadMembers.Count;  
		for (int rowNum = 0; rowNum < height && newpositions.Count < squadMembers.Count; rowNum++)  
		{  
			for (int i = 0; i < rowNum + 1 && newpositions.Count < squadMembers.Count; i++)  
			{  
				float xOffset = 0f;  
  
				if (rowNum + 1 == height)  
				{  
					// If we're in the last row, stretch it ...  
					if (finalRowCount != 1)  
					{  
						// Unless there's only one item in the last row.   
						// If that's the case, leave it centered.  
  
						xOffset = Mathf.Lerp(  
								rowNum / 2f,  
								-rowNum / 2f,  
								i / (finalRowCount - 1f)  
								) * horizontalModifier;  
					}  
				}  
				else  
				{  
					xOffset = (i - rowNum / 2f) * horizontalModifier;  
				}  
  
				float yOffset = (float)rowNum * verticalModifier;  
  
				Vector3 position = new Vector3(  
						startPos.x + xOffset, 0f, startPos.y - yOffset);  
				newpositions.Add(position);  
  
			}  
		}  
  
		move = true;  
		formation = Formation.Square;  
	}  
  
	private Vector3 FormationSquarePositionCalculation(int index) // call this func for all your objects  
	{  
		float posX = (index % columns) * gaps;  
		float posY = (index / columns) * gaps;  
		return new Vector3(posX, posY);  
	}  
  
	private void FormationSquare()  
	{  
		newpositions = new List<Vector3>();  
		quaternions = new List<Quaternion>();  
  
		for (int i = 0; i < squadMembers.Count; i++)  
		{  
			Vector3 pos = FormationSquarePositionCalculation(i);  
  
			squadMembers[i].transform.Rotate(new Vector3(0, -90, 0));  
  
			newpositions.Add(new Vector3(endpositions[i].x + pos.x, 0, endpositions[i].y + pos.y));  
		}	  
  
		move = true;  
		squareFormation = true;  
		formation = Formation.Circle;  
  
	}  
  
	private Vector3 FormationCirclePositionCalculation(Vector3 center, float radius, int index, float angleIncrement)  
	{  
		float ang = index * angleIncrement;  
		Vector3 pos;  
		pos.x = center.x + radius * Mathf.Sin(ang * Mathf.Deg2Rad);  
		pos.z = center.z + radius * Mathf.Cos(ang * Mathf.Deg2Rad);  
		pos.y = center.y;  
		return pos;  
	}  
  
	private void FormationCircle()  
	{  
		newpositions = new List<Vector3>();  
		quaternions = new List<Quaternion>();  
  
		Vector3 center = transform.position;  
		float radius = (float)circleRadius / 2;  
		float angleIncrement = 360 / squadMembers.Count;//(float)numberOfSquadMembers;  
		for (int i = 0; i < squadMembers.Count; i++)//numberOfSquadMembers; i++)  
		{  
			Vector3 pos = FormationCirclePositionCalculation(center, radius, i, angleIncrement);  
  
			var rot = Quaternion.LookRotation(center - pos);  
  
			if (Terrain.activeTerrain == true)  
				pos.y = Terrain.activeTerrain.SampleHeight(pos);  
			pos.y = pos.y + yOffset;  
			newpositions.Add(pos);  
			quaternions.Add(rot);  
		}  
		move = true;  
		squareFormation = false;  
		formation = Formation.Triangle;  
	}  
  
	private void MoveToNextFormation()  
	{  
		if (randomSpeed == false)  
		{  
			if (step.Length > 0)  
				step[0] = moveSpeed * Time.deltaTime;  
		}  
  
		for (int i = 0; i < squadMembers.Count; i++)  
		{  
			squadMembers[i].transform.LookAt(newpositions[i]);  
  
			if (randomSpeed == true)  
			{  
				squadMembers[i].transform.position =  
			Vector3.MoveTowards(squadMembers[i].transform.position, newpositions[i], step[i]);  
			}  
			else  
			{  
				squadMembers[i].transform.position =  
				Vector3.MoveTowards(squadMembers[i].transform.position, newpositions[i], step[0]);  
			}  
  
			if (Vector3.Distance(squadMembers[i].transform.position, newpositions[i]) < threshold)  
			{  
				if (squareFormation == true)  
				{  
					Vector3 degrees = new Vector3(0, 0, 0);  
					Quaternion quaternion = Quaternion.Euler(degrees);  
					squadMembers[i].transform.rotation = Quaternion.Slerp(squadMembers[i].transform.rotation, quaternion, rotateSpeed * Time.deltaTime);  
				}  
				else  
				{  
					squadMembers[i].transform.rotation = Quaternion.Slerp(squadMembers[i].transform.rotation, quaternions[i], rotateSpeed * Time.deltaTime);  
				}  
			}  
		}  
	}  
  
	private static int[] RandomSpeeds(int min, int max, int howMany)  
	{  
		int[] myNumbers = new int[howMany];  
  
		for (int i = 0; i < howMany; i++)  
		{  
			myNumbers[i] = UnityEngine.Random.Range(min, max);  
		}  
  
		return myNumbers;  
	}  
}  
  

In the Update() I tried before to add this :

if(oldnumberofsquadmembers != numberOfSquadMembers)  
        {  
  
			oldnumberofsquadmembers = numberOfSquadMembers;  
        }  

but not sure how to continue.

the goal is to keep the current formation and to add/remove to it squads or squad members when changing the variables numberOfSquads and numberOfSquadMembers.

for example if I start the application when the variable numberOfSquads is 11 and numberOfSquadMembers is 7

149164-aoy1.jpg

This script is how I generate the squads and squads members first time :

using System.Collections;  
using System.Collections.Generic;  
using UnityEngine;  
  
public class SquadsGenerator : MonoBehaviour  
{  
	private GameObject squadsParent;  
  
	private void Start()  
	{  
		squadsParent = GameObject.Find("Squads");  
	}  
  
	// Update is called once per frame  
	void Update()  
	{  
		  
	}  
  
	public void GenerateSquads(int squadsCount,  
		int numberOfMembers,  
		GameObject squadMemberPrefab, GameObject squadPrefab)  
	{  
		for (int i = 0; i < squadsCount; i++)  
		{  
			var newSquad = Instantiate(squadPrefab);  
			newSquad.name = "Squad " + i;  
			newSquad.tag = "Squad";  
			newSquad.transform.parent = squadsParent.transform;  
  
			for (int x = 0; x < numberOfMembers; x++)  
			{  
				var go = Instantiate(squadMemberPrefab);  
				go.name = "Member " + x;  
				go.tag = "Squad Member";  
				go.transform.parent = newSquad.transform;  
  
				switch (i % 6)  
				{  
					case 0: ColorSquad(go, Color.green); break;  
					case 1: ColorSquad(go, Color.red); break;  
					case 2: ColorSquad(go, Color.blue); break;  
					case 3: ColorSquad(go, Color.yellow); break;  
					case 4: ColorSquad(go, Color.cyan); break;  
					case 5: ColorSquad(go, Color.magenta); break;  
				}  
			}  
		}  
	}  
  
	private void ColorSquad(GameObject squad, Color color)  
	{  
		Renderer rend = squad.GetComponent<Renderer>();  
		rend.material.SetColor("_Color", color);  
	}  
}  
  
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,279 questions
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.