【问题标题】:Executing method only after another one completes只有在另一个完成后才执行方法
【发布时间】:2020-10-23 22:26:07
【问题描述】:

我正在制作一个棋盘游戏原型,它有 20 个“方块”,当按下空格键时,敌方角色一次跳一个方块(从 1 到 20)。如果敌人成功阻挡了 20 - 它就是胜利者。

每个方块都有不同的障碍物,敌人可能会被冻结、燃烧、困住、融化、传送等。有些方块可能有多个这些障碍。

我要做的是为每个障碍物创建一个单独的类,并使用.AddComponent<> 将它们添加到不同的块中。当敌人降落在一个方块上时,该方块会穿过该方块上添加的障碍物并相应地惩罚敌人。

这是块预制类:

public class CompositeBlock : MonoBehaviour{
    void Start(){
        gameObject.AddComponent<ActionFreeze>();
        gameObject.AddComponent<ActionTrap>();
    }

    // This is called when enemy steps on the block
    public void ExecuteActions(Enemy enemy){
        Debug.Log("Enemy has landed on this block");
        IBlockAction[] actionArray = GetComponents<IBlockAction>();
        foreach(IBlockAction action in actionArray){
            action.Execute(enemy);
        }
    }
}

以下是可以对敌人执行“动作”的类。现在假设方块只能冻结或困住敌人:

public interface IBlockAction{
    void Execute(Enemy enemy);
    void OnActionComplete();
}

public class ActionFreeze : MonoBehaviour, IBlockAction{
    public void Execute(Enemy enemy){
        Debug.Log("Freezing Enemy");
        enemy.Freeze(); // Change enemy's sprite to frozen
        Invoke("OnActionComplete", 2f); // Wait for 2 seconds
    }

    public void OnActionComplete(){
        Debug.Log("Freeze completed");
    }
}

public class ActionTrap : MonoBehaviour, IBlockAction{
    public void Execute(Enemy enemy){
        Debug.Log("Trapping Enemy");
        enemy.Trap(); // Change enemy's sprite to trapped
        Invoke("OnActionComplete", 3f); // Wait for 3 seconds
    }

    public void OnActionComplete(){
        Debug.Log("Trap completed");
    }
}

这按预期工作,但由于 ExecuteActions 有一个 for 循环,所有操作都会立即执行。敌人的“冰冻”精灵将完全不可见,因为下一个动作会立即执行。日志如下所示:

Enemy has landed on this block
Freezing Enemy
Trapping Enemy
Freeze completed
Trap completed

如何在调用当前动作的OnActionComplete()之后才调用下一个动作的.Execute(),使敌人的“冰冻”精灵显示2秒,然后敌人的精灵变为“被困”,然后显示 3 秒。日志应如下所示:

Enemy has landed on this block
Freezing Enemy
Freeze completed
Trapping Enemy
Trap completed

显示精灵的持续时间(冻结或捕获)并不重要,因为可以播放动画来代替精灵变化。无论敌人(被冻结或被困)状态如何显示 - OnActionComplete() 都应在完成后调用。

【问题讨论】:

  • @Fattie CompositeBlock 最终将成为一个预制件——我当然不会在不先将它们做成预制件的情况下复制/粘贴这 20 个块中的每一个:D。我已经更新了问题,以便更清楚。
  • @Fattie 我认为这非常适合统一。通过这种方式,我可以创建ActionMeltActionTeleportActionKillActionShrink 等类,然后通过执行gameObject.AddComponent&lt;ActionTeleport&gt;() 等将它们添加到不同的块预制件中。这些操作将在当敌人落在那个方块上时!
  • @Fattie 我认为“freezeEnemy”内部发生的事情无关紧要,因为即使没有调用该方法,日志也会输出相同的日志序列。
  • 啊!我想我终于明白 ypiur'e 在问@yeti 什么了!团结起来很容易..
  • 请注意,在几乎所有 Unity 项目中,您的 enemy.Trap() 几乎肯定是协程。任何需要时间的东西都是协程!顺便说一句,您可能会喜欢使用 Tweeng​​b> 这是一个简单的扩展。它在很大程度上消除了几乎所有简单的动画(音频、位置等)stackoverflow.com/a/37228628/294884

标签: unity3d


【解决方案1】:

你只是等待这样的协程..

同时进行:

StartCoroutine(A());
StartCoroutine(B());
StartCoroutine(C());
StartCoroutine(D());

一个接一个,按顺序做:

yield return StartCoroutine(A());
yield return StartCoroutine(B());
yield return StartCoroutine(C());
yield return StartCoroutine(D());

这是一个完整的粘贴示例

using UnityEngine;
using System.Collections;
public class Examp : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(Test());
    }
    IEnumerator Test()
    {
        yield return StartCoroutine(A());
        yield return StartCoroutine(B());
        yield return StartCoroutine(C());
    }

    IEnumerator A()
    {
        yield return new WaitForSeconds(1f); Debug.Log("..A");
    }
    IEnumerator B()
    {
        yield return new WaitForSeconds(1f); Debug.Log("..B");
    }
    IEnumerator C()
    {
        yield return new WaitForSeconds(1f); Debug.Log("..C");
    }
}

【讨论】:

  • 我已经更新了这个问题,这样就更清楚了。我确实使用协程,但我不确定在这种情况下如何使用它。
  • 幸运的是,这很容易,我已经回答了@yeti!欢呼
  • @Yeti ,注意我的电话Test() 有时人们会费心制作一个堆栈(或您喜欢的 C# 中的任何功能)以按顺序调用的项目。真的,我发现在大多数游戏中,最好在例程中明确地写出来,例如TakeOffSequenceWinSequence 或其他。几乎所有游戏都有许多看起来像“测试”的调用来表达一系列发生的事情!干杯
猜你喜欢
  • 1970-01-01
  • 2020-08-16
  • 1970-01-01
  • 1970-01-01
  • 2018-09-23
  • 2013-02-27
  • 1970-01-01
  • 2018-06-01
  • 1970-01-01
相关资源
最近更新 更多