Posted in 算法公式和技巧 on 04. 六, 2010
一、基础
先讲讲历史。一天,一个名叫罗伯特-布朗(Robert Brown)的植物学家正在观察一滴水中的花粉颗粒,随后他发现这些花粉是在随机运动的。虽然它们不是水流或水的运动,但是这些小小的颗粒却永远不会停下 来。他发现同样的事情会发生在微尘中,但它们不会像花粉那样游泳。虽然他不知道为什么会有这种现象,其实不只是他还有其他所有人在几十年内都不能给出解 释,但是他却将这种现象用自己的名字命名 —— 只是为了能意识到它!
当今,我们对布朗运动的解释是大量的水分子在一滴水中不断运动,虽然水滴看上去是静止的。这些水分子与花粉和灰尘发生碰撞,将一些动量传给它们。因为即使 是一颗小小的灰尘都要比一个水分子重上一百万倍,所以一次碰撞不会带来多大的影响。但是当每秒有几百万次的碰撞时,那么这些动量就会累计起来。
现在,一些水分子也许撞到了灰尘的一边,而另一些则撞在了另一边。最终,它们会达到总的平均值。但是,随着时间的变化,受到更多撞击的一边就会产生波动, 假设为左边,那么这个粒子就会向右运动一点。底部所受撞击越多,则粒子向上运动得就越多。最后所有的值趋于平均,最终的结果通常不会在任何一个方向产生太 多的动量。这就是随机悬浮动作。
我们可以在 Flash 中轻松地模拟出这种效果。在每一帧中,计算一个随机数加在运动物体的 x 和 y 速度中。随机的数值应该即可以是正数也可以是负数,并且一般来说都非常小,比如范围从 -0.1 到 +0.1。形式如下:
- vx += Math.random() * 0.2 - 0.1;
- vy += Math.random() * 0.2 - 0.1;
用 0.2 乘以一个随机的小数,所得的值从 0.0 到 0.2。再减去 0.1 则值变为 -0.1 到 0.1。在这里加入一些摩擦力(friction)很重要,否则速度会增大,并产生不自然的加速。在 Brownian1.as 中,我创建了 50 个粒子并让它们以布朗运动的形式悬浮。粒子就是我们熟悉的 Ball 类的实例,让它们为黑色并缩小。以下是代码:
- package {
- import flash.display.Sprite;
- import flash.events.Event;
- public class Brownian1 extends Sprite {
- private var numDots:uint=50;
- private var friction:Number=0.95;
- private var dots:Array;
- public function Brownian1() {
- init();
- }
- private function init():void {
- dots = new Array();
- for (var i:uint = 0; i < numDots; i++) {
- var dot:Ball=new Ball(1,0);
- dot.x=Math.random()*stage.stageWidth;
- dot.y=Math.random()*stage.stageHeight;
- dot.vx=0;
- dot.vy=0;
- addChild(dot);
- dots.push(dot);
- }
- addEventListener(Event.ENTER_FRAME, onEnterFrame);
- }
- private function onEnterFrame(event:Event):void {
- for (var i:uint = 0; i < numDots; i++) {
- var dot:Ball=dots[i];
- dot.vx+=Math.random()*0.2-0.1;
- dot.vy+=Math.random()*0.2-0.1;
- dot.x+=dot.vx;
- dot.y+=dot.vy;
- dot.vx*=friction;
- dot.vy*=friction;
- if (dot.x>stage.stageWidth) {
- dot.x=0;
- } else if (dot.x < 0) {
- dot.x=stage.stageWidth;
- }
- if (dot.y>stage.stageHeight) {
- dot.y=0;
- } else if (dot.y < 0) {
- dot.y=stage.stageHeight;
- }
- }
- }
- }
- }
二、拓展
1、方形分布
- package {
- import flash.display.Sprite;
- public class Random2 extends Sprite {
- private var numDots:uint=300;
- public function Random2() {
- init();
- }
- private function init():void {
- for (var i:uint = 0; i < numDots; i++) {
- var dot:Ball=new Ball(1,0);
- dot.x = stage.stageWidth / 2 + Math.random() * 100 - 50;
- dot.y = stage.stageHeight / 2 + Math.random() * 100 - 50;
- addChild(dot);
- }
- }
- }
- }
2、圆形分布
- package {
- import flash.display.Sprite;
- public class Random3 extends Sprite {
- private var numDots:uint=300;
- private var maxRadius:Number=50;
- public function Random3() {
- init();
- }
- private function init():void {
- for (var i:uint = 0; i < numDots; i++) {
- var dot:Ball=new Ball(1,0);
- var radius:Number=Math.random()*maxRadius;
- var angle:Number = Math.random() * (Math.PI * 2);
- dot.x = stage.stageWidth / 2 + Math.cos(angle) * radius;
- dot.y = stage.stageHeight / 2 + Math.sin(angle) * radius;
- addChild(dot);
- }
- }
- }
- }
3、圆形均匀分布
- package {
- import flash.display.Sprite;
- public class Random4 extends Sprite {
- private var numDots:uint=300;
- private var maxRadius:Number=50;
- public function Random4() {
- init();
- }
- private function init():void {
- for (var i:uint = 0; i < numDots; i++) {
- var dot:Ball=new Ball(1,0);
- var radius:Number=Math.sqrt(Math.random())*maxRadius;
- var angle:Number = Math.random() * (Math.PI * 2);
- dot.x = stage.stageWidth / 2 + Math.cos(angle) * radius;
- dot.y = stage.stageHeight / 2 + Math.sin(angle) * radius;
- addChild(dot);
- }
- }
- }
- }
4、偏向分布(1维6次迭代)
- package {
- import flash.display.Sprite;
- public class Random6 extends Sprite {
- private var numDots:uint=300;
- private var maxRadius:Number=50;
- private var iterations:uint=6;
- public function Random6() {
- init();
- }
- private function init():void {
- for (var i:uint = 0; i < numDots; i++) {
- var dot:Ball=new Ball(1,0);
- var xpos:Number=0;
- for (var j:uint = 0; j < iterations; j++) {
- xpos+=Math.random()*stage.stageWidth;
- }
- dot.x=xpos/iterations;
- dot.y = stage.stageHeight / 2 + Math.random() * 50 - 25;
- addChild(dot);
- }
- }
- }
- }
5、偏向分布(2维6次迭代)
- package {
- import flash.display.Sprite;
- public class Random7 extends Sprite {
- private var numDots:uint=300;
- private var maxRadius:Number=50;
- private var iterations:uint=6;
- public function Random7() {
- init();
- }
- private function init():void {
- for (var i:uint = 0; i < numDots; i++) {
- var dot:Ball=new Ball(1,0);
- var xpos:Number=0;
- for (var j:uint = 0; j < iterations; j++) {
- xpos+=Math.random()*stage.stageWidth;
- }
- dot.x=xpos/iterations;
- var ypos:Number=0;
- for (j = 0; j < iterations; j++) {
- ypos+=Math.random()*stage.stageHeight;
- }
- dot.y=ypos/iterations;
- addChild(dot);
- }
- }
- }
- }