SFML 轴独立碰撞
SFML Axis independent collision
我已经在我的游戏中实现了 tilemap 碰撞,它可以工作,但是当我在一个轴上发生碰撞并试图在另一个轴上移动时,问题就来了。我不能沿着墙滑。
在Player.cpp
void Player::update(float delta, std::vector<Tile>& tiles) {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) < -20) {
newPos.y -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) || sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) < -20) {
newPos.x -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S) || sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) > 20) {
newPos.y += speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) > 20) {
newPos.x += speed * delta;
}
sf::Vector2f oldPos = sprite.getPosition();
move(delta, newPos);
for (int i = 0; i < tiles.size(); i++) {
if (Collision::PixelPerfectTest(sprite, tiles[i].sprite) && tiles[i].collision) {
sprite.setPosition(oldPos);
newPos = oldPos;
}
}
}
void Player::move(float delta, sf::Vector2f position) {
sprite.setPosition(position);
}
在Collision.cpp
bool PixelPerfectTest(const sf::Sprite& Object1, const sf::Sprite& Object2, sf::Uint8 AlphaLimit) {
sf::FloatRect Intersection;
if (Object1.getGlobalBounds().intersects(Object2.getGlobalBounds(), Intersection)) {
sf::IntRect O1SubRect = Object1.getTextureRect();
sf::IntRect O2SubRect = Object2.getTextureRect();
sf::Uint8* mask1 = Bitmasks.GetMask(Object1.getTexture());
sf::Uint8* mask2 = Bitmasks.GetMask(Object2.getTexture());
// Loop through our pixels
for (int i = Intersection.left; i < Intersection.left + Intersection.width; i++) {
for (int j = Intersection.top; j < Intersection.top + Intersection.height; j++) {
sf::Vector2f o1v = Object1.getInverseTransform().transformPoint(i, j);
sf::Vector2f o2v = Object2.getInverseTransform().transformPoint(i, j);
// Make sure pixels fall within the sprite's subrect
if (o1v.x > 0 && o1v.y > 0 && o2v.x > 0 && o2v.y > 0 &&
o1v.x < O1SubRect.width && o1v.y < O1SubRect.height &&
o2v.x < O2SubRect.width && o2v.y < O2SubRect.height) {
if (Bitmasks.GetPixel(mask1, Object1.getTexture(), (int)(o1v.x) + O1SubRect.left, (int)(o1v.y) + O1SubRect.top) > AlphaLimit &&
Bitmasks.GetPixel(mask2, Object2.getTexture(), (int)(o2v.x) + O2SubRect.left, (int)(o2v.y) + O2SubRect.top) > AlphaLimit)
return true;
}
}
}
}
return false;
}
那是因为你的碰撞测试是全有或全无。我会做额外的碰撞测试来查看 x 或 y 新位置是否有效,例如:
if (tiles[i].collision && Collision::PixelPerfectTest(sprite, tiles[i].sprite))
{
sf::Vector2f checkPosX = newPos;
sf::Vector2f checkPosY = newPos;
checkPosX.y = oldPos.y;
checkPosY.x = oldPos.x;
sprite.setPosition(checkPosX);
if (!Collision::PixelPerfectTest(sprite, tiles[i].sprite))
{
newPos = checkPosX;
}
else
{
sprite.setPosition(checkPosY);
if (!Collision::PixelPerfectTest(sprite, tiles[i].sprite))
{
newPos = checkPosY;
}
else
{
sprite.setPosition(oldPos);
newPos = oldPos;
}
}
}
顺便说一句,如果您先测试 tiles[i].collision
,由于表达式短路,您将跳过更昂贵的 PixelPerfectTest()
非碰撞块测试。
我已经在我的游戏中实现了 tilemap 碰撞,它可以工作,但是当我在一个轴上发生碰撞并试图在另一个轴上移动时,问题就来了。我不能沿着墙滑。
在Player.cpp
void Player::update(float delta, std::vector<Tile>& tiles) {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) < -20) {
newPos.y -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) || sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) < -20) {
newPos.x -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S) || sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) > 20) {
newPos.y += speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) > 20) {
newPos.x += speed * delta;
}
sf::Vector2f oldPos = sprite.getPosition();
move(delta, newPos);
for (int i = 0; i < tiles.size(); i++) {
if (Collision::PixelPerfectTest(sprite, tiles[i].sprite) && tiles[i].collision) {
sprite.setPosition(oldPos);
newPos = oldPos;
}
}
}
void Player::move(float delta, sf::Vector2f position) {
sprite.setPosition(position);
}
在Collision.cpp
bool PixelPerfectTest(const sf::Sprite& Object1, const sf::Sprite& Object2, sf::Uint8 AlphaLimit) {
sf::FloatRect Intersection;
if (Object1.getGlobalBounds().intersects(Object2.getGlobalBounds(), Intersection)) {
sf::IntRect O1SubRect = Object1.getTextureRect();
sf::IntRect O2SubRect = Object2.getTextureRect();
sf::Uint8* mask1 = Bitmasks.GetMask(Object1.getTexture());
sf::Uint8* mask2 = Bitmasks.GetMask(Object2.getTexture());
// Loop through our pixels
for (int i = Intersection.left; i < Intersection.left + Intersection.width; i++) {
for (int j = Intersection.top; j < Intersection.top + Intersection.height; j++) {
sf::Vector2f o1v = Object1.getInverseTransform().transformPoint(i, j);
sf::Vector2f o2v = Object2.getInverseTransform().transformPoint(i, j);
// Make sure pixels fall within the sprite's subrect
if (o1v.x > 0 && o1v.y > 0 && o2v.x > 0 && o2v.y > 0 &&
o1v.x < O1SubRect.width && o1v.y < O1SubRect.height &&
o2v.x < O2SubRect.width && o2v.y < O2SubRect.height) {
if (Bitmasks.GetPixel(mask1, Object1.getTexture(), (int)(o1v.x) + O1SubRect.left, (int)(o1v.y) + O1SubRect.top) > AlphaLimit &&
Bitmasks.GetPixel(mask2, Object2.getTexture(), (int)(o2v.x) + O2SubRect.left, (int)(o2v.y) + O2SubRect.top) > AlphaLimit)
return true;
}
}
}
}
return false;
}
那是因为你的碰撞测试是全有或全无。我会做额外的碰撞测试来查看 x 或 y 新位置是否有效,例如:
if (tiles[i].collision && Collision::PixelPerfectTest(sprite, tiles[i].sprite))
{
sf::Vector2f checkPosX = newPos;
sf::Vector2f checkPosY = newPos;
checkPosX.y = oldPos.y;
checkPosY.x = oldPos.x;
sprite.setPosition(checkPosX);
if (!Collision::PixelPerfectTest(sprite, tiles[i].sprite))
{
newPos = checkPosX;
}
else
{
sprite.setPosition(checkPosY);
if (!Collision::PixelPerfectTest(sprite, tiles[i].sprite))
{
newPos = checkPosY;
}
else
{
sprite.setPosition(oldPos);
newPos = oldPos;
}
}
}
顺便说一句,如果您先测试 tiles[i].collision
,由于表达式短路,您将跳过更昂贵的 PixelPerfectTest()
非碰撞块测试。