🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Understanding how a collision detection system should work

Started by
12 comments, last by Alberth 4 years, 5 months ago

Sorry, it took me some time, but

  • bitmask is procedural programming
  • callback is functional programming
  • calling a method would be OOP.


Collision is between two object and these objects do nor really have an order which is different then function arguments, which are ordered. So in a language like C++ you would use the double-dispatch pattern, I guess. I hope that collision is a great example to understand that pattern.

4 Month ago there was this large thread on this site how people claim to do ECS, but stubbornly avoid OOP.

Advertisement

In my 2d game engine, collision detection is handled by the sprite class, every sprite checks for a collision IF it is commanded to move in a certain direction, I designed it so that you can actually push a block with another block and that other block would push the other block. On my player class I handle collision detection by getting a 4x4 grid that surrounds the player sprite from the tile map and then run it through the collision detection system via the sprite class.

Here is the function that does all collision checking, you might be able to adapt it to your game implementation, feel free to use my code.

bool SPRITE2D::checkcollision(string pointstr,vector<SPRITE2D>&v_mgsprites,float x)
// This function performs all the game collision checking by request from other sprite objects.
// If there is a collision, the array index is stored in i_spIndex to access the sprite later.
{
    bdnrect = getrect(); // refresh bounding rectangle

    RECT2D mgsprect; // to check 'v_mgsprites' rectangles

    // start search for possible overlapping rectangles
    for(unsigned int i = 0; i < v_mgsprites.size(); i++)
    {
        // skip the sprite requesting the collision
        if(v_mgsprites[i].getid() == i_spriteId) continue;

        // get the bounding rectangle
        mgsprect = v_mgsprites[i].getrect();

        if(pointstr=="left")
        {
            // if the rectangles overlap and we are behind
            if(bdnrect.left - x < mgsprect.right && bdnrect.right > mgsprect.right)
            {
                // a head on collision
                if( (bdnrect.top <= mgsprect.top && bdnrect.bottom >= mgsprect.bottom) ||
                    (bdnrect.top >= mgsprect.top && bdnrect.bottom <= mgsprect.bottom) )
                    { i_spIndex = i; return true; } // store the index, report collision

                // bottom corner collision
                if(bdnrect.top < mgsprect.top && bdnrect.bottom > mgsprect.top
                    && bdnrect.bottom < mgsprect.bottom)
                    { i_spIndex = i; return true; } // store the index, report collision

                // top corner collision
                if(bdnrect.bottom > mgsprect.bottom && bdnrect.top > mgsprect.top
                    && bdnrect.top < mgsprect.bottom)
                    { i_spIndex = i; return true; } // store the index, report collision
            }
        }

        if(pointstr=="right")
        {
            // if the rectangles overlap and we are behind
            if(bdnrect.right + x > mgsprect.left && bdnrect.left < mgsprect.left)
            {
                // a head on collision
                if( (bdnrect.top <= mgsprect.top && bdnrect.bottom >= mgsprect.bottom) ||
                    (bdnrect.top >= mgsprect.top && bdnrect.bottom <= mgsprect.bottom) )
                    { i_spIndex = i; return true; } // store the index, report collision

                // bottom corner collision
                if(bdnrect.top < mgsprect.top && bdnrect.bottom > mgsprect.top
                    && bdnrect.bottom < mgsprect.bottom)
                    { i_spIndex = i; return true; } // store the index, report collision

                // top corner collision
                if(bdnrect.bottom > mgsprect.bottom && bdnrect.top > mgsprect.top
                    && bdnrect.top < mgsprect.bottom)
                    { i_spIndex = i; return true; } // store the index, report collision
            }
        }

        if(pointstr=="down")
        {
            // if the rectangles overlap and we are behind
            if(bdnrect.bottom + x > mgsprect.top && bdnrect.top < mgsprect.top)
            {
                // a head on collision
                if( (bdnrect.left <= mgsprect.left && bdnrect.right >= mgsprect.right) ||
                    (bdnrect.left >= mgsprect.left && bdnrect.right <= mgsprect.right) )
                    { i_spIndex = i; return true; } // store the index, report collision

                // bottom corner collision
                if(bdnrect.left < mgsprect.left && bdnrect.right > mgsprect.left
                    && bdnrect.right < mgsprect.right)
                    { i_spIndex = i; return true; } // store the index, report collision

                // top corner collision
                if(bdnrect.right > mgsprect.right && bdnrect.left > mgsprect.left
                    && bdnrect.left < mgsprect.right)
                    { i_spIndex = i; return true; } // store the index, report collision
            }
        }

        if(pointstr=="up")
        {
            // if the rectangles overlap and we are behind
            if(bdnrect.top - x < mgsprect.bottom && bdnrect.bottom > mgsprect.bottom)
            {
                // a head on collision
                if( (bdnrect.left <= mgsprect.left && bdnrect.right >= mgsprect.right) ||
                    (bdnrect.left >= mgsprect.left && bdnrect.right <= mgsprect.right) )
                    { i_spIndex = i; return true; } // store the index, report collision

                // bottom corner collision
                if(bdnrect.left < mgsprect.left && bdnrect.right > mgsprect.left
                    && bdnrect.right < mgsprect.right)
                    { i_spIndex = i; return true; } // store the index, report collision

                // top corner collision
                if(bdnrect.right > mgsprect.right && bdnrect.left > mgsprect.left
                    && bdnrect.left < mgsprect.right)
                    { i_spIndex = i; return true; } // store the index, report collision
            }
        }
    }

    return false; // no collision
}

arnero said:
Sorry, it took me some time, but bitmask is procedural programming callback is functional programming calling a method would be OOP.

huh?

bitmasks have nothing to do with the type of programming. bit-twiddling (where bitmasks is just one aspect of) is a different view on integer numbers. The common view on integer numbers is that you can store an integer value in it, and add/subtract etc them. You can also see an integer number as eg 32 separate bits, ie you don't care about the numeric value, you only care which of the 32 bits is on or off. This way of looking gives you a set of up to 32 values (or 64 if you pick a longer integer number). The nice property of this view is that bit operations are very very very fast (compared with generic sets) and take very little space. So the next time you have loads of very small sets where the elements can be simply mapped onto a range of 0..31 (or whatever size integer you have), consider using integer as a set of bits.

functional programming is when you don't have assignments. You only have functions and parameters, but no “=” to give a variable a new value. I know it sounds weird ?

An example:

def fact(x):
    if x == 0:
        return 1
    else:
        return x * fact(x - 1)

See? no assignment and you can still compute a factorial. It takes a little getting used to, but the nice thing of functional programming is that variables never change value within one function call. The value of x in the last line is the same as when the function started, always. For complicated functions, that is a very useful property.

A callback is a notification that something has happened or something has been decided. It can be used in procedural (or imperative) programming as well. A common example is event notifications.

A method is indeed an OOP concept, but you don't need an OOP language to do OOP, ie you can code OOP style in C. The core idea of OOP is “smart data”, ie data that has some functions associated to it so you can ask it for information (eg mylist.size()), or ask it to do something (eg mylist.append(element)). You can do this in C too.

struct List mylist; /* my list data */

int size(struct List *lp) { /* compute and return length of *lp */ }
void append(struct List *lp, int element) { /* append ‘element’ to *lp */ }

// and now you can write
size(&mylist);
append(&mylist, element);

A bit more cluttered than a proper OOP language, but the idea of data with a bunch of functions associated to it is there.

This topic is closed to new replies.

Advertisement