原文翻译自:http://www.flashperfection.com/tutorials/Gravity-in-Action-75225.html
本文转载自天地会:http://bbs.9ria.com/thread-120250-1-1.html
研究物理动力学中的力学,是很有趣且蛮重要的,这节课主要研究力学中的运动以及变化。万有引力就是个例子:它能使卫星围绕着地球运动,并且能让我们站立在地球上。

在这节教程中,我们将要创造一个模拟自然现象,并且让其遵守自然现象的规律,试着在屏幕上玩粒子游戏。
在所有生成出来的粒子中间,有一个主要的大粒子来吸引其他的小粒子。由于这些小粒子朝着大粒子移动,用户可以单击大粒子并来回拖动它,这会使这些小粒子不断改变他们的运动轨迹。

当这些小粒子撞到大粒子的边缘线时,它们就停止运动,并且它们不会和其他粒子重叠在一起。
这篇教材的所写的构架内容,介绍了如何执行模拟,都是利用简单的物理原理来编写实现的
步骤1:万有引力公式

首先,看一看物理公式。两个物体之间相互吸引产生的吸引力,由下面的公式表述:

F:物体(p2)作用给任意一个粒子(p1)的吸引力
G:引力常量
m1: p1的质量;
m2: p2的质量;
r: p1到p2间的距离

特别在下面做些笔记:

  1. 引力与间距之间的关系: F 是和分开粒子之间距离的平方成反比的。这意味着A和B的距离越近,那么吸引力就越大,反之亦然。如果你把距离的值乘以一倍,那么力的值就会降为它本来的值的四分之一。
  2. 引力常数的值——G,科学数值是6.67259 x 10-11 N * m2 / kg2。然而,在Flash环境下,它的值会被500所替换。
  3. 我们能把粒子的宽度和它们的质量扯上联系。在这个例子中,我已经定义了粒子的质量是它半径的一半。

步骤2:牛顿第二定律公式


为了把力转化为动力,我们需要计算出粒子的加速度。牛顿的著名公式是这么写的:
F: 作用于相互物体间的引力(p2)
m: 运动对象的质量(p1);
a: 受力(F)影响的运动对象(p2)的加速度;
从这看出,一个更大的力作用在粒子A上会导致一个更快的加速度(假设质量保持不变)。这个加速度会改变粒子的速率。

步骤3: 开始工程


在FlashDevelop IDE来执行工程会更好。构建你的工程文件。
1.新建工程项目 > 新工程
2.选择窗口上方的,AS3工程
3.命名工程文件,按照我的,给它命名为Attrator
4.选择你的工程文件位置。

步骤4:你需要的类

有四个类需要创建在\src\文件夹中:Main.as,Vector2D.as,Ball.as还有Math2.as.你也可以从资源包里下载所有这些类,并且试着一步一步去了解这些类的原理,为了以后好修改这些类。
它们的作用如下:

Class Name Purpose of Organisation
Main.as Class to create the balls visually and to attach animation to events.
Vector2D Class that holds all vector manipulation functions.
Ball Class that contains functions to visually generate a ball, implements dynamics and kinematics of a ball.
Math2 Static class that holds a function to facilitate randomizing the initial location of balls.

步骤5:随机设值


让我们先说说Math2类吧。下面这个函数会生成一个随机数,在指定的范围之内。接受两个输入值,minimun和maximun来限制范围。
public static function randomiseBetween(range_min:int, range_max:int):int
{ var range:int = range_max - range_min; var randomised:int = Math.random() * range + range_min; return randomised;
}

步骤6:Vector2D,获取与设定


大多数要用的数学都位于Vector2D中。对读者而言,这篇写向量分析的文章会比较熟悉。下面的函数是用来设定和给予向量的分量值的,增加了一个使所有分量值重新为0的方法。
无论如何,如果你对Vector感到别扭,请看看一个很好的帖子:Daniel Sidhion写的欧几里德几何学。
public function Vector2D(valueX:Number, valueY:Number)
{ this._x = valueX; this._y = valueY;
} public function set vecX(valueX:Number):void
{ this._x = valueX;
} public function get vecX():Number
{ return this._x
} public function set vecY(valueY:Number):void
{ this._y = valueY;
} public function get vecY():Number
{ return this._y
} public function setVector(valueX:Number, valueY:Number):void
{ this._x = valueX; this._y = valueY;
} public function reset():void
{ this._x = 0; this._y = 0;
}

步骤7: Vector2D的操作

Vector2D的主要用法,在于以下功能:
* 获取向量的大小值
* 获取向量原点位置的角度
* 获取向量的向量方向
* 执行向量的加法运算,减法运算,以及乘法运算。

public function getMagnitude():Number
{ var lengthX:Number = this._x; var lengthY:Number = this._y; return Math.sqrt(lengthX * lengthX +lengthY * lengthY);
}public function getAngle():Number
{ var lengthX:Number = this._x; var lengthY:Number = this._y; return Math.atan2(lengthY, lengthX);
}public function getVectorDirection():Vector2D
{ var vectorDirection:Vector2D = new Vector2D(this._x / this.getMagnitude(), this._y / this.getMagnitude()); return Vector2D(vectorDirection);
}public function minusVector(vector2:Vector2D):void
{ this._x -= vector2.vecX; this._y -= vector2.vecY;
}public function addVector(vector2:Vector2D):void
{ this._x += vector2.vecX; this._y += vector2.vecY;
}public function multiply (scalar:Number):void
{ this._x *= scalar; this._y *= scalar;
}

步骤8:Ball.as 绘制


Ball类是所有的有趣的运算产生的地方。为了我们动画的开始,我们需要画一个小球并且设置几个与动力学(还有力学)有关的变量。绘制小球的方法如下:
private function draw(radius:Number, color:uint) :void
{ graphics.beginFill(color, 1); graphics.drawCircle(0, 0, radius); graphics.endFill();
}

步骤9: Ball.as 局部变量


所提及的与动力学和力学有关的变量,可以开始定义了,如下:
private var _disp:Vector2D; //displacement vector, relative to the origin
private var _velo:Vector2D; //velocity vector
private var _acc:Vector2D;  //acceleration vector
private var _attractive_coeff:Number = 500;
private var _mass:Number

步骤10:Ball.as 初始化


因为Ball类的构造函数被调用了,因此图形也画好了。一旦画好,小球就会被随机摆放在舞台上。我们也能设置局部变量。所有向量的数量也会初始化设置为0,除了相对位移测量的起点。
public function Ball(radius:Number = 20, color:uint = 0x0000FF)
{ this.draw(radius, color); this._mass = radius / 2;            //assuming mass is half of radius this.x = Math2.randomiseBetween(0, 550); this.y = Math2.randomiseBetween(0, 400); this._disp = new Vector2D(this.x, this.y);  //set initial displacement this._velo = new Vector2D(0, 0); this._acc = new Vector2D(0, 0);
}

步骤11:Ball.as计算吸引力

我们需要计算出使得粒子运动的潜在的力。猜猜,为什么它是万有引力。下面的函数有助于计算力。注意那个帽子,应用了加速度的值为5.
力的水平和垂直分量,利用三角构形,得到力的大小;通过上面的动画会帮你理解这些数学知识。

public function get mass():Number
{ return _mass;
}
private function getForceAttract (m1:Number, m2:Number, vec2Center:Vector2D):Vector2D
{ /* calculate attractive force based on the following formula: * F = K * m1 * m2 / r * r */var numerator:Number = this._attractive_coeff * m1 * m2; var denominator:Number = vec2Center.getMagnitude() * vec2Center.getMagnitude(); var forceMagnitude:Number = numerator / denominator; var forceDirection:Number = vec2Center.getAngle(); //setting a cap if (forceMagnitude > 0) forceMagnitude = Math.min(forceMagnitude, 5); //deriving force component, horizontal, vertical var forceX:Number = forceMagnitude * Math.cos(forceDirection); var forceY:Number = forceMagnitude * Math.sin(forceDirection); var force:Vector2D = new Vector2D(forceX, forceY); return force;
}

步骤12:Ball.as 计算加速度


一旦得到向量的力,我们能计算出加速度的结果。记住,F = ma, 所以 a = F/m.
public function getAcc(vecForce:Vector2D):Vector2D
{//setting acceleration due to forcevar vecAcc:Vector2D = vecForce.multiply(1 / this._mass);return veccAcc;
}

步骤13:Ball.as 计算位移

利用计算出的加速度,我们可以有效地计算出位移的结果
记住,那些计算出的力,实际上是建立在小球的各自中心点间的位移间距上的。

private function getDispTo(ball:Ball):Vector2D
{var currentVector:Vector2D = new Vector2D(ball.x, ball.y);currentVector.minusVector(this._disp);return currentVector;
}
public function attractedTo(ball:Ball) :void
{var toCenter:Vector2D = this.getDispTo(ball);var currentForceAttract:Vector2D = this.getForceAttract(ball.mass, this._mass, toCenter);this._acc = this.getAcc(currentForceAttract);this._velo.addVector(this._acc);this._disp.addVector(this._velo);
}

步骤14: Ball.as 执行位移


然后,通过以下的函数,我们能把小球移动到新的位置上。注意,位移绝不会在小球当前位置上立刻执行。这样设计是为了更好处理:球之间的碰撞检测。
public function setPosition(vecDisp:Vector2D):void
{this.x = Math.round(vecDisp.vecX);this.y = Math.round(vecDisp.vecY);
}

记住,力是建立在物体各自的中心点之间的距离上的。因此,当小球间距离越来越近,引力会越来越大,它们会继续运动且渗透在一起的。
当小球边缘撞击到另一个小球边缘的时候,我们需要重新设置它们加速度和速率为0。我们需要得到一个检测两个球撞击的方法。

步骤15:Ball.as撞击检测


撞击能容易检测。任意两个单独小球之间距离不能比他们的半径的总和小。下面是撞击检测函数:
public function collisionInto (ball:Ball):Boolean
{var hit:Boolean = false;var minDist:Number = (ball.width + this.width) / 2;if (this.getDispTo(ball).getMagnitude() < minDist){hit = true;}return hit;
}

步骤16:Ball.as 计算位移至排斥


通常两个球之间的撞击被检测到的时候,它们的状态是重叠在一起了。我们需要确保它们坐落在边缘上并且不会相互覆盖。
怎样做呢?我们可以把球从另一个球之间距离位移一段,但是我们首先需要计算正确的位移。这里是位移的计算:

public function getRepel (ball:Ball): Vector2D
{var minDist:Number = (ball.width + this.width) / 2;//calculate distance to repelvar toBall:Vector2D = this.getDispTo(ball);var directToBall:Vector2D = toBall.getVectorDirection();directToBall.multiply(minDist);directToBall.minusVector(toBall);directToBall.multiply( -1);return directToBall;
}

步骤17:Ball.as 执行位移到排斥



当我们计算好正确的位移之后,我们需要执行它。程序要让小球互斥,我们需要额外做两个指令。记住,我们要处理一个动力学的环境。即便我们把小球位移到小球边缘的时候,由于作用力以及碰撞造成的速率,会改变加速度,造成
不理想的里外颠簸。我们需要重新设置加速度的和速率的值为0.
public function repelledBy(ball:Ball):void
{this._acc.reset();this._velo.reset();var repelDisp:Vector2D = getRepel(ball);this._disp.addVector(repelDisp);
}

步骤18: Ball.as 赋予动画


最后,要想让它们互相吸引,我们要把我们的小球赋予动画(渲染)。当碰撞检测时,位移会调节到以至不会穿透边界。这会在他们用的中心点间距撞击时发生,每一个小球之间的碰撞都这样。
public function animate(center:Ball, all:Array):void
{this.attractedTo(center);if (collisionInto(center)) this.repelledBy(center);for (var i:int = 0; i < all.length; i++){var current_ball:Ball = all[i] as Ball;if (collisionInto(current_ball) && current_ball.name != this.name) this.repelledBy(current_ball);}this.setPosition(this._disp);
}

步骤19:Main.as局部变量


来到我们最后一个类:Main.Main类在工程一开始就产生。局部变量包含了一个吸引其他小球的主球,以及所有球的数量,一切都在Flash展示画面中。
private var mainBall:Ball;
private var totalBalls:int = 10;
步骤20:Main.as绘制小球

首先,我们应该把球初始化。这里有一个主要的大球来吸引其他的小球。把其他小球命好名称来方便于引用。
private function createBalls ():void
{mainBall = new Ball(50, 0x00FF00);this.addChild(mainBall);for (var i:int = 0; i < this.totalBalls; i++){var currentBall:Ball = new Ball();currentBall.name = "ball" + i;this.addChild(currentBall);}
}
步骤21: Main.as执行小球相互作用

然后,给主要的大球分配事件侦听,使它单击鼠标的时候拖曳当释放鼠标的时候停止。
private function init(e:Event = null):void
{removeEventListener(Event.ADDED_TO_STAGE, init);// entry pointcreateBalls();mainBall.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);animateAll();
}
private function onMouseUp(e:MouseEvent):void
{stopDrag();
}
private function onMouseDown(e:MouseEvent):void
{e.target.startDrag();
}
步骤22:Main.as 小球的动画

使小球产生动画,让它们被大球吸引。把一个EnterFrame事件分配在每个小球当中。
private function animateAll():void
{for (var i:uint = 0; i < totalBalls; i++){//each ball is pulled by main_ballvar current_ball:Ball = this.getChildByName("ball" + i) as Ball;current_ball.addEventListener(Event.ENTER_FRAME, enterFrame);}
}
private function enterFrame(e:Event):void
{var allObj:Array = new Array();for (var i:int = 0; i <= totalBalls; i++){var current_ball:Ball = this.getChildAt(i) as Ball;allObj.push(current_ball);}e.target.animate(mainBall, allObj);
}
步骤23:测试影片

最终,按下Ctrl + Enter观看动画效果吧。
结论

进一步来讲一下这个教程,读者也许通过运用线性力学来扩展了这个工程。

无论如何,模拟提供了一个传达思想的很好的手段,通过简单的图形和文本来解释这样一个复杂的物理学环境课程,特别是问题花费太多时间的时候。
我希望这小教程能给你带来一定的帮助。Terima Kasih审阅了这篇文章,也期待各位读者的评论。

AS3 ---- 万有引力(Gravity in Action)相关推荐

  1. SWF反编译软件Action Script Viewer ASV2011/08发布(AS3反编译引擎最重大升级)

    ASV2011/08今天正式发布. 此版本是对AS3支持最好的版本,AS3反编译引擎作出了最重大的升级.ASV2011是AS3开发人员的必备工具,Flash开发优化利器. 有何更新? 修复若干AS2/ ...

  2. 利用ViewPager+Fragment+actionbar实现可左右滑动的Action Tab

    1. ViewPager要点: ViewPager 是一个布局管理类(layout manager),用于提供页面的左右滑动功能,类似于ListView,也有为ViewPager提供     数据(F ...

  3. 25行AS3代码编程大赛的第一名!25行代码构造的AS3游戏

    叫做Marius Heil的AS开发者使用AS3构造了一个25行代码的AS3游戏,并且获得了25行AS3代码编程大赛的第一名! /** * 25-Line ActionScript Contest E ...

  4. PureMVC(AS3)剖析:设计模式(二)

    PureMVC(AS3)剖析:设计模式(二) 模式 上一篇中介绍了PureMVC中使用的3种设计模式:单例模式.观察者模式.外观模式.本篇将继续介绍剩下的3种设计模式: l  使用中介者(Mediat ...

  5. (转)AS3中的stage,this,root的区别

    要了解这个问题就要先对flash中的显示对象结构有一个大概的了解: 第一级:舞台: 第二级:当前SWF: 第三级:各种容器及可视对象(如:文本框,位图--): 以此类推---- stage: 其中舞台 ...

  6. 使用Box2D制作AS3游戏——2.1a版本——Hello World Box2D .

    本文版权归 csdn cunshuifengyun,转载请严格按照如下方式,于文章明显位置注明原文作者及出处,以示尊重!! 作者:cunshuifengyun 原文:http://blog.csdn. ...

  7. 瘟疫期间整理出万有引力的牛顿都做了哪些贡献?

    万有引力定律已经存在牛顿脑海里很久了 1665 年,英国伦敦大瘟疫 当时牛顿正在剑桥就读 买不到口罩的他 被迫回家进行自我隔离 他亲戚不走,聚会也不参加 但就是这段时间 让他有机会思考如下的问题: 是 ...

  8. url action editor 快速修改swf链接

    Url Action Editor 2012 介绍 UAE是一个SWF编辑器,无需重建为FLA就可以直接对SWF进行编辑,比如编辑代码或元件中的字符串(网址,帧标签,实例名等),替换元件,调整元件座标 ...

  9. AS3版本Progressive FLV播放方式

    用AS3来实现Progressive FLV的简单播放,下一篇贴出基于FMS的Streaming AS3实现版本 实现方法: 1.Flash CS3中建立一个AS文件,存为ProgressiveFlv ...

最新文章

  1. LeetCode简单题之最后一块石头的重量
  2. 最新全球自由职业技能单日排行
  3. 从源码分析DEARGUI之add_menu
  4. HBase常用操作之namespace
  5. Tuxera NTFS教程:在Mac上如何将MS-DOS文件系统格式化为NTFS文件系统?
  6. 邵阳市工业学校计算机29班,邵阳市南门口大祥区沙子坡文明路11号计算机学校...
  7. 【Axure电商原型】电商APP高保真原型+移动端通用版电商app模板+用户中心+会员体系+内容推荐+社区体系+运营推广+订单流程+运营活动+订单管理+售后及服务+秒杀专区+特惠推荐+高保真移动端电商
  8. 二分法之旋转有序数组
  9. 日本研发圆滚滚的球形无人机,被LED屏团团包围
  10. Linux音频驱动-PCM设备
  11. php对象在内存中的分配
  12. Excel怎么忽略位置对比两列数据是否相同
  13. 智能语言处理之依存树计算句子结构相似度计算
  14. 怎么修改服务器上的分数,在服务器上设置 WinSAT 分数
  15. 3dmax文件保存后超大怎么缩小?想学3D建模,还没软件速来领取
  16. 神舟GX8的强冷模式,其他神船伙伴也可以试一试
  17. MyStack<T>
  18. 本程序实现求n*m的二维数组元素的最大值,请将程序补充完整,以实现规定功能
  19. 浅谈通用的字典表结构设计
  20. 交警部门:路口随意变道压实线罚200元记3分

热门文章

  1. 不会编程能学前端吗?web前端需要学习什么?
  2. PHP 类的静态成员变量和普通成员变量对比
  3. 什么是学生机云服务器,哪里可以找到学生机云服务器?
  4. Excel/WPS表格对两列数据进行排列组合
  5. 运算放大器的内部结构-运放
  6. 4-(9H-咔唑-9-基)苯甲醛 4-(9H-carbazol-9-yl)benzaldehyde cas:110677-45-7
  7. CDN技术之--全局负载均衡(GSLB)
  8. python输入两个数字的成语_一起来写个简单的解释器(2)
  9. HP DL360服务器安装redhat7操作系统采坑及路由专线配置过程
  10. Beginning Python PDF 分享