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

Author Topic: Vector of Vectors Collision Detection  (Read 2473 times)

0 Members and 1 Guest are viewing this topic.

coltranenaima

  • Newbie
  • *
  • Posts: 11
    • View Profile
Vector of Vectors Collision Detection
« on: May 28, 2018, 04:28:06 am »
Hello,

I am having issues with collision detection of player bullets against enemies.

I have three "types" of enemies and plan on having many more with distinct characteristics.

enemyOne(sf::Color::Yellow, 20.f, 20.f)
enemyTwo(sf::Color::Red, 40.f, 40.f)
enemyThree(sf::Color::Cyan, 80.f, 80.f)

that feed into

std::vector<Enemy> enemiesOne;
std::vector<Enemy> enemiesTwo;
std::vector<Enemy> enemiesThree;

I currently have a not so elegant function that won't scale very well with my goal...however it does work.

void Bullet::BulletEnemyCollision(sf::RectangleShape playerBulletShape, std::vector<Enemy>& enemyVectorsOne, std::vector<Enemy>& enemyVectorsTwo, std::vector<Enemy>& enemyVectorsThree)
{
        for (unsigned int i = 0; i < enemyVectorsOne.size(); i++)
        {
                if (playerBulletShape.getGlobalBounds().intersects(enemyVectorsOne[i].enemyShape.getGlobalBounds()))
                {
                        enemyVectorsOne.erase(enemyVectorsOne.begin() + i);
                }
        }
        for (unsigned int i = 0; i < enemyVectorsTwo.size(); i++)
        {
                if (playerBulletShape.getGlobalBounds().intersects(enemyVectorsTwo[i].enemyShape.getGlobalBounds()))
                {
                        enemyVectorsTwo.erase(enemyVectorsTwo.begin() + i);
                }
        }
        for (unsigned int i = 0; i < enemyVectorsThree.size(); i++)
        {
                if (playerBulletShape.getGlobalBounds().intersects(enemyVectorsThree[i].enemyShape.getGlobalBounds()))
                {
                        enemyVectorsThree.erase(enemyVectorsThree.begin() + i);
                }
        }
}


An idea I have is to feed each enemy vector into a vector and simply have the function iterate through that vector of vectors. This currently does not work.

std::vector<std::vector<Enemy> >& enemyVectors


void Bullet::BulletEnemyCollision(sf::RectangleShape playerBulletShape, std::vector<std::vector<Enemy> >& enemyVectors)
{
        for (unsigned int i = 0; i < enemyVectors.size(); i++)
        {
                for (unsigned int j = 0; j < enemyVectors[i].size(); j++)
                {
                        if (playerBulletShape.getGlobalBounds().intersects(enemyVectors[i][j].enemyShape.getGlobalBounds()))
                        {
                                enemyVectors[i].erase(enemyVectors[i].begin() + j);
                        }
                }
        }
}

Below is a brief recording of the game with the not so elegant code in place.

https://gfycat.com/gifs/detail/LivelySpottedChevrotain

You may notice the lack of pointers and keywords like auto...etc. This game for me is an exercise in learning classes & functions at a basic level. The next game I plan on taking a stab at utilizing pointers and super useful keywords. The last game I made I was using header files for implementation...baby steps.

Thanks for reading and I appreciate the help.


Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Vector of Vectors Collision Detection
« Reply #1 on: May 28, 2018, 08:14:36 pm »
Looping though (iterating) elements in a vector can be done using iterators rather than indices.
For example:
std::vector<int> v;
for (std::vector<int>::iterator it{ v.begin() }; it != v.end(); ++it)
{
    // use 'it' - the iterator; it's used similarly to a pointer.
}
Of course, you can - and probably will most of the time - use auto instead of std::vector<int>::iterator but you mentioned you wanted to avoid it and be explicit.
However, auto makes the line much simpler and clearer:
for (auto it{ v.begin() }; it != v.end(); ++it)

Anyway, one thing to consider applying to your function is to get the player bullet rectangle's global boundaries once at the beginning of the function and then use that to compare intersections. This avoids the 'getting' of the bounds for every collision check for every enemy. Note that this isn't a massive deal really but it seems wasteful if there are a lot of enemies to check.

What doesn't work in your second code? What is passed into enemyVectors? Should it not be a vector of references instead a vector of elements?
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

coltranenaima

  • Newbie
  • *
  • Posts: 11
    • View Profile
Re: Vector of Vectors Collision Detection
« Reply #2 on: May 29, 2018, 04:09:00 am »
Thanks Hapax for helping me out again. I'm watching a youtube tutorial on auto (and glancing at my Stroustrup book), it's simply just ignorance on my part for not knowing useful keywords and how they work. At a glance it just appears to be magic and/or syntax sugar.

Anyway, one thing to consider applying to your function is to get the player bullet rectangle's global boundaries once at the beginning of the function and then use that to compare intersections. This avoids the 'getting' of the bounds for every collision check for every enemy. Note that this isn't a massive deal really but it seems wasteful if there are a lot of enemies to check.

I appreciate this advice, and I will try to make this happen.

What doesn't work in your second code? What is passed into enemyVectors? Should it not be a vector of references instead a vector of elements?

I have an initializer function (English not c++ lol) that loads "enemies" (rectangle shapes) into a vector of "enemy" type...and once that is loaded, I load that vector into a vector (the vector of vectors). I trimmed out the node functionality (enemy movement). I do realize I need to work on my naming conventions...it is confusing to say the least.

void Levels::LevelLoadNodes(Player& pO, Enemy& enemyObject, std::vector<Enemy>& enemy, int numberOfEnemies)
{
        enemyObject.loadEnemies(numberOfEnemies, enemy, enemyObject, pO);
        enemyVectors.push_back(enemy);
 

I am passing that vector of vectors by reference to the player bullet "move" function to check for collisions by iterating through all the enemies while the player bullet is "moving". The function BulletEnemyCollision is my original post.

void Bullet::BulletPlayerMove(float delta, std::vector<std::vector<Enemy> >& enemyVectors)
{
        for (unsigned int i = 0; i < bulletVector.size(); i++)
        {
                bulletVector[i].move(cos(bulletAngleVector[i]) * bulletSpeed * delta, sin(bulletAngleVector[i]) * bulletSpeed * delta);
                bulletTimeFVector[i] = bulletTimeVector[i].getElapsedTime().asSeconds();
                window.draw(bulletVector[i]);
                BulletEnemyCollision(bulletVector[i], enemyVectors);
        }
}

I am gonna take a stab at using auto, thanks again.

« Last Edit: May 29, 2018, 04:11:38 am by coltranenaima »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Vector of Vectors Collision Detection
« Reply #3 on: May 29, 2018, 03:09:22 pm »
So, do loadEnemies copy the enemies onto the single vector?
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*