using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class SquadFormation : MonoBehaviour
{
enum Formation
{
Square, Circle, Triangle
}
[Header("Main Settings")]
[Space(5)]
public Transform squadMemeberPrefab;
[Range(4, 100)]
public int numberOfSquadMembers = 20;
[Range(1, 20)]
public int numberOfSquads = 1;
[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;
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 int numofobjects = 0;
// Use this for initialization
void Start()
{
numofobjects = numberOfSquadMembers;
if (startRandomFormation)
{
formation = (Formation)UnityEngine.Random.Range(0, Enum.GetNames(typeof(Formation)).Length);
}
else
{
formation = Formation.Square;
}
currentFormation = formation.ToString();
ChangeFormation();
foreach (Transform child in gameObject.transform)
{
if (child.tag == "Squad Member")
squadMembers.Add(child.gameObject);
}
randomSpeeds = RandomNumbers(randSpeedMin, randSpeedMax, squadMembers.Count);
step = new float[squadMembers.Count];
}
// Update is called once per frame
void Update()
{
if (numofobjects != numberOfSquadMembers)
{
numofobjects = 0;
numofobjects = numberOfSquadMembers;
squadMembers = new List<GameObject>();
FormationSquare();
}
if (Input.GetKeyDown(KeyCode.F))
{
randomSpeeds = RandomNumbers(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;
}
}
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>();
Transform go = squadMemeberPrefab;
for (int i = 0; i < numofobjects; i++)
{
if (squadMembers.Count == 0)
go = Instantiate(squadMemeberPrefab);
Vector3 pos = FormationSquarePositionCalculation(i);
go.position = new Vector3(transform.position.x + pos.x, 0, transform.position.y + pos.y);
go.Rotate(new Vector3(0, -90, 0));
go.tag = "Squad Member";
go.transform.parent = gameObject.transform;
newpositions.Add(go.transform.position);
}
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 / (float)numberOfSquadMembers;
for (int i = 0; i < numberOfSquadMembers; i++)
{
Vector3 pos = FormationCirclePositionCalculation(center, radius, i, angleIncrement);
var rot = Quaternion.LookRotation(center - pos);
pos.y = Terrain.activeTerrain.SampleHeight(pos);
pos.y = pos.y + yOffset;
newpositions.Add(pos);
quaternions.Add(rot);
}
move = true;
squareFormation = false;
formation = Formation.Square;
}
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[] RandomNumbers(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;
}
}在构造函数中,我使用标记团队成员搜索childs。但是列表squadMembers将是空的,因为脚本附加到一个新的空GameObject上,没有任何子程序。
然后变量步骤也将为空。然后,在方法MoveToNextFormation中,我正在检查step是否为空:
if (step.Length > 0)
step[0] = moveSpeed * Time.deltaTime;如果不检查它将抛出异常,因为索引0没有任何异常,则为null。但是如果台阶是空的,那么物体的运动就没有速度/s了。
这是个问题。我甚至不知道为什么在构造函数中,我与孩子和“团队成员”标签一起做了这个角色。我还没有用这个标记创建任何子元素,所以我对我试图在构造函数中做什么感到困惑。
第二个问题在FormationSquare方法的这一行中:
if (squadMembers.Count == 0)
go = Instantiate(squadMemeberPrefab);但是如果squadMembers是空的,那么它将在代码中的其他地方抛出异常。我在FormationSquare方法中创建新对象,这是因为我默认使用FormationSquare启动,但是如果我想默认情况下使用FormationCircle方法启动呢?
这个想法是从最少的(1)小队数和最少(4)成员的人数开始时开始计划。或者从最小到最大的范围开始。但一切都搞砸了。
发布于 2018-11-04 14:21:04
在您的示例中,我会将预编实例化与小组形状格式分开,这样做将有助于您识别错误。
例如,添加以下方法并在“开始”期间使用它们:
void AddSquadMember()
{
// Use this to instantiate/spawn a new game object prefab.
}
void AddSquadMember(GameObject object)
{
// Use this for game object already in the scene. (.eg the children with your tag)
}然后,在形成方法上,删除语调调用,只使用列表中的任何游戏对象。
最后,我会抛出“numofobjects”变量。然后使用“squadMembers.Count”而不是“numofobjects”和“numberOfSquadMembers”,假设在“开始”期间,您已经负责实例化所有游戏对象,以便“numberOfSquadMembers == squadMembers.Count”。这是因为你可能需要在游戏中增加几个成员来提高阵容。
https://stackoverflow.com/questions/53129518
复制相似问题