碰撞无法正常工作(使玩家卡住)

问题描述 投票:0回答:1

我无法正确处理碰撞。玩家只会被困在方块中,即使是在方块之上。 (顺便说一句还有重力)

我的碰撞依赖于玩家的“过去”位置

编辑:我在代码中犯了一个错误,所以我更改了它。我还没有得到答案。为什么它得到-1票🤔?

我是新人,所以请帮助我,不要批评我太多。这是我的第一个问题。

这是我的代码:

#include <SFML/Graphics.hpp>
#include <iostream>
#include <math.h>
constexpr auto PI = 3.14159265;
bool rr(float x1, float y1, float w1, float h1, float x2, float y2, float w2, float h2) {
    return (x1 + w1 > x2 && y1 + h1 > y2 && x1 < x2 + w2 && y1 < y2 + h2);
};
//#include <string>
int main()
{
    
    //Player stuffs
    sf::Vector2f playerPos(0, 0);
    sf::Vector2f playerPastPos(0, 0);
    sf::Vector2f playerVel(0, 0);
    sf::RectangleShape playerRender;
    
    playerRender.setSize(sf::Vector2f(20, 20));
    playerRender.setFillColor(sf::Color(0, 255, 0));

    sf::RenderWindow window(sf::VideoMode(600, 400), "Platformer (SFML)");
    window.setFramerateLimit(60);
    sf::Vector2u windowSize = window.getSize();
    int block_map[] = {
        0,0,0,0,0,0,0,1,
        0,0,0,0,0,0,0,1,
        0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,2,
        1,0,0,0,0,0,1,1,
        1,1,1,1,1,1,1,1,
    };
    int map_width = 8;
    int map_height = 8;
    sf::RectangleShape rect[sizeof(block_map) / sizeof(*block_map)];
    
    for (int i = 0; i < sizeof(block_map) / sizeof(*block_map); i++) {
            
            rect[i].setPosition(sf::Vector2f((i%(map_width))*20, std::floor(i/map_height)*20));
            rect[i].setFillColor(sf::Color(255, 255, 255, 0));
            switch(block_map[i]){
                case 1:
                    rect[i].setFillColor(sf::Color(255, 255, 255));
                    break;
                case 2:
                    rect[i].setFillColor(sf::Color(255, 0, 255));
                    break;
            }
            
            //std::cout <<"/"+std::to_string((a[i].at(j)));
            
            
        
        
        
    }
    
    int i = 0, j = 50, l = 0;
    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        window.clear();
        windowSize = window.getSize();
        playerPastPos = playerPos;
        while (l < sizeof(rect) / sizeof(rect[0])) {
            
            rect[l].setSize(sf::Vector2f(20, 20));

            //rect[l].setPosition(i, j);

            window.draw(rect[l]);

            //i += 25;

            l++;
        }
        for (int i = 0; i < sizeof(block_map) / sizeof(*block_map); i++) {
            bool canColl = false;
            sf::Vector2f pos = sf::Vector2f((i % (map_width)) * 20, std::floor(i / map_height) * 20);


            if (rr(playerPos.x, playerPos.y, 20, 20, pos.x, pos.y, 20, 20)) {
                switch (block_map[i]) {
                case 1:
                    canColl = true;
                    break;
                case 2:
                    canColl = true;
                    break;
                }
                //0.0174532925
                if (canColl) {
                    
                        
                    if (playerPastPos.y < pos.y - 20) {
                        playerVel.y = 0;
                        playerPos.y = pos.y - 20;
                    }
                    if (playerPastPos.x > pos.x + 20) {
                        playerVel.x = 0;
                        playerPos.x = pos.x + 20;
                    }
                    if (playerPastPos.y > pos.y + 20) {
                        playerVel.y = 0;
                        playerPos.y = pos.y + 20;
                    }
                    if (playerPastPos.x < pos.x - 20) {
                        playerVel.x = 0;
                        playerPos.x = pos.x - 20;
                    }
                    
                }
            }

        }
        //Player in game stuffs
        playerVel.x *= 0.95;
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) && playerVel.x < 3) {
            playerVel.x += 0.5;
        }
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) && playerVel.x > -3) {
            playerVel.x -= 0.5;
        }
        playerVel.y += 0.3;
        playerPos += playerVel;
        
        
        playerRender.setPosition(playerPos);
        window.draw(playerRender);

        


        // Reset variables.
        l = 0;
        i = 0;
        // Copy the buffer to the window.
        window.display();
    }
}
c++ sfml collision
1个回答
0
投票

请注意,默认情况下,矩形的原点位于其左上角。这意味着检查碰撞时的

pos.x
pos.y
值是块的左上角。如果您的播放器继承了 sf::Transformable,这也适用于您的播放器。考虑到这一点,你的计算都是错误的。你应该:

bool rr(float x1, float y1, float w1, float h1, float x2, float y2, float w2, float h2) {
    // Is player pos x inside block pos x?
    // Yes if top right x of player is greater than top left x of block
    // and if top left x of player is lesser than top right x of block at the same time
    bool xIn = (x1 + w1 > x2) && (x1 < x2 + w2);
    
    // Is player pos y inside block pos y?
    // Yes if top left y of player is greater than bottom left y of block
    // and if bottom left y of player is lesser than top left y of block at the same time
    bool yIn = (y1 > y2 - h2) && (y1 - h1 < y2);

    return xIn && yIn;
}

现在您知道发生了碰撞,您必须纠正玩家的位置。现在,您的实现似乎从方块的角度忽略了玩家的相对位置,而且效果不好。我会尝试改变这一点:

// Correct x pos
// Is player coming from left or right?
if ((playerVel.x > 0) && (playerPastPos.x + 20 < pos.x)) {
    // Coming from left
    playerVel.x = 0;
    playerPos.x = pos.x - 20;
}
else if ((playerVel.x < 0) && (playerPastPos.x > pos.x + 20)) {
    // Coming from right
    playerVel.x = 0;
    playerPos.x = pos.x + 20;
}

// Correct y pos
// Is player coming from top or bottom?
if ((playerVel.y > 0) && (playerPastPos.y < pos.y - 20)) {
    // Coming from bottom
    playerVel.y = 0;
    playerPos.y = pos.y - 20;
}
else if ((playerVel.y < 0) && (playerPastPos.y - 20 > pos.y)) {
    // Coming from top
    playerVel.y = 0;
    playerPos.y = pos.y + 20;
}

这显然不是最好的做事方式,但我尝试遵循您的实现的基本思想。

© www.soinside.com 2019 - 2024. All rights reserved.