【问题标题】:How to execute a block only if all previous conditions were false and execute a specific block if one of them was true?仅当所有先前的条件都为假时如何执行一个块,如果其中一个条件为真,如何执行一个特定的块?
【发布时间】:2014-08-07 11:58:45
【问题描述】:

我正在用 C++ 制作一个小游戏,我想知道如何优化我的分支。看这段代码:

if (
  isUpPressed ||
  isDownPressed ||
  isLeftPressed ||
  isRightPressed ||
  isSpacePressed
) {
  if (isUpPressed)
    state |= State::MoveUp;
  if (isDownPressed)
    state |= State::MoveDown;
  if (isLeftPressed)
    state |= State::MoveLeft;
  if (isRightPressed)
    state |= State::MoveRight;
  if (isSpacePressed)
    state |= State::Jump);
} else
  state = State::Still;

我想要实现的是:如果按下了上、下、左、右或空格,则将state设置为适当的值。如果这些条件没有为真,则将状态设置为State::Still。我的代码有效,但感觉好像我做错了。一定会有更好的办法。我的问题是:
如何仅在 所有 指定条件失败时执行块,如果一个或多个条件为真,则执行特定于每个条件的块,而不使用像我一样嵌套if 和很多|| 运算符?

【问题讨论】:

  • 除了冗余。
  • 冗余正是问题所在。
  • 我没有看到冗余。如果我正确理解您的代码,您必须以某种方式将事件映射到状态。
  • 对,但我想检查一个键是否被按下一次且仅一次。不需要检查两次。
  • @filsmick 我认为这是必要的,因为您要问两个不同的问题(“按键”与“按下”)。当然你可以使用向量+哈希图,但最终你会以相同的冗余结束,只是在不同的地方。根据您提供给我们的信息(State::Still == 0,您可以使用 Chnossos 的技巧)我怀疑您可以做得更好。

标签: c++ conditional-statements or-operator


【解决方案1】:

我认为你可以这样做:

state = State::Still;

if (isUpPressed)
  state |= State::MoveUp;
if (isDownPressed)
  state |= State::MoveDown;
if (isLeftPressed)
  state |= State::MoveLeft;
if (isRightPressed)
  state |= State::MoveRight;
if (isSpacePressed)
  state |= State::Jump;

这样,如果没有按下任何键,state 将设置为 Still

如果state 之前不为0,则可以使用meneldal 解决方案,即使用布尔值。

【讨论】:

  • 太棒了!我应该想到这一点。也就是说,它对我来说是完美的,但对于一些更复杂的东西(比如如果没有按下任何键则显示一条消息),它就行不通了。
  • @filsmick 虽然这可能是正确的并且对您有用,但它可能会表现出与您最初发布的不同的行为。
  • 好吧,代码做了不同的事情。至少从 OP 的问题中不清楚当你这样做时会发生什么,例如State::Still | State::MoveUp。不过,我确实同意这是个好主意。
  • 但是如果一个键被按下,与State::Still按位or'ed会是什么结果?
  • @filsmick 这是假设你没有说的State::Still == 0。另外,在这种特殊情况下,它变成了一个技巧,而不是问题的一般解决方案。
【解决方案2】:

如果 State::Still 不是 0,您可以在每个分支中设置一个布尔值。设置布尔值是一项非常快速的操作,因此它可能比您的第一种方法更快。例如

bool still=true;

if (isUpPressed)
  still=false, state |= State::MoveUp;
if (isDownPressed)
  still=false, state |= State::MoveDown;
if (isLeftPressed)
  still=false, state |= State::MoveLeft;
if (isRightPressed)
  still=false, state |= State::MoveRight;
if (isSpacePressed)
  still=false, state |= State::Jump;
if(still)
  state=State::Still;

可能还有嵌套方法,但它非常丑陋,而且性能可能不会更好。

【讨论】:

    【解决方案3】:

    取自 cmets 中的点点滴滴。可能是这样的(假设没有一个运动状态保持值 0)

    State::Value state = State::Value(0);
    if (isUpPressed)
        state |= State::MoveUp;
    if (isDownPressed)
        state |= State::MoveDown;
    if (isLeftPressed)
        state |= State::MoveLeft;
    if (isRightPressed)
        state |= State::MoveRight;
    if (isSpacePressed)
        state |= State::Jump);
    
    if(state == State::Value(0))
        state = State::Still;
    
    if(isOnFire)
        state |= State::Fire;
    

    或者,如果你有更多类似于移动块的代码块,你可以创建一个临时状态变量,以同样的方式处理它并将临时状态和原始状态合并。

    【讨论】:

    • 正是我想要的。如果这件事变得更复杂,我将按照建议使用临时状态。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 2016-05-08
    • 1970-01-01
    • 2014-12-30
    • 2018-01-24
    • 1970-01-01
    相关资源
    最近更新 更多