Tablica z obiektami i wartość Random

0

Witam uczę się C# i napotkałem swoją pierwszą przeszkodę, której nie mogę przejść sam. Mam problem z przypisaniem losowej wartości do każdego obiektu z tablicy. Od razu pokażę kod.
Klasa do tworzenia obiektów, które będą poruszać się po trasie:

public class Greyhound
    {
        public int StartingPosition = 23;
        public int RacetrackLength;
        public PictureBox MyPictureBox = null;
        public Random MyRandom = new Random();

        public bool Run()
        {
            int Randomizer = MyRandom.Next(1, 10);

            MyPictureBox.Left += Randomizer;

            if (MyPictureBox.Left >= RacetrackLength - MyPictureBox.Width)
            {
                return true;
            }
            else
                return false;
        }
    }
 

Form1

 public partial class Form1 : Form
    {
        Greyhound[] hounds = new Greyhound[4];

        public Form1()
        {
            InitializeComponent();
        }


        public void MakeHounds(int index, PictureBox PictureBoxHound)
        {
            if (hounds[index] == null)
            {
                hounds[index] = new Greyhound();
                hounds[index].MyRandom = new Random();
                hounds[index].MyPictureBox = PictureBoxHound;
                hounds[index].RacetrackLength = pictureBox1.Width;
                timer1.Start();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MakeHounds(0, pictureBox2);
            MakeHounds(1, pictureBox3);
            MakeHounds(2, pictureBox4);
            MakeHounds(3, pictureBox5);
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            
            for (int i = 0; i < 4; i++)
            {
                if (hounds[i] != null)
                    hounds[i].Run();                   
            } 
        }
    }

Problem polega na tym, że wszystkie obiekty poruszają się z tą samą prędkością. Ja rozumiem to tak, że ze każdym razem gdy tworzymy Greyhound każdy z nich otrzymuje nową wartość Randomizer, no ale tak się nie dzieje. Czego nie widzę, co jest nie tak?

0

Ech, same dziwy w tym kodzie.
Po pierwsze, w klasie Greyhound masz obiekt typu Random o nazwie MyRandom. UTWORZONY obiekt. Więc po co go jeszcze raz tworzysz w MakeHounds? To nie ma żadnego sensu. Poza tym obiekt klasy Random powinien być jeden w całej aplikacji, a nie różne obiekty w różnych klasach. Musisz mieć jeden obiekt Random w całej aplikacji. Możesz to zrobić na kilka sposobów:

  • statyczny obiekt w klasie Greyhound (co jest bez sensu, bo co ma Random do Greyhound?)
  • jakiś własny statyczny helper
  • jakiś singleton, który zajmuje się wieloma rzeczami (co też jest bez sensu, bo klasa powinna zajmować się jedną, konkretną rzeczą).

Więc najlepiej będzie napisać sobie statycznego helpera, np:

public static class RandomHelper
{
    static Random m_random = new Random();

    public static int NextInt(int a, int b)
    {
        return m_random.Next(a, b);
    }
}
 

Coś w ten deseń.

Widzę jeszcze jedną bardzo niepokojącą rzecz.

for (int i = 0; i < 4; i++)
{
if (hounds[i] != null)
hounds[i].Run();
}

Dlaczego akurat 4? Skąd Ci się to wzięło? Bo tworzysz teraz 4 obiekty? A jeśli za miesiąc będą 3 albo 10? Będziesz przez godzinę szukał, dlaczego Ci nie działa albo się coś wywala?

Ograniczeniem pętli w takim wypadku ma być wielkość tablicy. Czyli: hounds.Length, a nie 4. Poza tym dużo lepiej będzie jeśli zamiast tablicy posłużysz się listą:

List<Greyhound> hounds = new List<Greyound>();

Potem już możesz sobie dodawać za pomocą metody Add nowe obiekty do listy.
I wtedy sprawdzać ilość tych obiektów właściwością Count:

for(int i = 0; i < hounds.Count....)

Tworzenie tych obiektów też jest bez sensu. Powinieneś to robić w pętli:

//zakładając, że hounds to lista
for(int i = 0; i < ile_chce_miec_obiektow; i++)
  hounds.Add(new Greyhound(jakis_tam_picturebox));
 

Zauważ, że zmieniłem Ci konstruktor. Z Twojego kodu wynika, że obiekt Greyhound bez PictureBoxa nie ma sensu. Konstruktor służy do tego, żeby utworzyć obiekt, który jest gotowy do wykorzystywania. Więc powinien żądać od Ciebie.... nie PictureBoxa, tylko bitmapy (Bitmap, Image). Dlatego, żeby bardziej oddzielić zachowanie klasy od wyglądu aplikacji. Z punktu widzenia prawidłowej obiektowości też robisz to źle, bo tak naprawdę, to klasa obiekt Greyhound powinien sam się rysować w odpowiednim miejscu i czasie. Ale to już inne zagadnienia. Rozpocząłeś moim zdaniem trochę ze zbyt dużego kopyta. Powinieneś najpierw skupić się na jakiś prostszych aplikacjach.

1 użytkowników online, w tym zalogowanych: 0, gości: 1