i've reached a good point with my engine, with static/instant collision detection and callbacks in case of collision. By instant collision detection i mean:

  • Object A moves from x1y1 to x2y2
  • Check if A (at x2y2) collides with B

Great for slow moving objects that need to be destroyed upon collision. Terrible for "stop on touch", "bounce" or "slide" interactions.

So i'm extending my engine to support on-movement-collision, for now only supports points as moving objects. The collision is the a line to polygon collision where the starting point of the line is the starting coordinates of the point object, and the end point of the line is where the object would go after moving if there was no collision.

The collision should not just return a true/false value, but also information like the distance to collision, the unit normal vector of the surface it collides with, and the point of collision. These information should allow me to implement the 3 mentioned interactions. (about the tags, i'm not sure whether this is collision detection or prediction)

However while i should have gotten most of the things right, the "bouncing" calculations on sloped lines aren't getting the angle right. I'm really bad at math, and just used some formulas from stackexchange.

Here's the code about collision detection and information returned, after the next horizontal separator is the code for calculating the "bounce" line.

Collision between two lines:

Collision_info Line::collide(Line& l)
    sf::Vector2f p0 = vertices[va].position;
    sf::Vector2f p1 = vertices[vb].position;
    sf::Vector2f p2 = l.vertices[va].position;
    sf::Vector2f p3 = l.vertices[vb].position;

    sf::Vector2f s1, s2;
    s1.x = p1.x - p0.x; 
    s1.y = p1.y - p0.y; 
    s2.x = p3.x - p2.x; 
    s2.y = p3.y - p2.y; 

    float s, t; 

    s = (-s1.y * (p0.x - p2.x) + s1.x * (p0.y - p2.y)) / (-s2.x * s1.y + s1.x * s2.y); 
    t = (s2.x * (p0.y - p2.y) - s2.y * (p0.x - p2.x)) / (-s2.x * s1.y + s1.x * s2.y);

    if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
        { // Collision detected 
        sf::Vector2f c = p0 + (t * s1);
        return { c, l.normal, linelength(p0, c)};
    return Collision_info(); // No collision 

collision between line and polygon:

    Collision_info Line::collide(Polygon& p)
    bool collided = false;
    Collision_info ret;

    for (size_t i = 0; i < p.lines.size(); i++)
        Collision_info tmp = collide(p.lines[i]);

        if (tmp)
            if (collided) { if (tmp.distance < ret.distance) { ret = tmp; } }
            else { ret = tmp; collided = true; }
    if (collided) { return ret; }
    return Collision_info();

Collision informations:

    class Collision_info
        bool collision;
        operator bool() const; //returns collision
        sf::Vector2f collider_normal;
        sf::Vector2f collision_point;
        float distance;
        Collision_info(); //sets collision to false
        Collision_info(sf::Vector2f collision_point, sf::Vector2f collider_normal, float distance);

        //collision_line.move_p2(collide.collision_point + (collide.collider_normal * (line.length() - collide.distance)));

        sf::Vector2f full_line_reflection = -(2.f * (collide.collider_normal * line.unit) * collide.collider_normal - line.unit);
        sf::Vector2f unit_reflection = full_line_reflection / line.length();
        sf::Vector2f remaining_reflection = unit_reflection * (line.length() - collide.distance);
        collision_line.move_p2(collide.collision_point + remaining_reflection);

it feels alright when the polygon has axis-aligned lines, but the angle is quite wrong when not. GitHub link for a quick small project i'm using for testing all this math (sfml for graphics): collisions


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.