【问题标题】:Change movement of a instantiated GameObject from next instantiation从下一个实例化更改实例化游戏对象的移动
【发布时间】:2018-07-15 06:34:33
【问题描述】:

我正在使用 Unity 和 C#。

在我的游戏中,敌人被反复实例化并以直线路径向玩家移动。我想让敌人在特定时间过去后以正弦波移动,以使游戏更加艰难。

运动会立即改变,但我希望改变从新(下一个)敌人的实例化开始生效,而不是当前存在的敌人。

我能做什么?

EnemySpawner 脚本 -

private void Start()
{
    timeelapsed = 0f;
    StartCoroutine(SpawnEnemies(delay));
}
private void Update()
{
    timeelapsed += Time.deltaTime;
}
private IEnumerator SpawnEnemies(float delay)
{
    while (true)
    {
        SpawnNewEnemy();
        yield return new WaitForSeconds(delay);
    }
}
private void SpawnNewEnemy()
{
    if (!enemyclone)
    {
        enemyclone = Instantiate(enemy, enemySpawner.transform.position + offset, Quaternion.identity);
    }
}

Enemy Movement脚本:

private void Update()
{
    t = Time.time;
    if (EnemySpawner.timeelapsed > 0f && EnemySpawner.timeelapsed <= 20f)
    {
        enemy.transform.Translate(Vector3.forward * speed * Time.deltaTime);
    }
    if (EnemySpawner.timeelapsed > 20f && EnemySpawner.timeelapsed <= 40f)
    {
        enemy.GetComponent<Rigidbody>().velocity = Vector3.forward * 5 + Vector3.left * 3 * Mathf.Sin(10f * t);
    }
}

【问题讨论】:

标签: c# unity3d instantiation game-development gameobject


【解决方案1】:

有一千种方法可以实现这一点,但我认为可能很容易实现和理解的一种方法可能是设置当您从生成器实例化一个新敌人时触发的动作。我很快就对您的 EnemySpawner 和 EnemyMovement 脚本进行了一些更改,我认为这些更改可能会对您有所帮助。

首先,EnemySpawner:

public static event Action EnemySpawning;
void SpawnNewEnemy ( )
{
    if ( !enemyclone )
    {
        EnemySpawning?.Invoke ( );
        enemyclone = Instantiate ( enemy, enemySpawner.transform.position + offset, Quaternion.identity );
    }
}

现在,敌人运动:

private bool travelInLinearPath = true;

private void OnEnable ( )
{
    EnemySpawner.EnemySpawning -= OnEnemySpawning;
    EnemySpawner.EnemySpawning += OnEnemySpawning;
    travelInLinearPath = true;
}

public void OnEnemySpawning( )
{
    EnemySpawner.EnemySpawning-= OnEnemySpawning;
    travelInLinearPath = false;
}

private void Update ( )
{
    if ( travelInLinearPath )
        enemy.transform.Translate ( Vector3.forward * speed * Time.deltaTime );
    else
        enemy.GetComponent<Rigidbody> ( ).velocity = Vector3.forward * 5 + Vector3.left * 3 * Mathf.Sin ( 10f * Time.time );
}

每次启用敌人时,您都会要求在下一个敌人即将生成时得到通知。发生这种情况时,您告诉这个敌人从线性运动变为正弦运动 (travelInLinearPath)。您还要求在生成新敌人时不再通知此敌人(除非您重新启用此敌人)。

我也没有讨论你是否应该从一堆敌人物体中抓住一个新的敌人。但是希望您这样做是我在OnEnable() 中添加删除和重新注册活动的原因。您可能希望/需要将该代码放在 Start() 中,而不是取决于您的敌人实例化和游戏后期的创建。

【讨论】:

  • 我按照你说的做了一切,但是一旦计时器到达 20f,敌人就会停止移动。请注意 1.我在 if 语句中仍然有超时条件 2.Im 使用 C# 4,所以我不得不使用 if staements 而不是 EnemySpawning?.Invoke ( ); .这些是否会导致问题。
  • 您使用的是哪个版本的 Unity?如果您使用 Unity 2017+,您可以(并且应该)将您的框架版本设置为 .Net 4.x。我在 Unity 网站上读到,实际上鼓励使用 .Net Standard 以获得最大的可移植性以及更小的构建大小。然后调用?将正常工作。您能否解释一下我提供的代码是否不正确,或者您希望它执行当前未执行的操作。
  • 我现在切换到 Net 4.6。问题依然存在,当时间达到 20f(我要进行更改的时间)时,敌人停止移动
  • 如果没有删除 if 条件,敌人就会停止移动,但是如果我删除了 if 条件并完全按照您编写的代码编写代码,那么敌人会立即改变移动方式,就像我一开始那样
  • 我现在有点困惑。您的示例中有一个计时器,但您还说您希望在产生新敌人时改变运动。你想要计时器在那里,还是想要在产生新敌人时改变运动?
【解决方案2】:

现在知道请求是针对敌人的“波”,我们需要为每个敌人添加定义波的项目。因此,先修改EnemyMovement脚本:

public class EnemyMovement : MonoBehaviour
{
    public enum MovementType
    {
        None = 0,
        Linear = 1,
        Sinusoidal = 2
        // etc, etcc
    }

    /// <summary>
    /// Movement affects the movement type of the enemy.
    /// </summary>
    public MovementType Movement { get; set; }

    /// <summary>
    /// This affects the Speed of the Enemy. Used in conunction with Movement to
    /// produce the enenmy's wave movement type.
    /// </summary>
    public float Speed { get; set; }

    private Rigidbody rigidBody;


    private void Awake ( )
    {
        rigidBody = GetComponent<Rigidbody> ( );
    }


    private void Update ( )
    {
        switch ( Movement)
        {
            case MovementType.Linear:
                transform.Translate ( Vector3.forward * Speed * Time.deltaTime );
                break;
            case MovementType.Sinusoidal:
                // You probably want the Speed property to affect this as well...
                rigidBody.velocity = Vector3.forward * 5 + Vector3.left * 3 * Mathf.Sin ( 10f * Time.time );
                break;

           // Any extra movement types you want here...
        }

    }
}

然后是 EnemySpawner 脚本来驱动 Enemy 实例化:

public class EnemySpawner : MonoBehaviour
{
    public float Delay;
    public float StartSpeed;

    public GameObject enemy;
    public GameObject enemySpawner;
    public Vector3 offset;

    private float timeElapsed;
    private float currentSpeed;
    private EnemyMovement.MovementType currentMovement;


    void Start ( )
    {
        timeElapsed = 0f;
        currentSpeed = StartSpeed;
        StartCoroutine ( SpawnEnemies ( Delay ) );
        currentMovement = EnemyMovement.MovementType.Linear;
    }


    void Update ( )
    {
        timeElapsed += Time.deltaTime;

        // We can determine at what time the Wave parameters change here.
        if ( timeElapsed >= 40.0f )
        {
            currentSpeed += 10.0f; // Add speed, for example.
        }
        else if ( timeElapsed >= 20.0f )
        {
            currentMovement = EnemyMovement.MovementType.Sinusoidal;
        }
    }


    IEnumerator SpawnEnemies ( float delay )
    {
        while ( true )
        {
            var enemyClone = Instantiate ( enemy, enemySpawner.transform.position + offset, Quaternion.identity );
            var movement = enemyClone.GetComponent<EnemyMovement> ( );

            // We now set what the enemy uses as the Wave values.
            movement.Speed = currentSpeed;
            movement.Movement = currentMovement;

            yield return new WaitForSeconds ( delay );
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多