为啥我的粒子会漂移? (又名是 Math.random() 坏了还是我的算法?)

Posted

技术标签:

【中文标题】为啥我的粒子会漂移? (又名是 Math.random() 坏了还是我的算法?)【英文标题】:Why are my particles drifting? ( aka Is Math.random() broken or is it my algorithm? )为什么我的粒子会漂移? (又名是 Math.random() 坏了还是我的算法?) 【发布时间】:2011-04-21 13:37:44 【问题描述】:

我使用 javascript 粗略地模拟了粒子的布朗运动,但由于某种原因,我不明白我的粒子正在向上和向左漂移。

算法非常简单。每个粒子都是一个div,我只需在每轮divtopleft 位置中添加或减去一个随机数。

我稍微阅读了Math.random(),并尝试使用一个函数返回从minmax 的随机数:

// Returns a random integer between min and max  
// Using Math.round() will give you a non-uniform distribution!  
function ran(min, max)  
  
    return Math.floor(Math.random() * (max - min + 1)) + min;  
 

这是粒子运动的函数:

var x, y, $elie, pos, nowX, nowY, i, $that;    

function moveIt()

    $("div.spec").each(function(i, v) 
        x = ran(-5, 5);
        y = ran(-5, 5);
        $elie = $(v);
        pos = $elie.position();
        nowX = pos.left;
        nowY = pos.top;

          // The min and abs are to keep the particles within a box
          // The drift occurs even if I remove min and abs
        $elie.css("left", Math.min(Math.abs(nowX + x), 515));
        $elie.css("top",  Math.min(Math.abs(nowY + y), 515)); 
    );

下面是粒子最初是如何设置的,setInterval 开始了。

$(function() 
    $("body").append("<div/>").attr("id","box");
    $elie = $("<div/>").attr("class","spec");
    // Note that math random is inclussive for 0 and exclussive for Max
    for (i = 0; i < 25; ++i)
    
        $that = $elie.clone();  
        $that.css("top", ran(0, 495));
        $that.css("left", ran(0, 495));            
        $("#box").append($that);            
              
    timer = setInterval(moveIt, 60);
    $("input").toggle(function() 
        clearInterval(timer);
        this.value = " Start ";
    , function() 
        timer = setInterval(moveIt, 60);        
        this.value = " Stop ";            
    );        
);

我的问题是使用上面的minmax (-5, 5),所有粒子都非常快速地向上和向左漂移。

jsFiddle example of drift (-5, 5)

Example of drift even with the removal of .min() and .abs().

为了解决这个问题,我必须使用 minmax-1, 5

jsFiddle example of no drift (-1, 5)

这是div的CSS所有粒子都包含在:

#box 
    width:500px;
    height:500px;
    border:2px #000 solid;
    position: relative; 

这是每个粒子的默认 CSS:

div.spec 
    width:5px;
    height:5px;
    background-color:#00DDAA;
    position:absolute; 

发生了什么事?为什么-55 的最小值和最大值会导致向上和向左漂移?

随机函数ran() 的测试似乎没有显示出如此持久的负漂移。

jsFiddle example of testing ran()


ran() 函数取自 the MDC Math.random() page

【问题讨论】:

【参考方案1】:

你的错误是使用

pos = $elie.position();

而不是

pos = $elie.offset();

如果将它们添加到父 div,这不会有什么不同,但是您的元素没有正确添加到父 div,它们被直接附加到文档正文中。所以你的另一个错误是:

$("body").append("<div/>").attr("id","box");

如果您希望 div 的 id 为“box”,则该行应为:

$box = $("<div/>").attr("id","box");
$("body").append($box)

否则你实际上是在给“body”一个“box”的id

编辑:

追加 div 的最有效方法如下(如 this post 所述):

$(document.createElement('div')).appendTo('body').attr('id', 'box')

【讨论】:

感谢 Herman,向 DOM 添加元素的各种方式的速度测试来自 [this answer](***.com/questions/327047/…)。 --------------- PS:我正在编辑我的评论,不小心删除了那段代码,然后编辑评论的时间到期了。 这是这个的最终版本(在 IE 中不太好)-fiddle.jshell.net/PppZ3/show/light-我认为这需要另一种解决方案...研究 [Raphael] (raphaeljs.com)【参考方案2】:

不要使用.position(),而是尝试.offset()。看起来像it works。

Position.

Offset。

之所以如此,是因为您在 CSS 中设置了绝对的 'left' 和 'top' 值。相反,你可以使用这个Example:

$elie.css("margin-left", nowX + x);
$elie.css("margin-top",  nowY + y);

【讨论】:

.offset() 似乎确实解决了这个问题。我的粒子包含在父 div 中,所以我认为 .position() 也可以。为什么它不起作用? 这是因为您的 css 设置器设置了一个绝对的“左”和“上”,而不是相对于父级的一个。相反,使用'margin-left'。查看我的编辑。 实际上,父级div 有一个relative 位置,粒子在父级内有一个absolute 位置。这个问题似乎是父母的id 的问题。 啊,有趣。听起来解决根本问题是最好的方法。

以上是关于为啥我的粒子会漂移? (又名是 Math.random() 坏了还是我的算法?)的主要内容,如果未能解决你的问题,请参考以下文章

记录使用 Golang math/rand 随机数遇到的坑

记录使用 Golang math/rand 随机数遇到的坑

math/rand实现简易抽奖

golang之math/rand随机数

Golang之math/rand,双色球预测

UE4 为啥粒子特效放到场景不播放 只有点击播放按钮 才出现