0
\$\begingroup\$

I am currently coding a simple Monogame Space Shooter.

I have almost finished my enemy shooting behaviour, but I spent a long time on fixing it and got to the point where I wanted somebody to help me out.

Okay so basiclly I have my 9 enemies (instances of Enemy class) in my Level class, and in level update I do stuff like checking if enemy has been hit by player, if they are Dead so I can remove them from the list etc.

I made a simple Timer class that has only 1 function, uses

var timer += GameTime.ElpasedGameTime.TotalMiliseconds

and simply checks if timer is bigger or equal than function input parameter(or argument?), and func is a bool so it then returns T or F.

Now inside my Enemy.cs claas I have this function:

public bool IsShooting()
        {
            if (enemyTimer.Wait(randomFloat))
            {
                shot = true;
                return true;
            }
            else
            {
                shot = false;
                return false;
            }
        }

enemyTimer = new Timer() & randomFloat = field(variable at the top of the class) in my Enemy class.

And now last but not least(actually the problem here) is this, so now in my Level class I got this little update function:

public void Update(Weapon weapon)
        {
            if (enemies.Count == 0)
                isFinished = true;

            if(!isFinished)
            {
                for (int i = 0; i < enemies.Count; ++i)
                {
                    if (enemies[i].shot)
                    {
                        seconds = rand.Next(1, 10);
                        randMiliseconds = 1000f * seconds;
                    }

                    enemies[i].randomFloat = randMiliseconds;
                    enemies[i].Update();

                    if (enemies[i].isDead == true) // If enemy is dead, remove it from level
                    {
                        enemies.RemoveAt(i);
                        --i;
                    }

                    foreach (Bullet bullet in weapon.bullets)
                    {
                        if ( !(i < 0) && weapon.ShotEnemy(bullet, enemies[i])) // If not enemies count == 0 and if 
                        {                                                      // enemy has been shot decrease its health 
                            enemies[i].Health -= weapon.Damage;                          // and set bullet visibility to false;
                            bullet.isVisible = false;                                                     
                        }
                    }

                }

            }

        }

This for loop goes through all the enemies, first if block is used for checking that if the enemy has shot the bullet, then set random value again to something different, if shot has not yet been fired then use the old value and wether it has been changed or not it sets randomFloat field in Enemy class to that value.

Now this is how it works: First all of 9 enemies shoot 1 bullet at the same time (Just about when I open the window, cause I putted randomFloat = 1000f; in my Enemy CTOR), and then randomFloat value is set in Level class to something different, I have message output and FOR EVERY DAMN ENEMY randomFloat is the same.... now that is a problem, I want the rand value to be different for all of them, and it should, right? Becouse those 9 enemies are all different instances of that class and if in each for(;;) loop cycle in my Level.Update() if it gets positive value that enemies[index] has fired a shot it should change it to some number that is very unlikly to be the same for all 9 enemies (seconds = rand.Next(1,20); randomFloat = 1000 * seconds; ). So basiclly randomFloat get random, but it is the same every time for all enemies, and they all shot and will shot at the same random Time

Expected result: Every enemy shooting at different random time

\$\endgroup\$
2
\$\begingroup\$

Update: Rerun through your code, probably found the culprit:

if (enemies[i].shot)
                    {
                        seconds = rand.Next(1, 10);
                        randMiliseconds = 1000f * seconds;
                    }

                    enemies[i].randomFloat = randMiliseconds;
                    enemies[i].Update();

In the for loop you are assigning the randomFloat value regardless if it has been updated after the first Enemy shot its projectile. Thus each enemy onwards will always get the same value, since they'll get that interval before they fire themselves and can generate a new value.

You should include the enemies[i].randomFloat = randMiliseconds;

In the Shot checking aswell.

\$\endgroup\$
  • \$\begingroup\$ I did that and it changed nothing, all random values for each enemy instance are still the same. So basiclly they every - 10 seconds randomly shoot bullets all 9 at the same time. \$\endgroup\$ – Bruno Filip Nov 21 '16 at 14:05
  • \$\begingroup\$ Okay, rerun through your code and this should be the culprit: if (enemies[i].shot) { seconds = rand.Next(1, 10); randMiliseconds = 1000f * seconds; } enemies[i].randomFloat = randMiliseconds; enemies[i].Update(); At this point you update the randomfloat regardless if the earlier shot has been fired or not, thus Enemy[0] fires - second enemy gets the same firing interval and so on. \$\endgroup\$ – Razeal Nov 21 '16 at 14:21
  • \$\begingroup\$ I'll update the answer to show it better. \$\endgroup\$ – Razeal Nov 21 '16 at 14:22
  • \$\begingroup\$ Oh I was just writing my answer above for 10 mins and didn't see yours they are about the same becouse I think that maybe it would even work if I putted that line of code in if(enemies[].shot) Thanks :) \$\endgroup\$ – Bruno Filip Nov 21 '16 at 14:45
  • 1
    \$\begingroup\$ Whatever works. :) I'm glad you found a fix aswell. Mark whichever answer you feel like so that the question can be closed. \$\endgroup\$ – Razeal Nov 21 '16 at 14:59
0
\$\begingroup\$

Can not see this part of your code, but could it be that you are initializing a new Random rand object on every iteration?

That could make it start on the same sequence each time always giving the same number. Instead you should reuse the same object instance without doing

Random rand = new Random();

in between the rand.Next calls.

This explains the background further and also mentions that objects created within 15 milliseconds tend to get identical number sequences: https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx

\$\endgroup\$
  • \$\begingroup\$ Well i do the rand = new Random; only at the Level Initialize() function that gets called only at the Main Game Class Initialize method which is called only once per program run expect if not called by a programmer and I didn't call it \$\endgroup\$ – Bruno Filip Nov 20 '16 at 20:06
  • \$\begingroup\$ and then are you using rand.Next()? \$\endgroup\$ – lozzajp Nov 21 '16 at 8:57
  • \$\begingroup\$ Program does rand.Next(); each time the shot bool of an enemy is true. shot == true when enemyTimer(field in Enemy class of my type timer((has a Wait(Float) method))) returns true(when timer.Wait(randomFloat) has ticked off it returns true) else shot == false \$\endgroup\$ – Bruno Filip Nov 21 '16 at 12:02
  • \$\begingroup\$ Then this is likely not the problem in your case. I might have a look again later if I can recreate your problem and provide a better answer. \$\endgroup\$ – SpacemanSpiff Nov 21 '16 at 12:41
0
\$\begingroup\$

I found a solution to my problem, well at least where it came from, and it came from here:

public void Update(Weapon weapon)
    {
        if (enemies.Count == 0)
            isFinished = true;

        if(!isFinished)
        {
            for (int i = 0; i < enemies.Count; ++i)
            {

if (enemies[i].shot)                           
{                                              
    seconds = rand.Next(1, 10);                 // THIS---------------------
    randMiliseconds = 1000f * seconds;          // THIS---------------------
}      

               //THIS line below gets deleted after the solution below becouse I dont even use randMiliseconds variable anymore
               enemies[i].randomFloat = randMiliseconds; 

                enemies[i].Update();

                if (enemies[i].isDead == true) // If enemy is dead, remove it from level
                {
                    enemies.RemoveAt(i);
                    --i;
                }

                foreach (Bullet bullet in weapon.bullets)
                {
                    if ( !(i < 0) && weapon.ShotEnemy(bullet, enemies[i])) // If not enemies count == 0 and if 
                    {                                                      // enemy has been shot decrease its health 
                        enemies[i].Health -= weapon.Damage;                          // and set bullet visibility to false;
                        bullet.isVisible = false;                                                     
                    }
                }

            }

        }

I made a function which gets that enemys instance and changes its value directly:

if (enemies[i].shot)
 {
     EnemyRandom(enemies[i]);
 }

 void EnemyRandom(Enemy enemy)
        {
            enemy.randomFloat = (rand.Next(1, 10) * 1000f);
        }

Now it works better I should play around to make it even more randomized becouse still like 3 or 4 of them somtimes shoot at the same time :P

Thank you everyone for helping out

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.