随机值似乎不是真的随机吗?

时间:2018-08-10 19:46:36

标签: c# winforms

试图在C#中使用WinForm制作一个简单的杀死细菌的游戏,但是细菌(我暂时使用Panel)似乎并不是随机移动的。

具体来说,我遇到的问题是,细菌试图向左上角移动并仅在那附近移动。理想情况下,细菌需要均匀地在矩形范围内移动,但是我不确定如何实现。 查看下面的 gif 文件。

您会看到红色的Panel仅在左上角左右移动。如何使它均匀且随机地移动到任何地方?

这是我的代码:

private Panel _pnlBacteria;     //Panel representing a piece of bacteria
private Random r = new Random();  //For randomly-generated values
private int _prevX;        //Stores the previous X location
private int _prevY;        //Stores the previous Y location

public Form1()
{
    InitializeComponent();
    _pnlBacteria = new Panel();
    /* Get more property assignments to this._pnlBacteria (omitted) */

    //Bacteria's start position is also randomly selected
    _prevX = r.Next(50, 300);
    _prevY = r.Next(50, 500);
}

//Timer runs every 100 seconds changing the location of the bacteria
private void TmrMoveBacteria_Tick(object sender, EventArgs e)
{
    int x, y;
    //Get random values for X and Y based on where the bacteria was previously
    //and move randomly within ±10 range. Also it cannot go off the screen.
    do 
    {       
        x = r.Next(_prevX - 10, _prevX + 10);
        y = r.Next(_prevY - 10, _prevY + 10);
    } 
    while ((y <= 0) || (y >= 500) || (x <= 0) || (x >= 300));

    //Save the new location to be used in the next Tick round as previous values
    _prevX = x;
    _prevY = y; 

    //Apply the actual location change to the bacteria panel
    _pnlBacteria.Top = y;
    _pnlBacteria.Left = x;
}

我尝试将+10更改为+12,保持原样为-10,但现在这仅使细菌仅移动到右下角。我很茫然。 谁能帮忙吗?

5 个答案:

答案 0 :(得分:22)

如果您阅读Random.next(int,int)的文档,您会发现下限是包含性的,上限是排他性的,这就是-10和+11起作用的原因。

答案 1 :(得分:13)

解决此问题的方法略有不同,可能是选择随机的方向和随机的距离沿该方向行驶。如果我们在改变方向之前增加细菌可以传播的最大距离,这将允许在表单上进行更多的移动。

我们还可以“加权”距离的随机性,以便更频繁地选择较短的距离。这将增加运动方式的多样性和随机性,同时仍允许一些长距离的冲刺到另一个位置。

这里是一个示例,您可以将其复制/粘贴到实现此想法的新表单项目中。您可以使用maxDistance(更改方向之前允许的最远距离)和stepDistanceTimer的每次迭代所经过的距离)的设置进行播放。较小的stepDistance将使运动更平稳,但速度更慢。我把它做的很小,所以我也减小了Interval的{​​{1}}属性以加快速度。

您会注意到,我还添加了一种方法来验证方向是否有效,从而使细菌不会从屏幕上流下。我创建了一个Timer来表示方向,这使检查特定方向上的运动变得容易(即,如果枚举值包含“北”并且我们离顶部太近,那么它是无效方向-涵盖“北”,“西北”和“东北”方向。

编辑:我将“加权距离”列表的创建移至构造函数,并对其进行了修改,以选择指数级减少的项目,而不是线性减少的项目。

希望这是有道理的:

enum

答案 2 :(得分:1)

r.Next的左和右参数分别为包含式和排除式。

x = r.Next(_prevX - 10, _prevX + 10);
y = r.Next(_prevY - 10, _prevY + 10);

因此,此代码的概率空间是(_prevX,_prevY)中心左上方19x19平方英寸。这意味着更可能向左上方移动。

如果我们在右边使用11s,则概率空间是一个以(_prevX,_prevY)为中心的20x20正方形。细菌将移动得更均匀。其在概率平方内的平均位移为零,因此没有一个偏向的方向。但是对角线方向将是有利的,因为对角线位移平均是最大的。根据情况,这可能重要,也可能不重要。

如果我们使用半径和方向as explained by Rufus L,则可以生成更“自然”的圆形概率空间。这就是为什么它是首选方法。

答案 3 :(得分:0)

您应该使用panel.height的大小-square.height的大小与长度相同,而不是常量,如果屏幕尺寸更改,您的游戏仍然可以使用

return;

答案 4 :(得分:0)

问题在于您正在前后移动对象,因为范围是prev-+ 10;

 x = r.Next(_prevX - 10, _prevX + 10);
 y = r.Next(_prevY - 10, _prevY + 10);

您应该为yval和xval添加一个方向标记,并以一定的概率p(小于1/2)对其进行设置,当该标记处于打开状态时向右/向上移动,当其关闭时向左/向下移动,

if (forwardx){
    x = r.Next(_prevX , _prevX + 10);
}
else {
     x = r.Next(_prevX - 10, _prevX );
}
if (forwardy){
    y = r.Next(_prevY , _prevY + 10);
}
else{
    y = r.Next(_prevY - 10 , _prevY );
}

forwardx = r.Next(10) == 1; //p = 0.1
forwardy = r.Next(10) == 1;

祝你好运!