[英](SFML) Character movement is unnatural and has strange quirks
tld; dr:角色移动容易出现毛刺,似乎并不总是能记录到按键的释放,并且总体上很差; 有任何改进建议(或错误修复)?
你好,
我(仍在)致力于使用C ++在SFML中制作一个相对简单的平台游戏,而我一直在努力使动作流畅。 我的“地图”由(x,y)对的网格组成,这些网格定义了要在该点显示的图块(x和y代表我的关卡Spritesheet中图块Sprite的坐标)。
我遇到的问题是,即使该运动看起来可行,它有时仍会以意想不到的方式运行,而且我也不知道如何解决它,甚至也不知道为什么会发生这种情况。
例如,向箭头发出垃圾邮件(快速按下),有时您可以使角色在地图上滑动(并失去对他的控制),直到他撞到某物为止。 在其他时候(通常是倾斜进入),您可能会卡在地板上,除非先跳下车才能解开,否则无法移动。
截至目前,我正在通过使用4个点进行碰撞检测,这些点代表角色的Hitbox的矩形,因此这可能是问题的一部分。
(旁注:我的按键操作也只检测箭头键,而不检测WASD ...即使它们在相同的if语句中)
(main.cpp)(相关代码)
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::D || event.key.code == sf::Keyboard::Right)
thePlayer.goingRight = true;
if (event.key.code == sf::Keyboard::A || event.key.code == sf::Keyboard::Left)
thePlayer.goingLeft = true;
if (event.key.code == sf::Keyboard::W || event.key.code == sf::Keyboard::Up)
{
thePlayer.isJumping = true;
thePlayer.goingUp = true;
}
if (event.key.code == sf::Keyboard::S || event.key.code == sf::Keyboard::Down)
thePlayer.goingDown = true;
}
if (event.type == sf::Event::KeyReleased)
{
if (event.key.code == sf::Keyboard::D || event.key.code == sf::Keyboard::Right)
thePlayer.goingRight = false;
if (event.key.code == sf::Keyboard::A || event.key.code == sf::Keyboard::Left)
thePlayer.goingLeft = false;
if (event.key.code == sf::Keyboard::W || event.key.code == sf::Keyboard::Up)
thePlayer.goingUp = false;
if (event.key.code == sf::Keyboard::Space)
{
if (bulletsfired != true)
{
bulletsfired = true;
if (thePlayer.directionFacing == 0)
{
bulletsList.push_back(myPlayerNamespace::projectile (bulletTexture, thePlayer.mSprite.getPosition().x, (thePlayer.mSprite.getPosition().y + 20.f), thePlayer.directionFacing, bulletCount));
}
else
{
bulletsList.push_back(myPlayerNamespace::projectile (bulletTexture, thePlayer.mSprite.getPosition().x + 25.f, (thePlayer.mSprite.getPosition().y + 20.f), thePlayer.directionFacing, bulletCount));
}
bulletCount++;
}
}
}
thePlayer.updatePlayer();
for (int i = 0; i < bulletsList.size(); i++)
{
bulletsList[i].update();
}
(player.cpp)(相关代码)
void player::updatePlayer()
{
if (player::isJumping == true)
player::goingDown = true;
playerPosX = player::mSprite.getPosition().x;
playerPosY = player::mSprite.getPosition().y;
//Gravity
if (((map[(playerPosY+48)/32][(playerPosX+5)/32].x) != 0 || (map[(playerPosY+48)/32][(playerPosX+5)/32].y) != 0 ) || ((map[(playerPosY+48)/32][(playerPosX+28)/32].x) != 0 || (map[(playerPosY+48)/32][(playerPosX+28)/32].y) != 0 ))
{
player::isJumping = false;
player::goingDown = false;
}
else
{
player::isJumping = true;
player::goingDown = true;
}
//Collision top
if (((map[(playerPosY+6)/32][(playerPosX+5)/32].x) != 0 || (map[(playerPosY+6)/32][(playerPosX+5)/32].y) != 0 ) || ((map[(playerPosY+6)/32][(playerPosX+28)/32].x) != 0 || (map[(playerPosY+6)/32][(playerPosX+28)/32].y) != 0 ))
{
player::goingUp = false;
}
//Collision right
if (((map[(playerPosY+46)/32][(playerPosX+28)/32].x) != 0 || (map[(playerPosY+46)/32][(playerPosX+28)/32].y) != 0 ) || ((map[(playerPosY+6)/32][(playerPosX+28)/32].x) != 0 || (map[(playerPosY+6)/32][(playerPosX+28)/32].y) != 0 ))
{
if (((map[(playerPosY+46)/32][(playerPosX+28)/32].x) == 4 && (map[(playerPosY+46)/32][(playerPosX+28)/32].y) == 5 ) && ((map[(playerPosY+6)/32][(playerPosX+28)/32].x) == 4 && (map[(playerPosY+6)/32][(playerPosX+28)/32].y) == 5 ))
{
std::cout << "Ladder right!";
player::goingDown = false;
player::isJumping = false;
}
else
{
player::goingRight = false;
}
}
//Collision left
if (((map[(playerPosY+6)/32][(playerPosX+5)/32].x) != 0 || (map[(playerPosY+6)/32][(playerPosX+5)/32].y) != 0 ) || ((map[(playerPosY+46)/32][(playerPosX+5)/32].x) != 0 || (map[(playerPosY+46)/32][(playerPosX+5)/32].y) != 0 ))
{
if (((map[(playerPosY+6)/32][(playerPosX+5)/32].x) == 4 && (map[(playerPosY+6)/32][(playerPosX+5)/32].y) == 5 ) && ((map[(playerPosY+46)/32][(playerPosX+5)/32].x) == 4 && (map[(playerPosY+46)/32][(playerPosX+5)/32].y) == 5 ))
{
std::cout << "Ladder left!";
player::goingDown = false;
player::isJumping = false;
}
else
{
player::goingLeft = false;
}
}
if (player::goingRight == true)
{
player::moveRight(player::playerSpeed);
}
if (player::goingLeft == true)
{
player::moveLeft(player::playerSpeed);
}
if (player::goingDown == true)
{
player::moveDown(player::playerFallSpeed);
}
if (player::goingUp == true)
{
player::moveUp(player::playerJumpSpeed);
}
if (player::goingRight == true && player::goingUp == true)
{
player::mSprite.move(player::playerSpeed * 0.5 , -player::playerJumpSpeed * 0.5);
}
if (player::goingLeft == true && player::goingUp == true)
{
player::mSprite.move(-player::playerSpeed * 0.5 , -player::playerJumpSpeed * 0.5);
}
if (player::goingRight == true && player::goingDown == true)
{
player::mSprite.move(player::playerSpeed * 0.5 , player::playerFallSpeed * 0.5);
}
if (player::goingLeft == true && player::goingDown == true)
{
player::mSprite.move(-player::playerSpeed * 0.5 , player::playerFallSpeed * 0.5);
}
}
map [i] [j] .x = 4定义的图块,map [i] [j] .y = 5是“梯形”图块,因此我希望玩家能够在其中移动(以及为什么)它将“梯形图/ direction /!”输出到控制台)。
如果完全相关; playerSpeed = 4.f; playerFallSpeed = 5.f; playerJumpSpeed = 10.f;
最后,感谢您阅读本文! 我非常感谢任何帮助,因为我已经为此苦苦挣扎了大约一个星期。
在尝试实施Dundee的建议后,我终于得到了(或多或少)可以工作的代码。 关键的变化是在碰撞中将方向速度设置为0(例如,向右移动是x正,因此,如果我与右侧的墙碰撞,并且我的玩家速度大于0,则将其设置为0)。 另一个重大变化是抵消有时玩家“掉进地板上”的事实。 我相信会发生这种情况,因为我每秒仅检查碰撞60次,因此有时播放器的高度可能会下降几像素,所以我会检查是否发生了这种情况,如果确实发生,将播放器上移两个像素。 (当然,播放器可能会比预期的多掉2到5个像素,但这似乎或多或少地解决了这个问题)。 该解决方案的唯一缺点是存在明显的“反弹”。 我将利用动画的优势来使游戏看起来更加逼真。
这是新代码:
(main.cpp)
if (event.type == sf::Event::KeyReleased)
{
if (event.key.code == sf::Keyboard::D || event.key.code == sf::Keyboard::Right)
{
thePlayer.playerVelocity.x = 0.f;
}
if (event.key.code == sf::Keyboard::A || event.key.code == sf::Keyboard::Left)
{
thePlayer.playerVelocity.x = 0.f;
}
if (event.key.code == sf::Keyboard::W || event.key.code == sf::Keyboard::Up)
{
//Nothing
}
if (event.key.code == sf::Keyboard::Space)
{
if (bulletsfired != true)
{
bulletsfired = true;
if (thePlayer.directionFacing == 0)
{
bulletsList.push_back(myPlayerNamespace::projectile (bulletTexture, thePlayer.mSprite.getPosition().x, (thePlayer.mSprite.getPosition().y + 20.f), thePlayer.directionFacing, bulletCount));
}
else
{
bulletsList.push_back(myPlayerNamespace::projectile (bulletTexture, thePlayer.mSprite.getPosition().x + 25.f, (thePlayer.mSprite.getPosition().y + 20.f), thePlayer.directionFacing, bulletCount));
}
bulletCount++;
}
thePlayer.playerVelocity.x = 0;
}
}
//Direct input for movement
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
if (thePlayer.playerVelocity.y >= -thePlayer.playerMaxVelocity.y && thePlayer.isJumping == false)
{
thePlayer.playerVelocity.y -= thePlayer.playerJumpSpeed;
}
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) || sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
thePlayer.mSprite.setTextureRect(sf::IntRect(0,0,32,48));
thePlayer.directionFacing = 0;
if (thePlayer.playerVelocity.x >= -thePlayer.playerMaxVelocity.x)
{
thePlayer.playerVelocity.x -= thePlayer.playerSpeed;
}
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S) || sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
//Nothing
//thePlayer.playerVelocity.y += gravity.y;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
thePlayer.mSprite.setTextureRect(sf::IntRect(32,0,32,48));
thePlayer.directionFacing = 1;
if (thePlayer.playerVelocity.x <= thePlayer.playerMaxVelocity.x)
{
thePlayer.playerVelocity.x += thePlayer.playerSpeed;
}
}
thePlayer.updatePlayer();
(player.cpp)
void player::updatePlayer()
{
playerPosX = player::mSprite.getPosition().x;
playerPosY = player::mSprite.getPosition().y;
//Gravity + Collision bottom
if ((((map[(playerPosY+48)/32][(playerPosX+5)/32].x) != 0 || (map[(playerPosY+48)/32][(playerPosX+5)/32].y) != 0 ) || ((map[(playerPosY+48)/32][(playerPosX+28)/32].x) != 0 || (map[(playerPosY+48)/32][(playerPosX+28)/32].y) != 0 )) && isJumping==true)
{
{
playerVelocity.y = 0.f;
isJumping = false;
if ((((map[(playerPosY+46)/32][(playerPosX+10)/32].x) != 0 || (map[(playerPosY+46)/32][(playerPosX+10)/32].y) != 0 ) || ((map[(playerPosY+46)/32][(playerPosX+20)/32].x) != 0 || (map[(playerPosY+46)/32][(playerPosX+20)/32].y) != 0 )))
{
playerPosY -= 2;
mSprite.setPosition(playerPosX, playerPosY);
outline.setPosition(playerPosX+8, playerPosY+6);
}
}
}
else
{
if (playerVelocity.y <= playerMaxVelocity.y && isJumping == true)
{
playerVelocity.y += gravity.y;
}
isJumping = true;
}
//Collision top
if (((map[(playerPosY+6)/32][(playerPosX+5)/32].x) != 0 || (map[(playerPosY+6)/32][(playerPosX+5)/32].y) != 0 ) || ((map[(playerPosY+6)/32][(playerPosX+28)/32].x) != 0 || (map[(playerPosY+6)/32][(playerPosX+28)/32].y) != 0 ))
{
if (playerVelocity.y < 0)
{
playerVelocity.y = 0;
}
}
//Collision right
if (((map[(playerPosY+45)/32][(playerPosX+28)/32].x) != 0 || (map[(playerPosY+45)/32][(playerPosX+28)/32].y) != 0 ) || ((map[(playerPosY+6)/32][(playerPosX+28)/32].x) != 0 || (map[(playerPosY+6)/32][(playerPosX+28)/32].y) != 0 ))
{
if (((map[(playerPosY+45)/32][(playerPosX+28)/32].x) == 4 && (map[(playerPosY+45)/32][(playerPosX+28)/32].y) == 5 ) && ((map[(playerPosY+6)/32][(playerPosX+28)/32].x) == 4 && (map[(playerPosY+6)/32][(playerPosX+28)/32].y) == 5 ))
{
//std::cout << "Ladder right!";
}
else
{
if (playerVelocity.x > 0)
{
playerVelocity.x = 0;
}
}
}
//Collision left
if (((map[(playerPosY+6)/32][(playerPosX+5)/32].x) != 0 || (map[(playerPosY+6)/32][(playerPosX+5)/32].y) != 0 ) || ((map[(playerPosY+45)/32][(playerPosX+5)/32].x) != 0 || (map[(playerPosY+45)/32][(playerPosX+5)/32].y) != 0 ))
{
if (((map[(playerPosY+6)/32][(playerPosX+5)/32].x) == 4 && (map[(playerPosY+6)/32][(playerPosX+5)/32].y) == 5 ) && ((map[(playerPosY+45)/32][(playerPosX+5)/32].x) == 4 && (map[(playerPosY+46)/32][(playerPosX+5)/32].y) == 5 ))
{
//std::cout << "Ladder left!";
}
else
{
if (playerVelocity.x < 0)
{
playerVelocity.x = 0;
}
}
}
mSprite.move(playerVelocity.x, playerVelocity.y);
outline.move(playerVelocity.x, playerVelocity.y);
}
特别感谢Dundee,他提出了使用矢量进行运动的好主意。 如果可以通过某种方式为您提供互联网积分,请告诉我,我很乐意做! :D
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.