Advertisement

Spaceolopy

Started by July 25, 2022 01:09 AM
86 comments, last by pbivens67 1 year, 11 months ago

@JoeJ well I looked at your code, I am still unable to do AABB collision detection with multiple objects.

What do you try to achieve? What have you tried? And what does not work?
And, are you sure it properly works with some other case, like using just two objects?

Advertisement

well, I am able to use AABB collision detection to engage one object but when the bullet hits the bug all the bugs disappear. I am using a for loop to draw 5 rows and 8 columns of bugs just like in space invaders.

pbivens67 said:
but when the bullet hits the bug all the bugs disappear.

I guess you have one bug more than you think you have \:D/

Potential bug could be accidentally calculating the same bounding box for all bugs, or something is wrong with damage distribution.

Anyway, post code if you can't find it. To find it quickly, i'd suggest again to use the debugger to follow code execution line by line.

well, here is my code for collision detection for one bullet and one bug

void coll_ship_one()
{
	//draw bullet
	float x = -10.0f + move_x;
	float y = -90.0f + bullet;
	float oWidth = 5.0f;
	float oHeight = 5.0f;
	//draw bug
	float xTwo = -10.0f;
	float yTwo = 90.0f;
	float oTwoWidth = 10.0f;
	float oTwoHeight = 10.0f;

	if (checkCollide(x, y, oWidth, oHeight, xTwo, yTwo, oTwoWidth, oTwoHeight) == 1)
	{
		coll = 1;
		coll_count++;
		if (coll_count >= 1)
		{
			coll_count = 1;
		}
		cout << coll << " " << coll_count << endl;
		glutPostRedisplay();
	}
}

pbivens67 said:
void coll_ship_one()

Wow. That is incredible.

🙂🙂🙂🙂🙂<←The tone posse, ready for action.

Advertisement

pbivens67 said:
well, here is my code for collision detection for one bullet and one bug

Looks like testing code for the detection to work.

But for a game (thinking of Space Invaders or Galaga), you need something like this (ignoring my proposal to use some AABox struct or base class):


struct GameObject
{
	float x;
	float y;
	float width;
	float height;
	
	bool active;
	int type;
	int state;
	int timer;
	int textureID;
	// ... all kinds of stuff you need
};

Basically, with this approach we try to use on single class for all objects in the game: Enemies, player, and bullets.
The more complex the game becomes, the less practical this approach becomes. Because the single class would grow too large for all the specializations of different objects.
Then we would need some form of compositions, using class hierarchies, or components, etc.
But for simple games the single class approach works fine. Especially if we use bit packing to pack many properties into a single integer value.

After that, you could build your level like that:

GameObject bugs[8 x 5];
GameObject player;
Gameobject bullets[10];
// set their position, set them active, etc.

While you update the games bullets, you could loop over them, and for active ones change position and increase timer.
If the player shoots a bullet, you could loop through all bullets until you find one which is not active, to use the found object for the new bullet now activated.
If all 10 would be already active (which should be unlikely due to game design), you could replace the bullet with the largest timer value with the new bullet (effectively replacing the oldest one with a new).
If it happens that bullets often accidentally disappear when shooting new ones, increase the number of 10, or limit players ability to shoot too much bullets in short time, etc.

If a bullet hits a bug, you could disable the bug by setting active to false.
Or better, set its timer to one to indicate it has been hit, and using the timer to display a dying animation to fade out the bug. After the timer has reached some value, finally deactivate the bug.
A deactivated bug (or a bug with timer not zero) can be skipped for the collision detection.

The game collision detection could then look like this:

for (int j=0; j<10; j++)
{	
	if (bullet[j].active == fale)
		continue; 
		
	for (int i=0; i<8x5; i++)
	{
		if (bugs[i].active == false || bugs[i].timer != 0)
			continue;
			
		if (checkCollide(bullet vs. bug) == 1)
		{
			bullet[j].active = false;
			bugs[i].timer = 1;
		}
	}
}

Ofc. you can use unique classes for bugs and bullets, and use different design ideas, etc. That just was an example.
But you should end up with such nested loop to collide each bullet vs. each bug.

Because this nested loop tests everything against any other, it is brute force. If we have thousands of bullets or bugs, or if bugs could collide against each other, we might need some acceleration structure to reduce this work, which was topic of the code posted in the other thread.
But for Space Invaders / Galaga kind of game, brute force is fine.

@JoeJ you mentioned the brute force approach, what is that specifically?

pbivens67 said:
@JoeJ you mentioned the brute force approach, what is that specifically?

To explain, the better example is calculating collisions between ‘all enemies’:
Say we have 1000 enemies in our game, all running into individual directions, and we want to prevent them from running through each other.
Then we need to collide each enemy with each other enemy, which is what ‘brute force' means. It gives us 1000 x 1000 collision checks to do.
We can optimize this by avoiding double checks. If enemy 5 already did a check with enemy 8, no more need to check 8 with 5 as well.
This gives us the following nested loop:

for (int a=0; a<1000-1; a++) 
for (int b=a+1; b<1000; b++)
{
	Collide (enemy[a], enemy[b]);
}

The loop performs 1000 x 1000 / 2 tests.

Because this method has a time complexity of O(N^2), execution time grows exponentially with increasing counts of enemies. So we should do it only for a small number like 100 enemies.
If we need more enemies, we can use a spatial acceleration structure, e.g. a regular grid.
We link enemies to grid cells, so after that we only need to check grid cells adjacent to the current cell one enemy has, to find nearby and potentially colliding other enemies.
As a result, each enemy will perform tests only for a small number of other enemies. If we treat the average of this number as a constant, we get time complexity of O(N).
We no longer check every enemy against each other, so we no longer use a brute force method.

However, linking enemies to a grid, and iterating adjacent cells, has some cost too. It also increases code complexity.
Thus the improved method is only worth it if our numbers are large enough.
So it depends on how many bugs and bullets you have.
But no matter how much exactly, you don't need to collide one bug with all other bugs, and neither one bullet with all other bullets.
So a O(N^2) problem can't happen to you, and very likely the simple brute force approach is better or at least good enough.

@JoeJ

JoeJ said:
If we need more enemies, we can use a spatial acceleration structure, e.g. a regular grid.

can you explain regular grid

This topic is closed to new replies.

Advertisement