当前位置: 首页 > 知识库问答 >
问题:

C++SFML冲突不准确

颜熙云
2023-03-14

我正在用C++的SFML制作一个2D游戏,我有一个冲突的问题。我有一个玩家和一张用瓷砖做的地图。不起作用的是我的碰撞检测不准确。当我将玩家向上移动然后向下移动到瓷砖上时,结果会有所不同。

我知道这个问题的根源可能是在计算球员移动时使用帧间的delta时间--所以它不是恒定的。但它平滑了运动,所以我不知道如何做它的其他方式。我试着用定速阀来使碰撞完全准确--速度必须非常低,我对此不满意。

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

在玩家位置更新中,我创建了未来的精灵对象,它是应用移动后的对象,以获取它的边界并将它传递给碰撞检查器。到冲突检查器我也传递玩家pos,因为我的地图存储在二维数组的瓷砖指针,所以我只检查这些在玩家范围。

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

Github上的完整项目

我已经将update函数中的if语句更改为while语句,这将减小我的偏移量,直到不存在冲突。我还是要做一些调整,但大意是:

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和偏移量矢量,这样它就可以自己计算边界了。

共有1个答案

酆阳煦
2023-03-14

当玩家与一个瓷砖碰撞时,你应该计算穿透,即“玩家进入瓷砖的多少”的值。当你有这个值的时候,把你的玩家往后推那么多。

 类似资料:
  • 我目前正在用SFML制作一个2D rpg游戏,我正在尝试让玩家与某些瓷砖碰撞。我已经达到了玩家可以与我想要的瓷砖碰撞的程度,也可以通过下面的代码沿墙滑动: 它所做的基本上是迭代每一个实体,并测试玩家是否与其中任何一个实体相交。如果有交叉,玩家会回到他们之前没有碰撞时的位置。 我有的主要问题是,当我同时按两个方向(例如,在向右和向上移动时与右边的墙相撞)时,玩家会陷入僵局,因为它正在重置x和y坐标。

  • 所以,最近我开始用C和SFML制作一个Pacman克隆。开发游戏时一切都很顺利,直到我需要创建墙碰撞。我不擅长碰撞,所以我以为会有问题。 我想做的是检查你上方是否有一堵墙,除了你或其他什么,然后如果你与一堵墙相撞,阻止玩家。 问题是,当你撞到墙时,你很早就停下来了。有时你会陷入困境。这并不是要与代码混淆,因为代码使Pacman在你身上有一堵墙的时候不能转身,而是在遇到墙的时候停下来。 这是我刚才提

  • 现在这种情况仍然发生,但很少发生,就像100次碰撞中有1次发生,而在100次碰撞中有20次发生之前

  • 我正在尝试为我的大学工作制作一个基于2D平台的游戏(在SFML)。我不是要求任何人为我编写一些代码,但如果有人能提供一些指示,我将非常感激:) 目前我有大约13门课,包括: BaseEntity(大多数游戏对象都是由此派生的) 玩家(继承自BE) 魔法宝石(玩家需要这些来通过关卡晋级) 平台 SolidBlock(从平台继承) 可以说,我已经构建了大部分的游戏“积木”--每个类都有自己的更新函数,

  • 小雪再 pull 的时候遇到了冲突。 → git pull --rebase remote: Counting objects: 3, done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0 Unpacking objects

  • C STLunordered_map如何解决冲突? 看着http://www.cplusplus.com/reference/unordered_map/unordered_map/,它说“唯一的键容器中的两个元素不能有相同的键。” 这意味着容器确实在解决碰撞。然而,那一页并没有告诉我它是如何做到的。我知道一些解决冲突的方法,比如使用链表和/或探测。我想知道的是c STL无序_映射是如何解决它的。