循环检查苹果的位置与蛇的身体位置

Loop to check apple position against snake body positions

本文关键字:位置 检查 循环 苹果      更新时间:2023-10-16

我正试图弄清楚如何编写一个循环来检查圆形相对于可变数量的矩形的位置,这样苹果就不会放在蛇的顶部,但我有一点麻烦思考它。我试着:

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

虽然,在这种情况下,如果它检测到与蛇身体的一个矩形的碰撞,它最终可能只是把苹果放在身体的前一个位置。我如何让它同时检查所有的位置,这样它就不会自我修正只是为了有机会再次重复同样的问题?

有三种方法(我能想到的)生成满足需求的随机数:

  • 第一种方法,也是最简单的方法,就是你想要做的:如果没有重试。
    但是,您应该更改条件,以便它立即检查所有禁止的单元格:

    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

  • 第三种方法是"欺骗",选择一个更强的要求,更容易执行。例如,如果你知道细胞体是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();

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

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
        }
    }
}

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