如何在SFML中实现基于网格的移动?

时间:2018-03-28 17:10:08

标签: c++ c++14 sfml

我无法在SFML中获得良好的32x32基于网格的移动,并需要一些帮助来确定如何使其工作。这是我到目前为止所得到的:

void player::updateMovement()
{
if(walkFinish) {
    pixelWalked = 0;
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
        direction = 1; // direction set to up

        EndYPos = GetPosition().y - 32; // The position the character is moving towards.

        walkFinish = false;
    } else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) && canMoveRight) {
        direction = 2; // Right

        EndXPos = GetPosition().x + 32;

        walkFinish = false;
    } else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
        direction = 3; // Down

        EndYPos = GetPosition().y + 32;

        walkFinish = false;
    } else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
        direction = 4; // Left

        EndXPos = GetPosition().x - 32;

        walkFinish = false;
    }
} else if(!walkFinish && direction > 0 && direction < 5) { // if walk is not finished, move character.
    if(direction == 1 && !(EndYPos == GetPosition().y)){ // Up
        rect.move(0, -movementSpeed);

    } else if(direction == 2 && !(EndXPos == GetPosition().x) && canMoveRight) { // Right
        rect.move(movementSpeed, 0);

    } else if(direction == 3 && !(EndYPos == GetPosition().y)) { // Down
        rect.move(0, movementSpeed);

    } else if(direction == 4 && !(EndXPos == GetPosition().x)) { // Left
        rect.move(-movementSpeed, 0);
    }
}

if( ((EndXPos == GetPosition().x) && (EndYPos == GetPosition().y)) && !(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) && !(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) && !(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) && !(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) ) {
    walkFinish = true; // if character has reached endpos in both axis, walkFinish becomes true
} else if( ((EndXPos == GetPosition().x) && (EndYPos == GetPosition().y))) { // This gets rid of a 1 frame character pause and makes the movement smoother
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
        direction = 1; // direction set to up
        EndYPos = GetPosition().y - 32; // Same deal as the first if statement of this function.
    } else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) && canMoveRight) {
        direction = 2;
        EndXPos = GetPosition().x + 32;

    } else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
        direction = 3;
        EndYPos = GetPosition().y + 32;

    } else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
        direction = 4;
        EndXPos = GetPosition().x - 32;

    }

}
}

和我的碰撞检查:

counter = 0;
for(iterWall = wallArray.begin(); iterWall != wallArray.end(); iterWall++) {
    if(objectPlayer.rect.getPosition().x == (wallArray[counter].rect.getPosition().x + 64)) {
        objectPlayer.canMoveLeft = false;
    } else if(objectPlayer.rect.getPosition().x == (wallArray[counter].rect.getPosition().x - 64)) {
        objectPlayer.canMoveRight = false;
    } else if(objectPlayer.rect.getPosition().y == (wallArray[counter].rect.getPosition().y - 64)) {
        objectPlayer.canMoveDown = false;
    } else if(objectPlayer.rect.getPosition().y == (wallArray[counter].rect.getPosition().y + 64)) {
        objectPlayer.canMoveUp = false;
    } else {
        objectPlayer.canMoveUp = true;
        objectPlayer.canMoveRight = true;
        objectPlayer.canMoveDown = true;
        objectPlayer.canMoveLeft = true;
    }

    counter++;
}

此代码的问题在于碰撞部分,因为角色在碰撞墙壁时会有卡住的风险。碰撞甚至发生在墙上,我的角色因此而不能移动到那里。我不知道如何实现基于网格的移动和碰撞,任何人都有示例代码,博客文章,教程或一些提示?

编辑: 碰撞部分发生在updateMovement函数之前!

2 个答案:

答案 0 :(得分:0)

我不知道你是否这样做,但通常你可以在你申请之前检查注册的移动(或者如果需要可以移动并稍后撤消),然后检查它是否与墙碰撞,如果它只是忽略了输入移动。或者你可以在检测到碰撞后应用非常小的余量,这样如果没有再次按下它就不会再次碰撞。

答案 1 :(得分:0)

最后想出来了:

counter = 0;
    for(iterWall = wallArray.begin(); iterWall != wallArray.end(); iterWall++) {
        if(!leftCheck){
            if( ( (wallArray[counter].rect.getPosition().x + 64) == objectPlayer.rect.getPosition().x ) && ( (wallArray[counter].rect.getPosition().y) == objectPlayer.rect.getPosition().y ) ) {
                objectPlayer.canMoveLeft = false; // if character is standing directly to the right of player AND(wall and player is at the same height), player cant move left.
                leftCheck = true;
            } else {
                objectPlayer.canMoveLeft = true;
            }
        }

        if(!rightCheck) {
            if( ( (wallArray[counter].rect.getPosition().x + - 64) == objectPlayer.rect.getPosition().x ) && ( (wallArray[counter].rect.getPosition().y) == objectPlayer.rect.getPosition().y ) ) {
                objectPlayer.canMoveRight = false;
                rightCheck = true;
            } else {
                objectPlayer.canMoveRight = true;
            }
        }

        if(!downCheck) {
            if( ( (wallArray[counter].rect.getPosition().y + 64) == objectPlayer.rect.getPosition().y ) && ( wallArray[counter].rect.getPosition().x == objectPlayer.rect.getPosition().x ) ) {
                objectPlayer.canMoveUp = false;
                downCheck = true;
            } else {
                objectPlayer.canMoveUp = true;
            }
        }

        if(!upCheck) {
            if( ( (wallArray[counter].rect.getPosition().y - 64) == objectPlayer.rect.getPosition().y ) && ( wallArray[counter].rect.getPosition().x == objectPlayer.rect.getPosition().x ) ) {
                objectPlayer.canMoveDown = false;
                upCheck = true;
            } else {
                objectPlayer.canMoveDown = true;
            }
        }

        counter++;
    }
    upCheck = false;
    rightCheck = false;
    downCheck = false;
    leftCheck = false;

当我在游戏中添加更多墙壁时,我意识到下一个墙壁覆盖了之前的墙壁canMoveUp布尔变化。为了防止这种变化,我在代码中添加了一些检查。检查在游戏启动时添加一次,但在代码中的任何其他位置都没有更改,但在此处。

并且我的updateMovement被分成两部分以防止帧暂停:

void player::updateEndPos() {
    if( (EndXPos == GetPosition().x) && (EndYPos == GetPosition().y) ) {
        if(canMoveUp && sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
            direction = 1; // direction set to Up

            EndYPos = GetPosition().y - 64; // Sets end-pos so the character knows where to stop.

        } else if(canMoveRight && sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
        direction = 2; // direction set to Right

            EndXPos = GetPosition().x + 64;

        } else if(canMoveDown && sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
            direction = 3; // direction set to Down

        EndYPos = GetPosition().y + 64;

        } else if(canMoveLeft && sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
            direction = 4; // direction set to Left

            EndXPos = GetPosition().x - 64;

        }
    }
}

以及:

void player::updateMovement() {
    if(EndYPos != GetPosition().y) {
        if(direction == 1) {
            rect.move(0, -movementSpeed); // moves player at "movementSpeed" speed.
        } else if(direction == 3) {
                rect.move(0, movementSpeed);
        } else {
            std::cout << "ERROR IN Y AXIS" << std::endl;
        }
        } else if(EndXPos != GetPosition().x) {
            if(direction == 2) {
                rect.move(movementSpeed, 0);
        } else if(direction == 4) {
            rect.move(-movementSpeed, 0);
        } else {
            std::cout << "ERROR IN X AXIS" << std::endl;
        }
    }
}

首先我检查碰撞,然后执行updateEndPos(),然后直接执行updateMovement()。

我拆分了updateEndPos和updateMovement,因为如果我不这样做,我会得到一个框架,其中up​​dateEndPos()部分将不会执行,并且玩家将在该框架中静止不动。它是非常明显的,但是它修复了它,现在角色的动作看起来很平滑。