对象使用自己独特的waypoints数组

时间:2016-03-20 21:04:42

标签: c# arrays class object unity3d

...更新

头等舱

using UnityEngine;
using System.Collections;

[System.Serializable]
public class Wave
{
    public GameObject enemyPrefab;
    public float spawnInterval = 2;
    public int maxEnemies = 20;
}

public class SpawnEnemy : MonoBehaviour
{

    public GameObject[] waypoints;
    public GameObject testEnemyPrefab;

    public Wave[] waves;
    public int timeBetweenWaves = 5;

    private GameManagerBehavior gameManager;

    private float lastSpawnTime;
    private int enemiesSpawned = 0;

    // Use this for initialization
    void Start()
    {
        lastSpawnTime = Time.time;
        gameManager =
            GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
    }

    // Update is called once per frame
    void Update()
    {
        // 1 Get the index of the current wave, and check if it’s the last one.
        int currentWave = gameManager.Wave;
        if (currentWave < waves.Length)
        {
            // 2 If so, calculate how much time passed since the last enemy spawn and whether it’s time to spawn an enemy. Here you consider two cases.
            // If it’s the first enemy in the wave, you check whether timeInterval is bigger than timeBetweenWaves.
            // Otherwise, you check whether timeInterval is bigger than this wave’s spawnInterval. In either case, you make sure you haven’t spawned all the enemies for this wave.
            float timeInterval = Time.time - lastSpawnTime;
            float spawnInterval = waves[currentWave].spawnInterval;
            if (((enemiesSpawned == 0 && timeInterval > timeBetweenWaves) ||
                 timeInterval > spawnInterval) &&
                enemiesSpawned < waves[currentWave].maxEnemies)
            {
                // 3 If necessary, spawn an enemy by instantiating a copy of enemyPrefab. You also increase the enemiesSpawned count.
                lastSpawnTime = Time.time;
                GameObject newEnemy = (GameObject)
                    Instantiate(waves[currentWave].enemyPrefab);
                newEnemy.GetComponent<MoveEnemy>().waypoints = waypoints;
                newEnemy.GetComponent<MoveEnemy>().JiggleWaypoints();
                enemiesSpawned++;
            }
            // 4 You check the number of enemies on screen. If there are none and it was the last enemy in the wave you spawn the next wave.
            // You also give the player 10 percent of all gold left at the end of the wave.
            if (enemiesSpawned == waves[currentWave].maxEnemies &&
                GameObject.FindGameObjectWithTag("Enemy") == null)
            {
                gameManager.Wave++;
                gameManager.Gold = Mathf.RoundToInt(gameManager.Gold * 1.1f);
                enemiesSpawned = 0;
                lastSpawnTime = Time.time;
            }
            // 5 Upon beating the last wave this runs the game won animation.
        }
        else {
            gameManager.gameOver = true;
            GameObject gameOverText = GameObject.FindGameObjectWithTag("GameWon");
            gameOverText.GetComponent<Animator>().SetBool("gameOver", true);
        }
    }
}

第二课

using UnityEngine;
using System.Collections;

public class MoveEnemy : MonoBehaviour
{

    [System.NonSerialized]
    public GameObject[] waypoints;
    private int currentWaypoint = 0;
    private float lastWaypointSwitchTime;
    public float speed = 1.0f;

    // Use this for initialization
    void Start()
    {
        lastWaypointSwitchTime = Time.time;
    }

    // Update is called once per frame
    void Update()
    {
        // 1 
        Vector3 startPosition = waypoints[currentWaypoint].transform.position;
        Vector3 endPosition = waypoints[currentWaypoint + 1].transform.position;
        // 2 
        float pathLength = Vector3.Distance(startPosition, endPosition);
        float totalTimeForPath = pathLength / speed;
        float currentTimeOnPath = Time.time - lastWaypointSwitchTime;
        gameObject.transform.position = Vector3.Lerp(startPosition, endPosition, currentTimeOnPath / totalTimeForPath);
        // 3 
        if (gameObject.transform.position.Equals(endPosition))
        {
            if (currentWaypoint < waypoints.Length - 2)
            {
                // 3.a 
                currentWaypoint++;
                lastWaypointSwitchTime = Time.time;
                RotateIntoMoveDirection();
            }
            else {
                // 3.b 
                Destroy(gameObject);

                AudioSource audioSource = gameObject.GetComponent<AudioSource>();
                AudioSource.PlayClipAtPoint(audioSource.clip, transform.position);
                //<< deduct health
                GameManagerBehavior gameManager =
    GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
                gameManager.Health -= 1;
                //>>
            }
        }
    }

    public void JiggleWaypoints()
    {
        for (int i = 1; i < waypoints.Length; i++)
        {
            waypoints[i].transform.position = new Vector3(waypoints[i].transform.position.x + Random.Range(-3, 3), waypoints[i].transform.position.y + Random.Range(-3, 3), 0);
        }
    }

    private void RotateIntoMoveDirection()
    {
        //1 It calculates the bug’s current movement direction by subtracting the current waypoint’s position from that of the next waypoint.
        Vector3 newStartPosition = waypoints[currentWaypoint].transform.position;
        Vector3 newEndPosition = waypoints[currentWaypoint + 1].transform.position;
        Vector3 newDirection = (newEndPosition - newStartPosition);
        //2 It uses Mathf.Atan2 to determine the angle toward which newDirection points, in radians, assuming zero points to the right.
        // Multiplying the result by 180 / Mathf.PI converts the angle to degrees.
        float x = newDirection.x;
        float y = newDirection.y;
        float rotationAngle = Mathf.Atan2(y, x) * 180 / Mathf.PI;
        //3 Finally, it retrieves the child named Sprite and rotates it rotationAngle degrees along the z-axis.
        // Note that you rotate the child instead of the parent so the health bar — you’ll add it soon — remains horizontal.
        GameObject sprite = (GameObject)
            gameObject.transform.FindChild("Sprite").gameObject;
        sprite.transform.rotation =
            Quaternion.AngleAxis(rotationAngle, Vector3.forward);
    }

    public float distanceToGoal()
    {
        float distance = 0;
        distance += Vector3.Distance(
            gameObject.transform.position,
            waypoints[currentWaypoint + 1].transform.position);
        for (int i = currentWaypoint + 1; i < waypoints.Length - 1; i++)
        {
            Vector3 startPosition = waypoints[i].transform.position;
            Vector3 endPosition = waypoints[i + 1].transform.position;
            distance += Vector3.Distance(startPosition, endPosition);
        }
        return distance;
    }
}

代码100%正常工作,没有错误,但.... 在每个spawn之后,所有对象都获得相同的waypoint数组。这可以在屏幕上看到,因为每次生成新对象时,所有对象都会一起跳转到新的航点。我希望已经生成的对象能够使用它自己的数组,只有一次创建的航点。

2 个答案:

答案 0 :(得分:2)

每次从预制对象创建一个航点时,您需要创建一个新的航点数组。您没有显示Instantiate方法,但我猜它有这样一行:

this.waypoints = prefab.waypoints;

这意味着您创建的所有对象将共享相同的航点列表(如您所发现的那样)。

你需要的是这样的 - 假设航路点有X,Y和Z属性):

this.waypoints = new GameObject[5];
for (int i = 0; i++ ; i < 5)
{
    this.waypoints[i].X = prefab.waypoints[i].X;
    this.waypoints[i].Y = prefab.waypoints[i].Y;
    this.waypoints[i].Z = prefab.waypoints[i].Z;
}

(如果您希望您的积分是可变长度,您可能需要考虑使用列表)。

这意味着每个对象都有一个唯一点列表,即使它们以相同的值开头,您可以单独更改它们。

答案 1 :(得分:0)

基于ChrisFs&#39;和Joe Blows&#39;答案,在MoveEnemy脚本中执行类似的操作:

private Vector3[] myWay;

public void JiggleWaypoints(GameObject[] waypoints)
{
    myWay = new Vector3[waypoints.Length];
    for(int i = 1; i < waypoints.Length; i++)
    {
        myWay[i] = new Vector3(waypoints[i].transform.position.x + Random.Range(-3, 4), waypoints[i].transform.position.y + Random.Range(-3, 4), 0);
    }
}

myWay取代GameObject[]

SpawnEnemy脚本中执行此操作:

GameObject e = (GameObject)Instantiate(enemyPrefab);
e.GetComponent<MoveEnemy>().JiggleWaypoints(waypoints);