在Update()XNA / C#期间运行一次事件

时间:2014-07-10 13:38:13

标签: c# xna

这是我能想到的最佳方式。你能否给我这样的提示:这是否是正确的方法,或者是否有更有效的方式。

我的情况是: 每次帧都是Update()'ed(就像在XNA中一样)我想检查是否发生了某些事情。就像该屏幕的计时器已经运行超过2000毫秒一样。但我只想要它一次,而不是每次更新帧。这会导致问题:

if(totalMilliseconds > 2000)
{
    this.Fader.FadeIn();
}

所以我想出了我在GameScreen类中实现的这个方法,如下所示:

public bool RunOnce(string Alias, bool IsTrue)
{
    if (!this.Bools.ContainsKey(Alias))
        this.Bools.Add(Alias, false);

    if (IsTrue && !this.Bools[Alias])
    {
        this.Bools[Alias] = true;
        return true;
    }
    else
        return false;
}

这基本上检查传递的if语句boolean是否为true,如果是,则它会触发一次而不是再次触发,除非将Bool [“Alias”]设置回false。我这样用它:

if(this.RunOnce("fadeInStarted", totalMilliseconds > 2000))
{
    this.Fader.FadeIn();
}

这将只运行一次,我认为代码很容易阅读。

我发布这个的原因有两个原因。首先是因为我想表明我是如何克服这个问题的,因为它可能对那些遇到同样问题的人有所帮助。其次是看我是否有错过了一种明显的方法,没有为它创建一个手动方法,或者它可以更有效地完成。

2 个答案:

答案 0 :(得分:0)

你的方法很有趣,我没有看到它的问题,你基本上创建了一个新的编程结构。

我没有遇到过这种情况,所以在这种情况下我所做的总是从不整洁的方法开始:

bool _hasFadedIn = false;

if(totalMilliseconds > 2000 && !_hasFadedIn)
{
    this.Fader.FadeIn();
    _hasFadedIn = true;
}

90%的时间我都是这样离开的。如果班级开始变得太大,我只会改变一些事情。那我要做的是:

_faderControl.Update(totalMilliseconds);

将推子控制的逻辑放入一个单独的类中,所以:

class FaderControl
{
   bool _hasFadedIn=false;
   public void Update(int totalMilliseconds)
   {
       if (_hasFadedIn)
            return;
       if (totalMilliseconds <= 2000)
            return;
       this.Fader.FadeIn();
       _hasFadedIn=true;
   }
}

可对其进行修改以使其可配置,例如重置,设置“开始”,“结束”,淡出时间或控制淡出。

答案 1 :(得分:0)

以下是我如何解决这个问题。

这些是您的要求:

  1. 您希望在Update()
  2. 中执行任意逻辑
  3. 有问题的逻辑有一个与之关联的谓词,用于确定操作是否可以执行。
  4. 该动作最多应执行一次。
  5. 这里的核心概念是“带有关联谓词的动作”,因此创建一个代表该概念的数据结构:

    public class ConditionalAction
    {
        public ConditionalAction(Action action, Func<Boolean> predicate)
        {
            this.Action = action;
            this.Predicate = predicate;
        }
        public Action Action { get; private set; }
        public Func<Boolean> Predicate { get; private set; }
    }
    

    现在,您的示例变为

    var action = new ConditionalAction(
        () => this.Fader.FadeIn(), 
        () => totalMilliseconds > 2000);
    

    Update()中,您需要能够执行这些条件操作的内容:

    public void Update(GameTime time)
    {
        // for each conditional action that hasn't run yet:
        //     check the action's predicate
        //     if true:
        //         execute action
        //         remove action from list of pending actions
    }
    

    因为它们的谓词可能不相关,所以操作不一定按顺序运行。所以这不是一个简单的行动队列。它是一个操作列表,可以从中以任意顺序删除操作。

    为了演示这个概念,我将把它作为一个链表来实现,但这可能不是在生产代码中实现它的最好方法。链接列表在托管堆上分配内存,这通常是XNA中要避免的。然而,为此目的提出一个更好的数据结构是最好留一天的练习。

    private readonly LinkedList<ConditionalAction> pendingConditionalActions = 
        new LinkedList<ConditionalAction>();
    
    public void Update(GameTime time)
    {
        for (var current = pendingConditionalActions.First; current != null; current = current.Next)
        {
            if (current.Value.Predicate())
            {
                current.Value.Action();
                pendingConditionalActions.Remove(current);
            }
        }
    }
    
    public void RegisterConditionalAction(ConditionalAction action)
    {
        pendingConditionalActions.AddLast(action);
    }
    

    注册的操作将等到其谓词变为真,此时它们将被执行并从待处理操作列表中删除,确保它们只运行一次。