1

I am making a prototype for a game, and am trying to make it so that the characters have spawned in a number of random places, and each will get a random X and Y coordinate that they will go to, arrive, and move to a new one. So far, I am having an issue where they all receive the same coordinates to travel to, and not getting new coordinates either. Any help would be greatly appreciated. Below is a rough code reading of what I have done so far:

private void MakeShootEnemies()                                 //creates the function for shootEnemy creation
{
    PictureBox shootEnemy = new PictureBox();                   //initialises the creation of picturebox
    shootEnemy.Tag = "shootEnemy";                              //tags the picturebox
    shootEnemy.Image = Properties.Resources.RangeScientistTransparent;     //inserts the scientist image to the picture box
    shootEnemy.Left = randNum.Next(100, 1820);                  //creates a random x coordinate for the enemy to spawn on
    shootEnemyLeft = shootEnemy.Left;
    shootEnemy.Top = randNum.Next(100, 920);                    //creates a random y coordinate for the enemy to spawn on
    shootEnemyTop = shootEnemy.Top;
    Size size = new Size(75, 100);                              //creates a size for the box to be
    shootEnemy.Size = size;                                     //sets the box to said size
    shootEnemy.SizeMode = PictureBoxSizeMode.StretchImage;      //makes the image fit to the picturebox
    shootEnemy.BackColor = Color.Transparent;                   //should make the background transparent (doesnt work and will probably remove)
  
    shootEnemiesList.Add(shootEnemy);                           //adds enemy to enemies list
    this.Controls.Add(shootEnemy);                              //adds the controls for the enemy to the form
    player.BringToFront();                                      //brings the player to the front of the screen
    healthBar.BringToFront();
    shootXDestination = randNum.Next(100, 1820);
    shootYDestination = randNum.Next(100, 920);
}

^Function that creates the enemies^

private void ShootEnemyMovement()
{
    foreach (Control y in this.Controls)
            {               
            
                shootXDestination = randNum.Next(0, 1820);
                shootYDestination = randNum.Next(100, 920);
            
            }
}

^Function that should give a new random value when arriving at the previous destination^

I have also tried to do this with the randNum function within the spawning of the enemies, as shown below:

for (int i = 0; i < 2; i++)               //spawns the number of shoot enemies needed to take the total enemy count to 10
{
    MakeShootEnemies();
    shootXDestination = randNum.Next(100, 1820);
    shootYDestination = randNum.Next(100, 920);
}

(number will differ in future but this is for testing purposes)

The randNum function is initialized as follows:

Random randNum = new Random();

Below is the movement itself:

foreach (Control y in this.Controls)                            //makes the shoot enemies easier to control
            {
                if (y is PictureBox && (string)y.Tag == "shootEnemy")
                {
                    if ((y.Left == shootXDestination && y.Top == shootYDestination) || (y.Left == shootEnemyLeft && y.Top == shootEnemyTop))
                    {
                        ShootEnemyMovement();
                    }

                    if (y.Left > shootXDestination)
                    {
                        y.Left -= enemySpeed;
                    }

                    if (y.Left < shootXDestination)
                    {
                        y.Left += enemySpeed;
                    }

                    if (y.Top > shootYDestination)
                    {
                        y.Top -= enemySpeed;
                    }

                    if (y.Top < shootYDestination)
                    {
                        y.Top += enemySpeed;
                    }
                }
            }

nat_to_han
  • 11
  • 2
  • 3
    Try `Random.Shared` instead of `randNum`. It seems that `randNum` *recreates* `Random` for each call. In case of early c# versions (no `Random.Shared`), use just *one* `static` `Random` instance – Dmitry Bychenko Mar 07 '23 at 09:50
  • i think the issue is that you reinitialize the `randNum` somewhere; so it starts the same "random" list; please add to your question where it is initialized or where does it come from – zedling Mar 07 '23 at 09:52
  • I added at the end of the question how the randNum is initialized – nat_to_han Mar 07 '23 at 09:56
  • Be aware that "Random" is only _pseudo_ random. If you create it with the same seed, you'll get the exact same numbers every time. – Fildor Mar 07 '23 at 09:56
  • Maybe use some code from this post and exclude numbers? https://stackoverflow.com/questions/18484577/how-to-get-a-random-number-from-a-range-excluding-some-values – MrSpt Mar 07 '23 at 10:08
  • @Fildor is there a function to make it true random rather than pseudo random? – nat_to_han Mar 07 '23 at 10:12
  • Nope. Just adapt your usage of it according to the answer. That's what we all do. – Fildor Mar 07 '23 at 10:13
  • Are you *sure* that the code inside the `if` in the `ShootEnemyMovement()` method is actually being called? The code looks suss - is that really the entire method? – Matthew Watson Mar 07 '23 at 10:16
  • @MatthewWatson there is some extra, the movement of the enemies themselves is not an issue, that is in a timerEvent, the idea behind ShootEnemyMovement is that it is called when the enemies reach the desired position, in order to generate a new position – nat_to_han Mar 07 '23 at 10:22
  • You didn't answer the question though - is the code inside the `if` definitely being executed? – Matthew Watson Mar 07 '23 at 10:23
  • @MatthewWatson sorry, it is not, when the enemies reach the position they just stay there, although I have now changed that, and am about to edit the snippet in the original question – nat_to_han Mar 07 '23 at 10:25

1 Answers1

4

It seems that you re-create (re-initialize) Random instance for each call, e.g.

// Creates new Random on each call
// Wrong approach: you are going to have new Random instance 
// each time you address the property 
private Random randNum => new Random();

You can either try to use Random.Shared instead of randNum and let .Net do the work for you, or, if you have an old version of c# (no Random.Shared available), create Random manually, but just once:

// Field which is initialized just once
// Not thread safe
private static readonly Random randNum = new Random();

or

// Readonly property which is initialized just once
// Not thread safe
private static Random randNum {get;} = new Random();
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • Hello, thank you for your answer. I have tried this but to no avail. The enemies still go to the same place on the screen as each other (a different location with each new instance) – nat_to_han Mar 07 '23 at 10:06
  • @nat_to_han: Are you sure that `randNum` is **static**, i.e. just one for the entire program? `private static readonly Random randNum = new Random();` – Dmitry Bychenko Mar 07 '23 at 10:11
  • Yes, I copied and pasted from your snippet, replacing the original initialization – nat_to_han Mar 07 '23 at 10:13