循环检查苹果位置与蛇 body 位置的对比

Loop to check apple position against snake body positions

我想弄清楚如何编写一个循环来检查圆圈相对于可变数量的矩形的位置,以便苹果不会放在蛇的顶部,但我有一点想通它的麻烦。我试过了:

do 
   apple.setPosition(randX()*20+10, randY()*20+10); // apple is a CircleShape
while (apple.getPosition() == snakeBody[i].getPosition());

不过,在这种情况下,如果它检测到与蛇 body 的一个矩形发生碰撞,它最终可能只是将苹果放在 body 的先前位置。我如何让它同时检查所有位置,使其无法自我纠正,才有机会再次重复同样的问题?

生成满足要求的随机数有3种方式(我能想到):

  • 第一种方法,也是您要尝试做的更简单的方法:如果不成功,请重试。
    但是,您应该更改条件,以便它一次检查所有禁止的单元格:

    bool collides_with_snake(const sf::Vector2f& pos, //not sure if it's 2i or 2f
                             const /*type of snakeBody*/& snakeBody,
                             std::size_t partsNumber) {
      bool noCollision = true;
      for( std::size_t i = 0 ; i < partsNumber && noCollision ; ++i )
        noCollision = pos != snakeBody[i].getPosition()
      return !noCollision;
    }
    
    //...
    do 
      apple.setPosition(randX()*20+10, randY()*20+10);
    while (collides_with_snake(apple.getCollision(), snakeBody,
                               /* snakeBody.size() ? */));
    
  • 第二种方法是尝试生成较少的数字并找到一个函数将这些数字映射到您想要的集合。例如,如果您的网格有 N 个单元格,您可以生成一个介于 0N - [number of parts of your Snake] 之间的数字,然后将此数字 X 映射到最小的数字 Y 这样这个整数不是指被蛇部分占据的单元格,X = Y + S 其中 S 是被小于 Y 的数字引用的蛇部分占据的单元格数。 =32=] 不过比较复杂。

  • 第三种方法是"cheat",选择更容易执行的更强的要求。例如,如果您知道细胞体的长度为 N 个细胞,则只在距离蛇头 N + 1 个细胞的细胞上生成苹果(您可以通过生成角度来做到这一点) .

问题很宽泛,但假设 snakeBodyRectangles 的向量(或从矩形派生),并且您有一个 checkoverlap() 函数:

do {
   // assuming that randX() and randY() allways return different random variables
   apple.setPosition(randX()*20+10, randY()*20+10); // set the apple
  } while (any_of(snakeBody.begin(), snakeBody.end(), [&](Rectangle &r)->bool { return checkoverlap(r,apple); } );  

这依赖于标准算法 any_of() 来检查一个简单的表达式是否有任何蛇体元素与苹果重叠。如果有重叠,我们就再次迭代并获得一个新的随机位置,直到它好为止。

如果 snakebody 是数组而不是标准容器,只需在上面的代码中使用 snakeBody, snakeBody+snakesize 而不是 snakeBody.begin(), snakeBody.end()

如果重叠检查就像比较位置一样简单,您可以将上面代码中的 return checkoverlap(r,apple); 替换为 return r.getPosition()==apple.getPosition();

"naive" 方法是生成苹果并测试它们对整条蛇的位置,直到我们找到一个空闲位置:

bool applePlaced = false;
while(!applePlaced) { //As long as we haven't found a valid place for the apple
    apple.setPosition(randX()*20+10, randY()*20+10);
    applePlaced = true;  //We assume, that we can place the apple
    for(int i=0; i<snakeBody.length; i++) { //Check the apple position with all snake body parts
        if(apple.getPosition() == snakeBody[i].getPosition()) {
            applePlaced=false;  //Our prediction was wrong, we could not place the apple
            break; //No further testing necessary
        }
    }
}

更好的方法是将所有空闲位置存储在一个数组中,然后从该数组中选择一个位置(并将其从数组中删除),这样就不需要随机测试了。如果蛇移动,它还需要更新数组。