团结的承诺

时间:2014-05-24 10:47:09

标签: c# unity3d unityscript

我想要一个Character类,继承MonoBehavior并暴露少数方法:Walk,Attack,......

但是,假设两个组件同时使用这些方法,我想对操作进行排队,并通过某种方式通知组件他们的操作已被执行。

在Javascript标准中,我会做这样的事情:

var Character = function ( ) {
    this._deferred = new Deferred( );
};

Character.prototype.walk = function ( ) {
    return this._deferred = this._deferred.then( function ( ) {
        // Do the actual walk
    } );
};

Character.prototype.attack = function ( ) {
    return this._deferred = this._deferred.then( function ( ) {
        // Do the actual attack
    } );
};

var character = new Character( );

// Component A
character.walk( ).then( function ( ) {
    // Executes when the walk is done
} );

// Component B
character.attack( ).then( function ( ) {
    // Executes when the walk AND attack is done
} );

Unity / C#的正确方法是什么?

2 个答案:

答案 0 :(得分:5)

序言

  1. 对于答案,我将使用此“我想将操作排队”作为您问题的描述。
  2. 有很多方法可以解决这个问题。而且我并不假装是全面的。
  3. 即使在JS中,我也会考虑使用Promises将字符命令排队作为错误的选择。
  4. 我没有编译,运行或测试我在这里提供的代码:D
  5. C#中的承诺

    github上有some C# port of Promises。我从来没有使用它,但代码似乎没有任何阻止它在Unity中使用的东西。无论如何,你可以尝试一下。

    使用Queue<>

    我肯定会使用某些TCommand的Queue<TCommand>来解决这个问题。唯一的问题是如何使用TCommand。我会在这里举两个例子。但是,像往常一样,有更多的选择。

    某些课程

    这样的事情:

    public enum CommandUpdateResult
    {
        Ongoing,
        Finished
    }
    
    public interface ICommand
    {
       CommandUpdateResult Update();
    }
    
    public class RunCommand: ICommand
    {
        // Bla-bla-bla
    }
    
    public class AttackCommand: ICommand
    {
        // Bla-bla-bla
    }
    
    
    public class Character: MonoBehaviour
    {
        private Queue<ICommand> commandQueue;
    
        public void Awake()
        {
            commandQueue = new Queue<ICommand>();
        }
    
        public void Update()
        {
            if (commandQueue.Count > 0 && commandQueue.Peek().Update() == CommandUpdateResult.Finished)
                commandQueue.Dequeue();
        }
    
        public void EnqueueCommand(ICommand command)
        {
            commandQueue.Enqueue(command);
        }
    }
    
    public class SomeClassThatUsesCharacter
    {
        private Character character;
        public void SomeMethodThatUsesCharacter()
        {
            character.EnqueueCommand(new RunCommand(bla-bla-bla));
            character.EnqueueCommand(new AttackCommand(bla-bla-bla));
        }
    }
    

    的IEnumerator

    使用IEnumerator最简单(但不是很优雅)的方法是使用一些无限coroutine

    public class Character: MonoBehaviour
    {
        private Queue<IEnumerator> commandQueue;
    
        private IEnumerator CommandQueueCoroutine()
        {
            while (true)
            {
                if (commandQueue.Count > 0)
                    yield return StartCoroutine(commandQueue.Peek());
                else
                    yield return new WaitForFixedUpdate();
            }
        }
    
        public void Awake()
        {
            commandQueue = new Queue<ICommand>();
            StartCoroutine(CommandQueueCoroutine());
        }
    
        public void Update()
        {
            if (commandQueue.Count > 0 && commandQueue.Peek().Update() == CommandUpdateResult.Finished)
                commandQueue.Dequeue();
        }
    
        public void Enqueue(IEnumerator command)
        {
            commandQueue.Enqueue(command);
        }
    
        IEnumerator RunCommand()
        {
            while (Jenny.Tells("Run"))
            {
                transform.position.x += 1;
                yield return new WaitForFixedUpdate();
            }
        }
    
        IEnumerator AttackCommand(BadGuy badGuy)
        {
            badGuy.Die();
            yield break;
        }
    }
    
    public class SomeClassThatUsesCharacter
    {
        private Character character;
    
        public void SomeMethodThatUsesCharacter()
        {
            character.Enqueue(character.RunCommand());
            character.Enqueue(character.AttackCommand(someBadGuy));
        }
    }
    

答案 1 :(得分:2)

非常好的Unity Promise库:https://github.com/Real-Serious-Games/C-Sharp-Promise并查看相关博客http://www.what-could-possibly-go-wrong.com/promises-for-game-development/

另外,我认为您也可以使用Observers对WalkAttack事件作出反应的RX方法。见https://github.com/neuecc/UniRx