简体   繁体   English

SDL和C ++中的碰撞

[英]Collisions in SDL & C++

How do I calculate a collision between two rects in C++ & SDL, and how do I make the player not able to go through this rect (ie ensure one rect cannot pass through the other)? 如何计算C ++和SDL中两个矩形之间的碰撞,以及如何使播放器无法通过该矩形(即确保一个矩形不能穿过另一个矩形)?

I know to stop the player would be playeryvel = 0 , making the player's Y velocity 0, so they cannot pass through it. 我知道停止播放器将是playeryvel = 0 ,使播放器的Y速度为0,因此他们无法通过它。 My problem is, this will stop ALL vertical movement, when I want to stop movement through the other rect. 我的问题是,当我想停止通过其他矩形的移动时,这将停止所有垂直移动。

My current code uses a function named check_collision(SDL_Rect, SDL_Rect) . 我当前的代码使用了一个名为check_collision(SDL_Rect, SDL_Rect)的函数。 Here's my the code for the usage, and the actual function. 这是我的用法代码和实际功能。

// This loops through a vector, containing rects.
for (int i=0; i<MAP::wall.size(); i++)
{
    std::cout << i << std::endl;
    cMap.FillCustomRect(MAP::wall.at(i), 0xFFFFFF);
    if (check_collision(cMap.wall.at(i), cDisplay.getPlayer(playerx, playery)))
    {
        exit(0); // It exits just as an example to show if there actually is a collision
    }
}


bool check_collision( SDL_Rect A, SDL_Rect B )
{
    //The sides of the rectangles
    int leftA, leftB;
    int rightA, rightB;
    int topA, topB;
    int bottomA, bottomB;

    //Calculate the sides of rect A
    leftA = A.x;
    rightA = A.x + A.w;
    topA = A.y;
    bottomA = A.y + A.h;

    //Calculate the sides of rect B
    leftB = B.x;
    rightB = B.x + B.w;
    topB = B.y;
    bottomB = B.y + B.h;

     //If any of the sides from A are outside of B
    if( bottomA <= topB )
    {
        return false;
    }

    if( topA >= bottomB )
    {
        return false;
    }

    if( rightA <= leftB )
    {
        return false;
    }

    if( leftA >= rightB )
    {
        return false;
    }

    //If none of the sides from A are outside B
    return true;
}

Simply push player away from the point of collision, every frame. 只需在每一帧中将播放器推离碰撞点即可。 You don't need boolean tests (collide or not), you need to adjust player position if collision occurs. 您不需要布尔测试(是否发生碰撞),如果发生碰撞,则需要调整玩家位置。

  1. Update player position (position += velocity * time); 更新玩家位置(位置+ =速度*时间);
  2. If collision occurs, push player away from point of collision so no collision occur. 如果发生碰撞,请将玩家推离碰撞点,以免发生碰撞。

This can work really well, because you'll be able to "slide" along walls, etc. To do that you need to find point of contact, depth of intersection and direction of intersection (ie in which direction you should push the player to move away). 这可以很好地起作用,因为您将能够沿墙壁“滑动”等。为此,您需要找到接触点,相交深度和相交方向(即,应将玩家推向哪个方向)离开)。

Of course, you'll need to calculate how far you should move the player, but in 2D it is extremely easy to do. 当然,您需要计算播放器的移动距离,但是在2D模式下,这非常容易做到。

You need to calculate how much two rectangles overlap. 您需要计算两个矩形有多少重叠。 Then you push player rectangle in the direction (x or y) that overlaps the most (only in x or y direction, unless they're equal). 然后,您沿重叠最多的方向(x或y)(仅在x或y方向,除非它们相等)推动玩家矩形。

I see you used Lazyfoo code. 我看到您使用了Lazyfoo代码。 So did I. I had the same problem as you but i solved it. 我也是。我和你有同样的问题,但我解决了。 Here's how i did it. 这是我的方法。

hero.move(true);   // hero is moved in some direction 
if (check_collision(hero.rect(),box.rect()))  // check for collision after movement 
{
    hero.move(false); // if collision happend , move hero back 
}

SDL_flip(screen);

It will look like hero has stopped on block but in reality it will move forward then, if collision happens, move back. 看起来英雄已经​​停下来了,但实际上它将向前移动,如果发生碰撞,则向后移动。 After this he will be displayed. 此后,将显示他。 The true and false arguments are used to tell the function if the hero must be moved forward (x += speed) or backward (x -= speed). true和false参数用于告知函数英雄是否必须向前移动(x + =速度)或向后移动(x-=速度)。 If you will need some code from my collision code just ask. 如果您需要我的碰撞代码中的一些代码,请询问。

It sounds like you're only catching your collisions after the fact. 听起来您像是在事后才发现自己的碰撞。 Most likely you're moving the player into the rectangle, so subsequent collision checks always return true. 您很可能会将播放器移到矩形中,因此后续的碰撞检查始终返回true。 There are a few ways to fix this, but I think the easiest is to catch the collision before it happens, not after, and prevent it. 有几种方法可以解决此问题,但我认为最简单的方法是在发生碰撞之前 (而不是在发生之后)捕获并防止它。

Let's say the player is falling and you update the player's position each frame. 假设播放器跌倒了,而您每帧都更新了播放器的位置。 Before you move the player's position is changed, you want to check if the new position is going to intersect a rectangle. 在移动玩家的位置之前,您需要检查新位置是否将与矩形相交。 If the new position will intersect a rectangle, you want to change how far the player is moved (let's call this distance the step ) so that it touches the edge of the rectangle, but doesn't intersect it. 如果新位置将与矩形相交,则要更改播放器的移动距离(我们将此距离称为step ),以使其接触矩形的边缘,但不相交。

Add checking colision in move function. 在移动功能中添加检查大肠杆菌。 Pass new position (as if it was moved) to checking colision function. 传递新位置(好像已移动)以检查大肠杆菌功能。 If there will occur collision return false in move func, if there isn't move and return true. 如果发生碰撞,则在move func中返回false,否则,则返回true。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM