狗的速度一样快

5
我正在做《Headfirst C#》的第一个实验,遇到了一个问题:我的程序中的狗以相同的速度行动。我不明白为什么会这样,因为在我的眼中每个对象实例都会随机添加1到5像素的X坐标。这种特性的随机性应该足够产生足够的差异。
因此,由于我不想发布整个实验一的类集合,我重新创建了一个小而独立的版本,其中只有两条赛狗,没有博彩方面的内容。
Form1.Designer包含: - 两个带有猎犬图片的图片框。 - 一个开始按钮。
Greyhound.cs类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace test
{
    public class Greyhound
    {
        public int DogID;
        public PictureBox myPictureBox;
        public Point StartingPosition;
        public Point CurrentPosition;
        public Random Randomizer;

        public bool Run()
        {
            int AddDistance = Randomizer.Next(1, 7);
            CurrentPosition.X += AddDistance;
            myPictureBox.Location = CurrentPosition;

            if (CurrentPosition.X > 600)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public void ReturnToStart()
        {
            CurrentPosition = StartingPosition;
            myPictureBox.Location = StartingPosition;
        }
    }
}

Form1.cs 类:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace test
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Greyhound One = new Greyhound() { DogID = 1, myPictureBox = pictureBox1, StartingPosition = pictureBox1.Location, CurrentPosition = pictureBox1.Location, Randomizer = new Random() };
            Greyhound Two = new Greyhound() { DogID = 2, myPictureBox = pictureBox2, StartingPosition = pictureBox1.Location, CurrentPosition = pictureBox2.Location, Randomizer = new Random() };
            if (One.Run())
            {
                timer1.Enabled = false;
                MessageBox.Show("Dog One WON!");

            }
            else if (Two.Run())
            {
                timer1.Enabled = false;
                MessageBox.Show("Dog Two WON!");
            }


        }

        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Enabled = true;
        }
    }
}

有人能看出这个创建方式存在什么问题吗?为什么狗们会以相同的速度奔跑,而不是每次随机1到5个像素。


+1表示已创建简化版本以展示问题。 - Fabio Marcolini
2个回答

2

不要为每只狗传递一个新的随机数,而是这样做:

Random rnd = new Random();
Greyhound One = new Greyhound() { DogID = 1, myPictureBox = pictureBox1, StartingPosition = pictureBox1.Location, CurrentPosition = pictureBox1.Location, Randomizer = rnd };
Greyhound Two = new Greyhound() { DogID = 2, myPictureBox = pictureBox2, StartingPosition = pictureBox1.Location, CurrentPosition = pictureBox2.Location, Randomizer = rnd  };

解释
这是因为Random对象实际上是半随机的,它们生成一系列随机数,该随机数是通过使用给定的种子号进行计算的。 如果您使用Random()构造函数,则此种子会在运行时自动生成。但是,如果您按顺序创建两个Random对象,就像您在代码中所做的那样,生成的种子将相等,因此两个随机数生成器生成的数字也将相同。

您可以尝试一个更简单的例子:

        //Your two dogs have two new Random instantiated in sequence.
        //The two random numbers will be always the same
        bool areTheSame = new Random().Next() == new Random().Next();
        Console.WriteLine("two dogs with two Random are the same? "+ areTheSame);
        Random rnd = new Random();

        //The two dogs have now the same random object.
        //The two random numbers will be almost always different. Almost because the numbers are random and two or more equals number can occur in sequence.
        areTheSame = rnd.Next() == rnd.Next();
        Console.WriteLine("two dogs using the same random are the same? ~" + areTheSame);
        Console.ReadLine();

正确,但最好解释一下为什么这个解决方案有效。 - Sergey Berezovskiy
1
我在回答完之后立即开始这样做。 - Fabio Marcolini

2
问题出在Random类上。当你创建一个没有参数的新对象时,它会使用系统时钟:
默认情况下,Random类的无参构造函数使用系统时钟生成种子值,而其带参数的构造函数可以根据当前时间中的时钟滴答数来取一个Int32值。然而,由于时钟具有有限的分辨率,使用无参构造函数在短时间内创建不同的Random对象会创建产生相同随机数序列的随机数生成器。
你应该只使用一个Random类,并插入不同的生成值作为你的起始速度。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接