gpt4 book ai didi

C++ SFML 碰撞不准确

转载 作者:太空狗 更新时间:2023-10-29 22:59:42 25 4
gpt4 key购买 nike

我正在使用 C++ 中的 SFML 制作 2D 游戏,但我遇到了碰撞问题。我有一个播放器和一张由瓷砖制成的 map 。不起作用的是我的碰撞检测不准确。当我将玩家向上然后向下移动到瓷砖时,结果会有所不同。

Player very high above tile Player above tile Player standing on tile

我知道这个问题的根源可能是使用帧之间的增量时间来计算玩家移动 - 所以它不是恒定的。但它可以平滑运动,所以我不知道如何以其他方式进行。我尝试使用恒定速度值并使碰撞完全准确 - 速度必须非常低,我对此并不满意。

void Player::move() {
sf::Vector2f offsetVec;

if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
offsetVec += sf::Vector2f(0, -10);

if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
offsetVec += sf::Vector2f(0, 10);

if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
offsetVec += sf::Vector2f(-10, 0);

if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
offsetVec += sf::Vector2f(10, 0);

this->moveVec += offsetVec;
}

void Player::update(float dt, Map *map) {
sf::Vector2f offset = sf::Vector2f(this->moveVec.x * this->playerSpeed * dt,
this->moveVec.y * this->playerSpeed * dt);
sf::Sprite futurePos = this->sprite;
futurePos.move(offset);
if (map->isCollideable(this->pos.x, this->pos.y, futurePos.getGlobalBounds())) {
this->moveVec = sf::Vector2f(0, 0);
return;
}
this->sprite.move(offset);
this->pos += offset;
this->moveVec = sf::Vector2f(0, 0);
return;
}

player position update 中,我创建了 future sprite 对象,这是应用移动后的对象,以获取它的边界并将其传递给碰撞检查器。对于碰撞检查器,我还传递了玩家位置,因为我的 map 存储在 2d 瓦片指针数组中,所以我只检查玩家范围内的这些。

bool Map::isCollideable(float x, float y, const sf::FloatRect &playerBounds) {
int startX = int(x) / Storage::tileSize;
int startY = int(y) / Storage::tileSize;
Tile *tile;
for (int i = startX - 10; i <= startX + 10; ++i) {
for (int j = startY - 10; j <= startY + 10; ++j) {
if (i >= 0 && j >= 0) {
tile = getTile(i, j);
if (tile != nullptr && playerBounds.intersects(tile->getGlobalBounds()))
return true;
}
}
}
return false;
}

Full project on Github

我的解决方案

我已将更新函数中的 if 语句更改为 while 语句,这会减少我的偏移 vector ,直到不存在碰撞为止。我仍然需要做一些调整,但总体思路是:

void Player::update(float dt, Map *map) {
int repeats = 0;
sf::Vector2f offset = sf::Vector2f(this->moveVec.x * this->playerSpeed * dt,
this->moveVec.y * this->playerSpeed * dt);
sf::Sprite futurePos = this->sprite;
while (map->isCollideable(this->pos.x, this->pos.y, futurePos, offset)) {
offset = 0.7f * offset;
repeats++;
if (repeats > 5) {
this->moveVec = sf::Vector2f(0, 0);
return;
}
}
this->sprite.move(offset);
this->pos += offset;
this->moveVec = sf::Vector2f(0, 0);
return;
}

我还必须稍微修改 isCollideable 方法,使其接受 sf::Sprite 和偏移 vector ,以便它可以自行计算边界。

最佳答案

当玩家碰撞到瓦片时,你应该计算穿透力,即“玩家进入瓦片多少”的值。当您拥有此值时,将您的播放器推回那么多。

关于C++ SFML 碰撞不准确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36154187/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com