Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Colision with SFML2  (Read 5520 times)

0 Members and 1 Guest are viewing this topic.

prchakal

  • Full Member
  • ***
  • Posts: 142
    • View Profile
Colision with SFML2
« on: February 24, 2011, 06:27:27 am »
Hi ppl,

anyone have collision class for SFML2 ?

i need:
- PixelPerfectTest
- BoundingBox
- Circle

Thanks very much.

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
SFML / OS X developer

prchakal

  • Full Member
  • ***
  • Posts: 142
    • View Profile
Colision with SFML2
« Reply #2 on: February 26, 2011, 04:52:39 am »
Im already use it, but it have some errors with sfml2:

1 - 1>d:\workspaces\workspace_vs_2010\solodefender\solodefender\collision.cpp(49): error C2039: 'Offset' : is not a member of 'sf::Rect<T>'

2 - 1>d:\workspaces\workspace_vs_2010\solodefender\solodefender\collision.cpp(88): error C2664: 'bool sf::Rect<T>::Intersects(const sf::Rect<T> &,sf::Rect<T> &) const' : cannot convert parameter 2 from 'sf::IntRect *' to 'sf::Rect<T> &'

3 - 1>d:\workspaces\workspace_vs_2010\solodefender\solodefender\collision.cpp(103): error C2039: 'GetWidth' : is not a member of 'sf::Rect<T>'


4 - 1>d:\workspaces\workspace_vs_2010\solodefender\solodefender\collision.cpp(103): error C2039: 'GetHeight' : is not a member of 'sf::Rect<T>'

5 - 1>d:\workspaces\workspace_vs_2010\solodefender\solodefender\collision.cpp(103): error C2039: 'GetHeight' : is not a member of 'sf::Rect<T>'

:(

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
Colision with SFML2
« Reply #3 on: February 26, 2011, 09:23:41 am »
You have to update the code. See the reference.
SFML / OS X developer

prchakal

  • Full Member
  • ***
  • Posts: 142
    • View Profile
Colision with SFML2
« Reply #4 on: February 27, 2011, 04:58:30 am »
Im already updated the code, but it doesnt work.

Code: [Select]

#include <SFML/Graphics.hpp>
#include "Collision.h"

Collision::Collision() {
}

Collision::~Collision() {
}

sf::IntRect Collision::GetAABB(const sf::Sprite& Object) {

//Get the top left corner of the sprite regardless of the sprite's center
//This is in Global Coordinates so we can put the rectangle back into the right place
sf::Vector2f pos = Object.TransformToGlobal(sf::Vector2f(0, 0));

//Store the size so we can calculate the other corners
sf::Vector2f size = Object.GetSize();

float Angle = Object.GetRotation();

//Bail out early if the sprite isn't rotated
if (Angle == 0.0f) {
return sf::IntRect(static_cast<int> (pos.x),
static_cast<int> (pos.y),
static_cast<int> (pos.x + size.x),
static_cast<int> (pos.y + size.y));
}

//Calculate the other points as vectors from (0,0)
//Imagine sf::Vector2f A(0,0); but its not necessary
//as rotation is around this point.
sf::Vector2f B(size.x, 0);
sf::Vector2f C(size.x, size.y);
sf::Vector2f D(0, size.y);

//Rotate the points to match the sprite rotation
B = RotatePoint(B, Angle);
C = RotatePoint(C, Angle);
D = RotatePoint(D, Angle);

//Round off to int and set the four corners of our Rect
int Left = static_cast<int> (MinValue(0.0f, B.x, C.x, D.x));
int Top = static_cast<int> (MinValue(0.0f, B.y, C.y, D.y));
int Right = static_cast<int> (MaxValue(0.0f, B.x, C.x, D.x));
int Bottom = static_cast<int> (MaxValue(0.0f, B.y, C.y, D.y));

//Create a Rect from out points and move it back to the correct position on the screen
sf::IntRect AABB = sf::IntRect(Left, Top, Right, Bottom);
sf::IntRect AABB_interset(static_cast<int> (pos.x), static_cast<int> (pos.y), static_cast<int> (pos.x + size.x), static_cast<int> (pos.y + size.y));
sf::IntRect AABB_result;
AABB.Intersects(AABB_interset, AABB_result);
return AABB_result;
}

float Collision::MinValue(float a, float b, float c, float d) {
float min = a;

min = (b < min ? b : min);
min = (c < min ? c : min);
min = (d < min ? d : min);

return min;
}

float Collision::MaxValue(float a, float b, float c, float d) {
float max = a;

max = (b > max ? b : max);
max = (c > max ? c : max);
max = (d > max ? d : max);

return max;
}

sf::Vector2f Collision::RotatePoint(const sf::Vector2f& Point, float Angle) {
Angle = Angle * RADIANS_PER_DEGREE;
sf::Vector2f RotatedPoint;
RotatedPoint.x = Point.x * cos(Angle) + Point.y * sin(Angle);
RotatedPoint.y = -Point.x * sin(Angle) + Point.y * cos(Angle);
return RotatedPoint;
}

bool Collision::PixelPerfectTest(const sf::Sprite& Object1, const sf::Sprite& Object2, sf::Uint8 AlphaLimit) {
//Get AABBs of the two sprites
sf::IntRect Object1AABB = GetAABB(Object1);
sf::IntRect Object2AABB = GetAABB(Object2);

sf::IntRect Intersection;

if (Object1AABB.Intersects(Object2AABB, Intersection)) {

//We've got an intersection we need to process the pixels
//In that Rect.

//Bail out now if AlphaLimit = 0
if (AlphaLimit == 0) return true;

//There are a few hacks here, sometimes the TransformToLocal returns negative points
//Or Points outside the image.  We need to check for these as they print to the error console
//which is slow, and then return black which registers as a hit.

sf::IntRect O1SubRect = Object1.GetSubRect();
sf::IntRect O2SubRect = Object2.GetSubRect();

sf::Vector2i O1SubRectSize(O1SubRect.Width, O1SubRect.Height);
sf::Vector2i O2SubRectSize(O2SubRect.Width, O2SubRect.Height);

sf::Vector2f o1v;
sf::Vector2f o2v;
//Loop through our pixels
for (int i = Intersection.Left; i < Intersection.Width; i++) {
for (int j = Intersection.Top; j < Intersection.Height; j++) {

o1v = Object1.TransformToLocal(sf::Vector2f(i, j)); //Creating Objects each loop :(
o2v = Object2.TransformToLocal(sf::Vector2f(i, j));

//Hack to make sure pixels fall withint the Sprite's Image
if (o1v.x > 0 && o1v.y > 0 && o2v.x > 0 && o2v.y > 0 &&
o1v.x < O1SubRectSize.x && o1v.y < O1SubRectSize.y &&
o2v.x < O2SubRectSize.x && o2v.y < O2SubRectSize.y) {

//If both sprites have opaque pixels at the same point we've got a hit
if ((Object1.GetPixel(static_cast<int> (o1v.x), static_cast<int> (o1v.y)).a > AlphaLimit) &&
(Object2.GetPixel(static_cast<int> (o2v.x), static_cast<int> (o2v.y)).a > AlphaLimit)) {
return true;
}
}
}
}
return false;
}
return false;
}

bool Collision::CircleTest(const sf::Sprite& Object1, const sf::Sprite& Object2) {
//Simplest circle test possible
//Distance between points <= sum of radius

float Radius1 = (Object1.GetSize().x + Object1.GetSize().y) / 4;
float Radius2 = (Object2.GetSize().x + Object2.GetSize().y) / 4;
float xd = Object1.GetPosition().x - Object2.GetPosition().x;
float yd = Object1.GetPosition().y - Object2.GetPosition().y;

return sqrt(xd * xd + yd * yd) <= Radius1 + Radius2;
}

//From Rotated Rectangles Collision Detection, Oren Becker, 2001

bool Collision::BoundingBoxTest(const sf::Sprite& Object1, const sf::Sprite& Object2) {

sf::Vector2f A, B, C, BL, TR;
sf::Vector2f HalfSize1 = Object1.GetSize();
sf::Vector2f HalfSize2 = Object2.GetSize();

//For somereason the Vector2d divide by operator
//was misbehaving
//Doing it manually
HalfSize1.x /= 2;
HalfSize1.y /= 2;
HalfSize2.x /= 2;
HalfSize2.y /= 2;
//Get the Angle we're working on
float Angle = Object1.GetRotation() - Object2.GetRotation();
float CosA = cos(Angle * RADIANS_PER_DEGREE);
float SinA = sin(Angle * RADIANS_PER_DEGREE);

float t, x, a, dx, ext1, ext2;

//Normalise the Center of Object2 so its axis aligned an represented in
//relation to Object 1
C = Object2.GetPosition();

C -= Object1.GetPosition();

C = RotatePoint(C, Object2.GetRotation());

//Get the Corners
BL = TR = C;
BL -= HalfSize2;
TR += HalfSize2;

//Calculate the vertices of the rotate Rect
A.x = -HalfSize1.y*SinA;
B.x = A.x;
t = HalfSize1.x*CosA;
A.x += t;
B.x -= t;

A.y = HalfSize1.y*CosA;
B.y = A.y;
t = HalfSize1.x*SinA;
A.y += t;
B.y -= t;

t = SinA * CosA;

// verify that A is vertical min/max, B is horizontal min/max
if (t < 0) {
t = A.x;
A.x = B.x;
B.x = t;
t = A.y;
A.y = B.y;
B.y = t;
}

// verify that B is horizontal minimum (leftest-vertex)
if (SinA < 0) {
B.x = -B.x;
B.y = -B.y;
}

// if rr2(ma) isn't in the horizontal range of
// colliding with rr1(r), collision is impossible
if (B.x > TR.x || B.x > -BL.x) return false;

// if rr1(r) is axis-aligned, vertical min/max are easy to get
if (t == 0) {
ext1 = A.y;
ext2 = -ext1;
}// else, find vertical min/max in the range [BL.x, TR.x]
else {
x = BL.x - A.x;
a = TR.x - A.x;
ext1 = A.y;
// if the first vertical min/max isn't in (BL.x, TR.x), then
// find the vertical min/max on BL.x or on TR.x
if (a * x > 0) {
dx = A.x;
if (x < 0) {
dx -= B.x;
ext1 -= B.y;
x = a;
} else {
dx += B.x;
ext1 += B.y;
}
ext1 *= x;
ext1 /= dx;
ext1 += A.y;
}

x = BL.x + A.x;
a = TR.x + A.x;
ext2 = -A.y;
// if the second vertical min/max isn't in (BL.x, TR.x), then
// find the local vertical min/max on BL.x or on TR.x
if (a * x > 0) {
dx = -A.x;
if (x < 0) {
dx -= B.x;
ext2 -= B.y;
x = a;
} else {
dx += B.x;
ext2 += B.y;
}
ext2 *= x;
ext2 /= dx;
ext2 -= A.y;
}
}

// check whether rr2(ma) is in the vertical range of colliding with rr1(r)
// (for the horizontal range of rr2)
return !((ext1 < BL.y && ext2 < BL.y) ||
(ext1 > TR.y && ext2 > TR.y));

}


whats wrong?

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
Colision with SFML2
« Reply #5 on: February 27, 2011, 10:30:10 am »
I don't know, what says the compiler ?
SFML / OS X developer

prchakal

  • Full Member
  • ***
  • Posts: 142
    • View Profile
Colision with SFML2
« Reply #6 on: February 27, 2011, 04:05:16 pm »
Hi,

The problem is not when compile, but when try collide objects.

On SFML 1.6 the collision class works perfect, but when i need change the class for SFML 2, it doesnt work.

Example:
Code: [Select]
if (Collision::PixelPerfectTest(sprite, GameObjects::planet->getSprite()))
{
remove();
}

Sam42

  • Newbie
  • *
  • Posts: 16
    • View Profile
Colision with SFML2
« Reply #7 on: February 27, 2011, 05:27:07 pm »
Try this:

Code: [Select]
/*
 * File:   collision.cpp
 * Author: Nick
 *
 * Created on 30 January 2009, 11:02
 */
#include <SFML/Graphics.hpp>
#include "collision.h"

Collision::Collision() {
}

Collision::~Collision() {
}

sf::IntRect Collision::GetAABB(const sf::Sprite& Object) {

    //Get the top left corner of the sprite regardless of the sprite's center
    //This is in Global Coordinates so we can put the rectangle back into the right place
    sf::Vector2f pos = Object.TransformToGlobal(sf::Vector2f(0, 0));

    //Store the size so we can calculate the other corners
    sf::Vector2f size = Object.GetSize();

    float Angle = Object.GetRotation();

    //Bail out early if the sprite isn't rotated
    if (Angle == 0.0f) {
        return sf::IntRect(static_cast<int> (pos.x),
                static_cast<int> (pos.y),
                static_cast<int> (pos.x + size.x),
                static_cast<int> (pos.y + size.y));
    }

    //Calculate the other points as vectors from (0,0)
    //Imagine sf::Vector2f A(0,0); but its not necessary
    //as rotation is around this point.
    sf::Vector2f B(size.x, 0);
    sf::Vector2f C(size.x, size.y);
    sf::Vector2f D(0, size.y);

    //Rotate the points to match the sprite rotation
    B = RotatePoint(B, Angle);
    C = RotatePoint(C, Angle);
    D = RotatePoint(D, Angle);

    //Round off to int and set the four corners of our Rect
    int Left = static_cast<int> (MinValue(0.0f, B.x, C.x, D.x));
    int Top = static_cast<int> (MinValue(0.0f, B.y, C.y, D.y));
    int Right = static_cast<int> (MaxValue(0.0f, B.x, C.x, D.x));
    int Bottom = static_cast<int> (MaxValue(0.0f, B.y, C.y, D.y));

    Left += pos.x;
    Top  += pos.y;

    //Create a Rect from out points and move it back to the correct position on the screen
    sf::IntRect AABB = sf::IntRect(Left, Top, size.x, size.y);
    //AABB.Offset(static_cast<int> (pos.x), static_cast<int> (pos.y));
    return AABB;
}

float Collision::MinValue(float a, float b, float c, float d) {
    float min = a;

    min = (b < min ? b : min);
    min = (c < min ? c : min);
    min = (d < min ? d : min);

    return min;
}

float Collision::MaxValue(float a, float b, float c, float d) {
    float max = a;

    max = (b > max ? b : max);
    max = (c > max ? c : max);
    max = (d > max ? d : max);

    return max;
}

sf::Vector2f Collision::RotatePoint(const sf::Vector2f& Point, float Angle) {
    Angle = Angle * RADIANS_PER_DEGREE;
    sf::Vector2f RotatedPoint;
    RotatedPoint.x = Point.x * cos(Angle) + Point.y * sin(Angle);
    RotatedPoint.y = -Point.x * sin(Angle) + Point.y * cos(Angle);
    return RotatedPoint;
}

bool Collision::PixelPerfectTest(const sf::Sprite& Object1, const sf::Sprite& Object2, sf::Uint8 AlphaLimit) {
        //Get AABBs of the two sprites
    sf::IntRect Object1AABB = GetAABB(Object1);
    sf::IntRect Object2AABB = GetAABB(Object2);

    sf::IntRect Intersection;

    if (Object1AABB.Intersects(Object2AABB, Intersection)) {

        //We've got an intersection we need to process the pixels
        //In that Rect.

        //Bail out now if AlphaLimit = 0
        if (AlphaLimit == 0) return true;

        //There are a few hacks here, sometimes the TransformToLocal returns negative points
        //Or Points outside the image.  We need to check for these as they print to the error console
        //which is slow, and then return black which registers as a hit.

        sf::IntRect O1SubRect = Object1.GetSubRect();
        sf::IntRect O2SubRect = Object2.GetSubRect();

        sf::Vector2i O1SubRectSize(O1SubRect.Width, O1SubRect.Height);
        sf::Vector2i O2SubRectSize(O2SubRect.Width, O2SubRect.Height);

        sf::Vector2f o1v;
        sf::Vector2f o2v;
        //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++) {

                o1v = Object1.TransformToLocal(sf::Vector2f(i, j)); //Creating Objects each loop :(
                o2v = Object2.TransformToLocal(sf::Vector2f(i, j));

                //Hack to make sure pixels fall withint the Sprite's Image
                if (o1v.x > 0 && o1v.y > 0 && o2v.x > 0 && o2v.y > 0 &&
                        o1v.x < O1SubRectSize.x && o1v.y < O1SubRectSize.y &&
                        o2v.x < O2SubRectSize.x && o2v.y < O2SubRectSize.y) {

                    //If both sprites have opaque pixels at the same point we've got a hit
                    if ((Object1.GetPixel(static_cast<int> (o1v.x), static_cast<int> (o1v.y)).a > AlphaLimit) &&
                            (Object2.GetPixel(static_cast<int> (o2v.x), static_cast<int> (o2v.y)).a > AlphaLimit)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
    return false;
}

bool Collision::CircleTest(const sf::Sprite& Object1, const sf::Sprite& Object2) {
    //Simplest circle test possible
    //Distance between points <= sum of radius

    float Radius1 = (Object1.GetSize().x + Object1.GetSize().y) / 4;
    float Radius2 = (Object2.GetSize().x + Object2.GetSize().y) / 4;
    float xd = Object1.GetPosition().x - Object2.GetPosition().x;
    float yd = Object1.GetPosition().y - Object2.GetPosition().y;

    return sqrt(xd * xd + yd * yd) <= Radius1 + Radius2;
}

//From Rotated Rectangles Collision Detection, Oren Becker, 2001

bool Collision::BoundingBoxTest(const sf::Sprite& Object1, const sf::Sprite& Object2) {

    sf::Vector2f A, B, C, BL, TR;
    sf::Vector2f HalfSize1 = Object1.GetSize();
    sf::Vector2f HalfSize2 = Object2.GetSize();

    //For somereason the Vector2d divide by operator
    //was misbehaving
    //Doing it manually
    HalfSize1.x /= 2;
    HalfSize1.y /= 2;
    HalfSize2.x /= 2;
    HalfSize2.y /= 2;
    //Get the Angle we're working on
    float Angle = Object1.GetRotation() - Object2.GetRotation();
    float CosA = cos(Angle * RADIANS_PER_DEGREE);
    float SinA = sin(Angle * RADIANS_PER_DEGREE);

    float t, x, a, dx, ext1, ext2;

    //Normalise the Center of Object2 so its axis aligned an represented in
    //relation to Object 1
    C = Object2.GetPosition();

    C -= Object1.GetPosition();

    C = RotatePoint(C, Object2.GetRotation());

    //Get the Corners
    BL = TR = C;
    BL -= HalfSize2;
    TR += HalfSize2;

    //Calculate the vertices of the rotate Rect
    A.x = -HalfSize1.y*SinA;
    B.x = A.x;
    t = HalfSize1.x*CosA;
    A.x += t;
    B.x -= t;

    A.y = HalfSize1.y*CosA;
    B.y = A.y;
    t = HalfSize1.x*SinA;
    A.y += t;
    B.y -= t;

    t = SinA * CosA;

    // verify that A is vertical min/max, B is horizontal min/max
    if (t < 0) {
        t = A.x;
        A.x = B.x;
        B.x = t;
        t = A.y;
        A.y = B.y;
        B.y = t;
    }

    // verify that B is horizontal minimum (leftest-vertex)
    if (SinA < 0) {
        B.x = -B.x;
        B.y = -B.y;
    }

    // if rr2(ma) isn't in the horizontal range of
    // colliding with rr1(r), collision is impossible
    if (B.x > TR.x || B.x > -BL.x) return false;

    // if rr1(r) is axis-aligned, vertical min/max are easy to get
    if (t == 0) {
        ext1 = A.y;
        ext2 = -ext1;
    }// else, find vertical min/max in the range [BL.x, TR.x]
    else {
        x = BL.x - A.x;
        a = TR.x - A.x;
        ext1 = A.y;
        // if the first vertical min/max isn't in (BL.x, TR.x), then
        // find the vertical min/max on BL.x or on TR.x
        if (a * x > 0) {
            dx = A.x;
            if (x < 0) {
                dx -= B.x;
                ext1 -= B.y;
                x = a;
            } else {
                dx += B.x;
                ext1 += B.y;
            }
            ext1 *= x;
            ext1 /= dx;
            ext1 += A.y;
        }

        x = BL.x + A.x;
        a = TR.x + A.x;
        ext2 = -A.y;
        // if the second vertical min/max isn't in (BL.x, TR.x), then
        // find the local vertical min/max on BL.x or on TR.x
        if (a * x > 0) {
            dx = -A.x;
            if (x < 0) {
                dx -= B.x;
                ext2 -= B.y;
                x = a;
            } else {
                dx += B.x;
                ext2 += B.y;
            }
            ext2 *= x;
            ext2 /= dx;
            ext2 -= A.y;
        }
    }

    // check whether rr2(ma) is in the vertical range of colliding with rr1(r)
    // (for the horizontal range of rr2)
    return !((ext1 < BL.y && ext2 < BL.y) ||
            (ext1 > TR.y && ext2 > TR.y));

}


The problem is that the latter two arguments rect takes was changed in sfml2 (takes left,top,width,height now), as a result GetAABB needs a tweak. Top and Left also need manually offsetting to return the co-ords to global as well, as Offset() no longer exists.

prchakal

  • Full Member
  • ***
  • Posts: 142
    • View Profile
Colision with SFML2
« Reply #8 on: February 27, 2011, 08:58:13 pm »
Thanks man, it works perfect.