Как я могу предотвратить добавление новых и новых объектов при нажатии F для изменения формации? - PullRequest
0 голосов
/ 03 ноября 2018
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;
    }
}

В конструкторе я ищу детей с тегом Squad Member. Но список squadMembers будет пустым, поскольку скрипт прикреплен к новому пустому GameObject без дочерних элементов.

Тогда и переменная step будет пустой. Затем внутри метода MoveToNextFormation я проверяю, пустой шаг или нет:

if (step.Length > 0)
                step[0] = moveSpeed * Time.deltaTime;

Если не установить флажок, он выдаст исключение, так как в индексе 0 нет ничего, это ноль. Но тогда, если шаг пуст, скорости движения не будет совсем / с.

Это одна проблема. Я даже не уверен, почему в конструкторе я сделал часть с детьми и тегом "Squad Member". Я пока не создаю детей с этим тегом, поэтому я не понимаю, что я пытался сделать в конструкторе.

Вторая проблема заключается в следующих строках метода FormationSquare:

if (squadMembers.Count == 0)
                go = Instantiate(squadMemeberPrefab);

Но если squadMembers пуст, то он выдаст исключение где-то еще в других местах кода. И я создаю новые объекты внутри метода FormationSquare, поскольку по умолчанию я начинаю с FormationSquare, но что, если я хочу начать по умолчанию с метода FormationCircle?

Идея состоит в том, чтобы начать с минимального (1) количества отрядов и с минимальным (4) количеством участников в отряде при запуске программы. Или начать с любого диапазона от мин до макс. Но все запутано.

1 Ответ

0 голосов
/ 04 ноября 2018

В вашем случае я бы отделил готовую инстанциацию члена отряда от форматирования формы отряда, это поможет вам идентифицировать вашу ошибку.

Например, добавьте следующие методы и используйте их при запуске:

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)
}

Затем в методах формирования удалите вызовы intantiate и просто используйте любой игровой объект, который у вас есть в списке.

Наконец, я бы бросил переменную 'numofobjects'. Затем используйте «squadMembers.Count» вместо «numofobjects» и «numberOfSquadMembers», предполагая, что во время «Start» вы позаботились о создании всех игровых объектов, чтобы «numberOfSquadMembers == squadMembers.Count». Это потому, что вам может понадобиться поднять отряд еще с несколькими участниками во время игры.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...