如果有条件执行

时间:2010-11-22 17:17:50

标签: xna controls if-statement structure

我遇到过在使用IF控制结构之前没有遇到的情况,还有一个嵌套的IF。通常情况下,嵌套的IF会破坏我正在检查的细粒度细节,但在这种情况下,它实际上与外部条件冲突 - 我正在检查鼠标单击。

这是代码 -

if (mouseState.LeftButton == ButtonState.Pressed)
{
     if (mouseState.LeftButton == ButtonState.Released)
     {
          //move sprite to clicked position
          spritePos.X = mouseState.X;
          spritePos.Y = mouseState.Y;
     }
}

我有几个问题。我被告知条件参数只检查一次,如果它的计算结果为true,则执行以下语句。 这是真的,还是在执行块内的每个语句之前实际检查过? - 因为后者显然会导致与我的嵌套if冲突。

如果这是真的,为什么我的按钮点击方法不起作用?精灵永远不会移动,就像鼠标释放永远不会执行一样。 是因为对两个条件执行检查之间的延迟是如此之小,以至于我在这段时间内无法释放按钮?我是否可以对此有点小心,并且克服它时间延迟,这可能足够大,以便在检查嵌套条件时允许释放鼠标按钮?

我看到的鼠标单击操作的方法,使用上一帧中鼠标的属性,并与新帧进行比较以检查鼠标单击。但是这种方法必须引入至少一帧的延迟来实际处理动作。高帧率可能不会引起注意,但仅仅为了论证,我说游戏渲染速度为20fps。在渲染任何帧之前将调用UpdateInput(),位置应该更新,然后帧应该最后渲染。

如果完全鼠标点击操作可以在不到1/20秒的时间内运行,那么不是一次性处理动作而不是在初始按下时存储变量,并比较下一帧中的状态?这肯定比引入进一步的延迟更好。

我确信之前其他人一定已经考虑过这个问题了,也许我并没有正确思考时间延迟操作实际暂停执行代码的问题。 时间延迟会暂停处理器执行代码,还是仅执行这些执行的结果,例如渲染和接受输入?它们不是我有任何使用经验的东西,我可能会混淆延迟是如何工作的。

谢谢你, 安德鲁。

3 个答案:

答案 0 :(得分:2)

哦,这里有太多错误......

if语句块之前,您可能正在做的事情是:

MouseState mouseState = Mouse.GetState();

现在GetState函数实际上决定了鼠标的当前状态并将其打包成MouseState结构。使用=,您将该状态分配到mouseState变量中。

mouseState改变的唯一时间是你自己改变它!所以你的条件看起来像这样:

if (mouseState.LeftButton == ButtonState.Pressed) {
    if (mouseState.LeftButton == ButtonState.Released) { /* "do stuff" */ }
}

你正在检查mouseState.LeftButton是否等于两个完全不同的东西!显然,“做东西”永远不会运行。

现在问题的另一部分我可以通过使代码按照您认为的方式工作来说明它应该有效:

if (Mouse.GetState().LeftButton == ButtonState.Pressed) {
    // Some kind of delay, perhaps?
    if (Mouse.GetState().LeftButton == ButtonState.Released) { /* "do stuff" */ }
}

因此每次检查时都会更新状态。

现在这是此代码的问题。您的鼠标必须在两个if语句之间从“Pressed”状态转换为“Released”状态。如果没有,则不会触发条件。

增加延迟时间不会因为多种原因而解决:首先,实际运行游戏需要时间。其次,不可能将它增加到帧时间的100% - 所以总是有一个百分比几率你的情况不会触发。

因此,处理输入的更好方法是跟踪帧之间的状态 。正如所有教程演示的那样,最好的方法是在调用MouseState lastMouseState;函数之间存储Update。所以你的代码应该是这样的:

MouseState mouseState = Mouse.GetState();
if (lastMouseState.LeftButton == ButtonState.Pressed)
{
    if (mouseState.LeftButton == ButtonState.Released)
    {
        /* "do stuff" */
    }
}
lastMouseState = mouseState;

现在,您可能会说,这仍然会让您首先看到您提到的实际问题:如果使用点击过快以致鼠标状态发生变化,然后在调用{{1}之间切换回来}吗

嗯 - 我对此的第一反应是“不要担心”。这个 XNA输入框架的已知问题。但在实践中,您会发现人们通常不会快速点击或打字,这会导致60FPS的实际问题。

如果您的游戏吸引力远低于60FPS,您仍可以60FPS运行更新。要降低您的提款率,您可以使用GetState或使Game.SupressDraw返回false(请参阅herehere)。如果您还需要以低于60FPS的速度运行更新,您仍然可以以60FPS(或更快!)更新输入,但这需要更多工作。 (请注意,XNA输入需要在主线程上完成。)

(就我个人而言,我建议你只需要60FPS,然后再担心它!)

最后,如果这对你来说还不够,你可以搞乱使用互操作并挂钩消息泵并捕获Game.BeginDraw消息。这是一种巨大的矫枉过正,但却是获得你想要的“正确”方式。

答案 1 :(得分:1)

Andrew,你的问题与if语句的工作方式无关。 mouseState表示调用GetState()时鼠标的状态。它不会因为鼠标改变状态而改变。为了使代码片段能够像您期望的那样工作,您必须在每个if语句之前调用GetState()。鼠标状态仅在您轮询或手动设置时更改。

答案 2 :(得分:-1)

它不起作用,因为如果按左键,则在程序检查if (mouseState.LeftButton == ButtonState.Released)条件之前无法释放它。

  

时间延迟会暂停处理器   执行代码

鼠标和键盘的输入延迟不明显。

我使用变量来存储每帧的左按钮状态:

while (1) // ininity loop
{
    if (mouseState.LeftButton == ButtonState.Pressed)
    {
         button_left_pressed = 1; // is pressed
    }
    else // Left Button is not pressed
    {
         if ( button_left_pressed ) // but was pressed (is released)
         {
             spritePos.X = mouseState.X;
             spritePos.Y = mouseState.Y;
             button_left_pressed = 0; // is not pressed
         }
    }
    // do another action        
}