Enemy shooting

Started by
18 comments, last by Suen 11 years, 7 months ago
I'm creating a very simple 2D game in C++ (with a given external library) where I might have something like 20-30 enemy sprites on the screen from the beginning. I keep track on whether the enemy is alive or not through a member variable of the enemy object (simply a bool variable).

Now I want to have one random enemy of these 20-30 enemies to shoot a bullet and I want this to happen periodically. So for example every two seconds one enemy should be shooting a bullet. First time it might be the first enemy, second time might be the 10th enemy etc. I thought I could keep this simple by just generating a random number within a limit (which is the number of enemies) and use that number to determine which enemy that will shoot. The issue here is that an enemy can only shoot if it is alive, and if I have...say 20 enemies and 19 of them are dead I will keep generating random numbers until I get that very specific number of the remaining enemy that is alive and that feels like quite a waste of computations, basically a very inefficient way of doing it.

Surely there are better ways of doing this? The problem is that I'm not quite sure on what to search for on the net when it comes to this.
Advertisement

header:
int m_FrameTime; // Initialized on zero in the cpp
int m_ShootCounter; // Initialized on a certain number of frames.

cpp:
// In the constructor(or initialize)
m_FrameTime = 0;
m_ShootCounter = 2; // 2 frames for example

//in the gamecycle(or gametick):
if(m_FrameTime > m_ShootCounter) // When my frametime reached the amount of frames of the shootcounter, search for a random enemy
{
if(m_pEnemyList->Size() > 0 )
{
int random = rand()%(m_pEnemyList->Size()-1); // Creates a random number from zero to the maximum number of enemies
/*NOTE: array starts from zero until the 'size-1', so if the last enemy is random-ed and you don't add a -1 to it, you are out of the array! */
m_pEnemyList->At(random)->ShootBullet();
}
m_FrameTime = 0 // Reset frameTime
}

++m_FrameTime;
I guess that you are storing your enemies in an array since they can either be set as alive or dead.

Just read EngineProgrammer's answer, and his code has an m_pEnemyList. It's not defined in his code, but it seems to be a vector.

Going with that, you add your living enemies to the vector, while still using the array as a data pool to spawn new enemies and keep dead ones. The vector would have pointers to the enemies that are alive in the array, and you would query a random index for the vector.

New game in progress: Project SeedWorld

My development blog: Electronic Meteor


I guess that you are storing your enemies in an array since they can either be set as alive or dead.

Just read EngineProgrammer's answer, and his code has an m_pEnemyList. It's not defined in his code, but it seems to be a vector.

Going with that, you add your living enemies to the vector, while still using the array as a data pool to spawn new enemies and keep dead ones. The vector would have pointers to the enemies that are alive in the array, and you would query a random index for the vector.


You are correct that I have an array where I have stored my enemies in. Going by the two answers given by you, I would at the start of the game have a vector of pointers to all of my enemies and as soon as a certain enemy is dead I should remove the pointer to this enemy from this vector, correct?. Yes this does basically reduce the amount of enemies that can shoot each time so it does solve the problem. But doesn't this also mean that each time I remove an element from the vector all the data in it has to be moved due to the nature of the stl vector? Is there a way of avoiding all that shuffling of data inside the vector? Or perhaps this movement of data in the vector isn't expensive due to the fact that it only consist of pointers?

[quote name='CC Ricers' timestamp='1346355995' post='4974892']
I guess that you are storing your enemies in an array since they can either be set as alive or dead.

Just read EngineProgrammer's answer, and his code has an m_pEnemyList. It's not defined in his code, but it seems to be a vector.

Going with that, you add your living enemies to the vector, while still using the array as a data pool to spawn new enemies and keep dead ones. The vector would have pointers to the enemies that are alive in the array, and you would query a random index for the vector.


You are correct that I have an array where I have stored my enemies in. Going by the two answers given by you, I would at the start of the game have a vector of pointers to all of my enemies and as soon as a certain enemy is dead I should remove the pointer to this enemy from this vector, correct?. Yes this does basically reduce the amount of enemies that can shoot each time so it does solve the problem. But doesn't this also mean that each time I remove an element from the vector all the data in it has to be moved due to the nature of the stl vector? Is there a way of avoiding all that shuffling of data inside the vector? Or perhaps this movement of data in the vector isn't expensive due to the fact that it only consist of pointers?
[/quote]

Yes, the vector would have to move all the data after the erased element down one position. The operation takes linear time whether it holds pointers or not, but for 30 enemies this is not a big deal and you won't notice a performance hit.

New game in progress: Project SeedWorld

My development blog: Electronic Meteor

But doesn't this also mean that each time I remove an element from the vector all the data in it has to be moved due to the nature of the stl vector? Is there a way of avoiding all that shuffling of data inside the vector? Or perhaps this movement of data in the vector isn't expensive due to the fact that it only consist of pointers?

If you do not care too much about the ordering of the pointers inside the element, you can swap the element to be deleted with the last element in the array then erase the last element in the array.
EngineProgrammer provided a nice solution

Something far more simple would be to:
keep track of how many enemies are alive (variable initialized with number of enemies and decremented each time one dies);
using the same process he described to do this at certain intervals: generate a random number using the number of living enemies as your cap, and iterate through your enemies array, skipping dead ones, while decrementing the random number, and have the enemy shoot when your random number is 0
Hope that makes sense biggrin.png

Some pseudo code could help:
int totalEnemies = 30;
int livingEnemies = totalEnemies;
Enemy[30] enemies;

// in code region dealing with enemy death
livingEnemies--;
//

// on iterval for enemy to shoot
if(livingEnemies > 0)
{
int randNum = Math.Rand(0, livingEnemies); // generates a random integer between bounds, lower exclusive, upper inclusive
for(int i = 0; i < totalEnemies; i++)
{
if(enemies.isAlive)
{
randNum--;
if(randNum == 0)
{
// Enemy shoots
}
}
}
}
//
I disagree with deleting an enemy at run-time.

Assume you are creating a game World Of Warcraft: ph34r.png There is a mob you are killing. The mod has like 40items carrying, position, rotation, etc. All stored in data members. And then... You kill it in run-time. The mob is gone.. And the world continues happily ever after. But then... unexpected The mob has a re-spawn!! ph34r.png BAM! Enemy has been allocated again! 40items, position, rotation, and many more data members created in Run-time.

I think we all know what will happen? If not: the game have a possibility of lag. always try to avoid lag so never ever allocate an object at run-time. ( unless it's a temporary local data variable or something.


Solution: The enemy has a "bool m_IsKilled" or somethng. You only calls Ticks, Paints, Checks on the Enemy when he is still alive.

Some pseudo code could help:
int totalEnemies = 30;
int livingEnemies = totalEnemies;
Enemy[30] enemies;

// in code region dealing with enemy death
livingEnemies--;
//

// on iterval for enemy to shoot
if(livingEnemies > 0)
{
int randNum = Math.Rand(0, livingEnemies); // generates a random integer between bounds, lower exclusive, upper inclusive
for(int i = 0; i < totalEnemies; i++)
{
if(enemies.isAlive)
{
randNum--;
if(randNum == 0)
{
// Enemy shoots
}
}
}
}
//



Won't work.

So you have 30 enemies. Let us say I have killed the 2nd, 4th, 6th one. So 27 enemies left.

the rand() seeder will only give me a number from 0-27.
Meaning, if I get the number 0, 4, 6 those enemies will try to shoot but they are dead..
Also means the last 3 enemies will never be able to shoot a bullet.

Won't work.

So you have 30 enemies. Let us say I have killed the 2nd, 4th, 6th one. So 27 enemies left.

the rand() seeder will only give me a number from 0-27.
Meaning, if I get the number 0, 4, 6 those enemies will try to shoot but they are dead..
Also means the last 3 enemies will never be able to shoot a bullet.

You must have misread the code or I made a mistake, but it is not accessing the array using the random number as an index, it is iterating through the array and every time an enemy is alive, it decrements its counter and if the counter is zero, meaning that this enemy is the nth living one, it will then have it shoot

This topic is closed to new replies.

Advertisement