如何在 SFML 中实现基于网格的移动?
How to implement grid-based movement in 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++;
}
此代码的问题在于碰撞部分,因为角色在与墙壁碰撞时有被卡住的风险。碰撞甚至发生在墙上方,因此我的角色无法移动到那里。我不知道如何实现基于网格的移动和碰撞,谁有示例代码、博客-post、教程或一些提示?
编辑:
碰撞部分发生在 updateMovement 函数之前!
我不知道你是否这样做,但通常你可以在应用它之前检查注册的移动(或者如果需要的话稍后再执行移动和撤消)然后检查它是否与墙壁碰撞以及它是否只是忽略输入移动。或者您可以在检测到碰撞后应用非常小的边距,这样如果不再次推动它就不会再次碰撞。
终于弄明白了:
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 分开,因为如果我不这样做,我会得到一个帧,其中 updateEndPos() 部分不会执行,玩家会在该帧中静止不动。它非常明显,但已修复它,现在角色的移动看起来很流畅。
我无法在 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++;
}
此代码的问题在于碰撞部分,因为角色在与墙壁碰撞时有被卡住的风险。碰撞甚至发生在墙上方,因此我的角色无法移动到那里。我不知道如何实现基于网格的移动和碰撞,谁有示例代码、博客-post、教程或一些提示?
编辑: 碰撞部分发生在 updateMovement 函数之前!
我不知道你是否这样做,但通常你可以在应用它之前检查注册的移动(或者如果需要的话稍后再执行移动和撤消)然后检查它是否与墙壁碰撞以及它是否只是忽略输入移动。或者您可以在检测到碰撞后应用非常小的边距,这样如果不再次推动它就不会再次碰撞。
终于弄明白了:
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 分开,因为如果我不这样做,我会得到一个帧,其中 updateEndPos() 部分不会执行,玩家会在该帧中静止不动。它非常明显,但已修复它,现在角色的移动看起来很流畅。