【问题标题】:SFML Collision Detection, C++ -> Reset Player PositionSFML 碰撞检测,C++ -> 重置玩家位置
【发布时间】:2014-03-17 11:02:56
【问题描述】:

我在碰撞检测方面工作了几天,现在我的代码真的很盲目:/。一切正常,除了玩家位置重置。 我的碰撞检测函数返回相交的矩形和 1,2,5 或 6 1=敌人左上角碰撞,2=敌人左下角碰撞,5=敌人右下角碰撞,6=敌人右上角碰撞。玩家信息如下:

X=Current X Position;
Y=Current Y Position (the higher Y the lower is the Player at the Screen);
X_INIT= the next X Position of the Player;
Y_Init= the next Y Position of the Player;
Player_width= :);
Player_height= :);

在播放器的下一个位置检测到碰撞。 现在,如果玩家从左侧(或右侧)移动,他应该停在敌人处。 如果他是从顶部跌落到他身上,跌落也应该停止。 如果他正在跌倒并向他移动,例如跳,他应该停在左边,或者,如果他足够高,他应该落在上面。

sf::IntRect rect_player(player->initialpos.x, player->initialpos.y, player->size.x, player->size.y);
sf::IntRect rect_tile(pos.x, pos.y, 50, 50);
s_collision_det collision=collide(rect_player,rect_tile);
float x=player->pos.x;
float y=player->pos.y;
float xx=player->initialpos.x;
float yy=player->initialpos.y;
float sx=player->size.x;
float sy=player->size.y;
//float sy=player->size.y;
float stx=collision.colliding_rect.left;
float sty=collision.colliding_rect.top;
float stsx=collision.colliding_rect.width;
//float stsy=collision.colliding_rect.height;
if (collision.collision==1){
cout<<"im in 1++";
    cout << stx<<"##"<< xx+sx;
    if (y>=yy){offset_up(player,rect_tile);}
    //if ((xx+sx>stx)and(sty!=y+sy)){offset_left(player,rect_tile);};

    //if (x+sx>=stx and xx+sx>=stx and y > yy ){offset_down(player,rect_tile);};
}else if (collision.collision==2){
  cout<<"im in 2++";
 if ((x+sx<=stx or xx+sx>stx)and(sty!=y+sy)){offset_left(player,rect_tile);};
    //if ((x>=stx+stsx or xx>stx+stsx) and (sty!=y+sy)){offset_right(player,rect_tile);};
    //if (x+sx>=stx and xx+sx>=stx and y < yy ){offset_up(player,rect_tile);};
    //if (x+sx>=stx and xx+sx>=stx and y > yy ){offset_down(player,rect_tile);};

}else if (collision.collision==5){
cout<<"im in 5++";

if ((x>=stx+stsx or xx>stx+stsx) and (sty!=y+sy)){offset_right(player,rect_tile);};
    //if (x<=stx+stsx and xx<=stx+stsx and y < yy ){offset_up(player,rect_tile);};
    //if (x<=stx+stsx and xx<=stx+stsx and y > yy ){offset_down(player,rect_tile);};
        }else if (collision.collision==6){
    cout<<"im in 6++";
    if ((x>=stx+stsx or xx>stx+stsx) and (sty!=y+sy)){offset_right(player,rect_tile);};
    //if (x<=stx+stsx and xx<=stx+stsx and y < yy ){offset_up(player,rect_tile);};
    //if (x<=stx+stsx and xx<=stx+stsx and y > yy ){offset_down(player,rect_tile);};
}

注释的条件是我已经尝试过的一些,但没有奏效。 我的想法有什么错误? :) 感谢您的帮助。 PS:请原谅我的英语有些语法错误,这不是我的母语。 附言: 偏移函数为:

void offset_left(character *player, sf::IntRect tile){
player->initialpos.x=tile.left-player->size.x;


player->x_speed=0;
cout<<"Offset_Left++";
};
void offset_right(character *player, sf::IntRect tile){
player->initialpos.x=tile.left+tile.width;
player->x_speed=0;
cout<<"Offset_Right++";
};
void offset_up(character *player, sf::IntRect tile){
player->initialpos.y=tile.top-player->size.y;
player->collision.bottom=1;
player->y_speed=0;
cout<<"Offset_Up++";
};
void offset_down(character *player, sf::IntRect tile){
player->initialpos.y=tile.top+tile.height;
player->y_speed=0;
cout<<"Offset_Down++";

};

【问题讨论】:

  • 我建议你先专注于算法,然后再尝试实现一些东西。您的代码非常难以阅读,因此从头开始重新实现它比将其提交提交更容易。
  • 感谢您的建议,我对 c++ 应用程序编程很陌生,这是我的第一个更大的项目,因此我不习惯在类和算法中思考 :),但我真的很努力超出程序编程。

标签: c++ macos collision sfml


【解决方案1】:

一些初步建模

我假设您游戏中的所有对象(包括玩家的头像)都有一个边界矩形。

您不仅希望将碰撞检测为布尔结果,还希望确定哪些边发生了碰撞(否则您将无法处理顶部/侧面情况)。

两个矩形的碰撞检测

假设一个矩形由它的左上角和右下角定义为 R(x0, y0, x1, y1),我们有两个矩形 A 和 B,

A 和 B 相交当且仅当

A.x0 <= B.x1 and
B.x0 <= A.x1 and
A.y0 <= B.y1 and
B.y0 <= A.y1

现在这不足以检测碰撞发生在哪一侧。您必须考虑之前的位置才能正确处理碰撞。

为此,您可以计算两个矩形的相对位置。

在一般情况下,每个轴可以有 3 种可能的状态(左/中/右和上/中/下)。结合这 3 个位置产生 9 种可能性(左上、上、右上、左、碰撞、右、左下、下、右下)。

这 4 种复合情况(左上、右上、左下和右下)处理起来很麻烦,因此您可以简单地优先考虑一个轴(通常是 X 轴,这样“上”和“下”才会发生)当玩家的精灵完全在障碍物/敌人/任何东西上方时)。

最后,您应该设计一个返回 5 个可能值的函数:左、右、上、下和碰撞。

该函数的伪代码如下:

position check_pos (rect a, rect b)
  if (a.x1 < b.x0) return left
  if (a.x0 > b.x1) return right
  if (a.y1 > b.y0) return above
  if (a.y0 < b.y1) return below
  return collide

现在要检测碰撞,您必须考虑移动对象的当前位置和下一个位置。假设矩形 a 位于位置 a0,速度为 va,我们可以检查与 b 的碰撞:

position check_collision (a0, va, b)
  a1 = a0 + va // apply speed to a
  current = check_pos (a0, b)
  next    = check_pos (a1, b)
  if (next == collide) return current
  return clear

这将返回 a 与 b 碰撞的一侧。它也可能返回“碰撞”,但这意味着您没有正确处理上一个时间步(即您允许两个对象继续移动,以便它们保持相互嵌入)。

朴素的实现

由于您的部分或全部对象将移动,因此将矩形定义为参考点和(宽度,高度)对会更方便。

Struct Point {
    int x;
    int y;
    Point (int x, int y) : x(x), y(y) {}
    Point operator+ (const Point& p) { return Point (x+p.x, y+p.y); }
};

Struct Rectangle {
    enum position { left, right, top, left, collide, clear };
    Point ref;
    Point size;
    Rectangle (Point ref, Point size) : ref(ref), size(size) {}
    Rectangle (int x, int y, int w, int h) : ref(x,y), size(w,h) {}

    position check_pos (const Rectangle& rect)
    {
        if (ref.x+size.x < rect.ref.x            ) return left;
        if (ref.x        > rect.ref.x+rect.size.x) return right;
        if (ref.y+size.y > rect.ref.y            ) return top;
        if (ref.y        < rect.ref.y+rect.size.y) return bottom;
        return collide;
    } 

    position check_collision (const Point velocity, const Rectangle& rect)
    {
        Rectangle a1 = Rectangle(ref+velocity, size);
        position cur  = check_pos (b);
        position next = a1.check_pos (b);
        if (next == collide) return cur;
        return clear;
    } 
};

这只是我脑海中的伪 C++。
不要指望它开箱即用,但希望它能让你开始。

【讨论】:

  • 感谢您的帮助,有了这个想法,我能够获得非常好的工作碰撞检测,并且碰撞处理也工作得很好。 :) 非常感谢 :)
  • 很高兴听到这个消息。完成后给我一个链接到你的游戏;)。
猜你喜欢
  • 1970-01-01
  • 2017-07-25
  • 1970-01-01
  • 1970-01-01
  • 2012-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多