`
madfroghe
  • 浏览: 122104 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Flash/Flex学习笔记(38):动量守恒与能量守恒

阅读更多

动能公式:

动量公式:

动量守恒:

能量守恒:

根据这些规律可以得到下列方程组:

解该方程组,得到下面的公式:

把这二个公式相减,可以得到:

即:

我们也经常利用这个公式简化运算

基本的动量守恒演示:

先给ball类添加一个质量"属性"

 
package {


import flash.display.Sprite;

 
//小球 类

 
public class Ball extends Sprite {

 
public var radius:uint;//半径

 
public var color:uint;//颜色

 
public var vx:Number=0;//x轴速度

 
public var vy:Number=0;//y轴速度

 
public var count:uint=0;//辅助计数变量

 
public var isDragged=false;//是否正在被拖动

 
public var vr:Number=0;//旋转速度

 
public var mass:Number = 1;//质量


public function Ball(r:Number=50,c:uint=0xff0000) {

 
this.radius=r;


this.color=c;


init();

 
}

 
private function init():void {

 
graphics.beginFill(color);


graphics.drawCircle(0,0,radius);

 
graphics.endFill();

 
}

 
}

 
}

一维单轴刚体碰撞测试:

package {


import flash.display.Sprite;

 
import flash.events.Event;

 
public class Billiard1 extends Sprite {

 
private var ball0:Ball;

 
private var ball1:Ball;

 
private var bounce:Number = -0.6;

 
public function Billiard1() {

 
init();

 
}

 
private function init():void {

 
ball0=new Ball(40);         

 
addChild(ball0);

 
ball1=new Ball(20,0x0000ff);            

 
addChild(ball1);                    


ReStart();

 
}


private function ReStart():void{

 
ball0.mass=2;


ball0.x=50;

 
ball0.y=stage.stageHeight/2;


ball0.vx=5;

ball1.mass=1;

 
ball1.x=300;


ball1.y=stage.stageHeight/2;


ball1.vx=-5;        

 
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);  

 
}

private function EnterFrameHandler(event:Event):void {

 
ball0.x+=ball0.vx;

 
ball1.x+=ball1.vx;

 
var dist:Number=ball1.x-ball0.x;

 
//如果撞到了


if (Math.abs(dist)<ball0.radius+ball1.radius) {

 
var vdx:Number = ball0.vx - ball1.vx;


var vx0Final:Number=((ball0.mass-ball1.mass)*ball0.vx + 2*ball1.mass*ball1.vx)/(ball0.mass+ball1.mass);

 
var vx1Final:Number= vx0Final + vdx;

 
ball0.vx=vx0Final;

 
ball1.vx=vx1Final;

 
//不加下面这二句的话,从视觉效果上看,有可能会看到二个球相互撞入对方球体内了,这样就不符合物理学"刚体"模型的定义

 
ball0.x+=ball0.vx;

 
ball1.x+=ball1.vx;


}

 
//舞台边界反弹

 
if (ball0.x >=stage.stageWidth-ball0.radius || ball0.x<=ball0.radius){

 
ball0.x -= ball0.vx;

 
ball0.vx *= bounce;

 
}           

 
if (ball1.x >=stage.stageWidth-ball1.radius || ball1.x<=ball1.radius){


ball1.x -= ball1.vx;


ball1.vx *= bounce;

 
}

 
trace(ball1.vx,ball0.vx);


//如果二球都停了

 
if (Math.abs(ball1.vx)<=0.05 && Math.abs(ball0.vx)<=0.05){

 
removeEventListener(Event.ENTER_FRAME,EnterFrameHandler);   

 
ReStart();

 
}

 
}

 
}


}

二维坐标上的刚体碰撞:

先来看这张图,红球a以Va速度运动,蓝球b以Vb速度运动,二球的连线正好与x轴平行(即:水平对心碰撞),碰撞的过程可以理解为二球水平速度分量Vax,Vbx应用运量守恒与能力守恒的结果(y轴方向的速度不受影响!)

但很多情况下,二球的连线并非总是与坐标轴平行,比如下面这样:

思路:仍然利用坐标旋转,先将二个球反向旋转到连线水平位置,然后按常规方式处理,完事后再旋转回来。

var ballA:Ball=new Ball(80,Math.random()*0xffffff);

 
var ballB:Ball=new Ball(50,Math.random()*0xffffff);

 
var bounce:Number=-1;

 
ballA.x=ballA.radius+100;

 
ballB.x=ballA.radius+200;

ballA.y=120;

 
ballB.y=300;

 
ballA.mass=2;


ballB.mass=1;


ballA.vx = 5*(Math.random()*2-1);


ballB.vx = 5*(Math.random()*2-1);

 
ballA.vy = 5*(Math.random()*2-1);


ballB.vy = 5*(Math.random()*2-1);


addChild(ballA);

 
addChild(ballB);

 
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);

 
function EnterFrameHandler(e:Event):void {

 
ballA.x+=ballA.vx;

 
ballA.y+=ballA.vy;

 
ballB.x+=ballB.vx;


ballB.y+=ballB.vy;

 
//运量守恒处理开始


var dx:Number=ballB.x-ballA.x;

 
var dy:Number=ballB.y-ballA.y;

 
var dist:Number=Math.sqrt(dx*dx+dy*dy);

 
if (dist<(ballA.radius + ballB.radius)) {

 
var angle:Number=Math.atan2(dy,dx);

 
var cos:Number=Math.cos(angle);

 
var sin:Number=Math.sin(angle);

 
//以ballA中心为旋转中心反向旋转

 
var xA:Number=0;//ballA自身为旋转中心,所以自身旋转后的相对坐标都是0


var yA:Number=0;

 
var xB:Number=dx*cos+dy*sin;

 
var yB:Number=dy*cos-dx*sin;

 
//先(反向)旋转二球相对(ballA的)速度


var vxA=ballA.vx*cos+ballA.vy*sin;

 
var vyA=ballA.vy*cos-ballA.vx*sin;

 
var vxB=ballB.vx*cos+ballB.vy*sin;

 
var vyB=ballB.vy*cos-ballB.vx*sin;

 
//旋转后的vx速度处理运量守恒

 
var vdx=vxA-vxB;

 
var vxAFinal = ((ballA.mass - ballB.mass)*vxA + 2*ballB.mass*vxB)/(ballA.mass + ballB.mass);

 
var vxBFinal=vxAFinal+vdx;

 
//相对位置处理

 
xA+=vxAFinal;

 
xB+=vxBFinal;

 
//处理完了,再旋转回去

 
//先处理坐标位置

 
var xAFinal:Number=xA*cos-yA*sin;


var yAFinal:Number=yA*cos+xA*sin;

 
var xBFinal:Number=xB*cos-yB*sin;

 
var yBFinal:Number=yB*cos+xB*sin;

 
//处理最终的位置变化

ballB.x=ballA.x+xBFinal;

 
ballB.y=ballA.y+yBFinal;


ballA.x+=xAFinal;


ballA.y+=yAFinal;


//再处理速度


ballA.vx=vxAFinal*cos-vyA*sin;

 
ballA.vy=vyA*cos+vxAFinal*sin;

 
ballB.vx=vxBFinal*cos-vyB*sin;

 
ballB.vy=vyB*cos+vxBFinal*sin;

 
}

 
//<--- 运量守恒处理结束


CheckBounds(ballA);

 
CheckBounds(ballB);

 
}


//舞台边界检测


function CheckBounds(b:Ball) {

 
if (b.x<b.radius) {

 
b.x=b.radius;

 
b.vx*=bounce;

 
} else if (b.x>stage.stageWidth-b.radius) {

 
b.x=stage.stageWidth-b.radius;

 
b.vx*=bounce;


}


if (b.y<b.radius) {

 
b.y=b.radius;

 
b.vy*=bounce;


} else if (b.y>stage.stageHeight-b.radius) {

 
b.y=stage.stageHeight-b.radius;

 
b.vy*=bounce;

 
}

 
}

粘连问题:

反复运行上面这段动画,偶尔可能会发现二个球最终粘在一起,无法分开了,造成这种原因的情况很多,下面的示意图分析了可能的形成原因之一

解决思路:找出重叠部分,然后把二个小球同时反向移动适当距离,让二个球分开即可

先来一段测试代码:验证一下是否有效


var ballA:Ball=new Ball(80,0xff0000);

 
ballA.x=stage.stageWidth/2;

 
ballA.y=stage.stageHeight/2;


addChild(ballA);

 
var ballB:Ball=new Ball(60,0x00ff00);

 
ballB.x=stage.stageWidth/2-70;

 
ballB.y=stage.stageHeight/2;

 
addChild(ballB);

 
btn1.x=stage.stageWidth/2;

 
btn1.y=stage.stageHeight-btn1.height;

 
btn1.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);


function MouseDownHandler(e:MouseEvent):void {


var overlap:Number=ballA.radius+ballB.radius-Math.abs(ballA.x-ballB.x);//计算重叠部分

 
trace(overlap);

//计算每个球所占重叠部分中的比例

 
var aRadio:Number = ballA.radius/(ballA.radius + ballB.radius);

var bRadio:Number = ballB.radius/(ballA.radius + ballB.radius);

 
//分离判断

 
if (overlap>0){

 
if (ballA.x>ballB.x){

 
ballA.x += overlap*aRadio;

 
ballB.x -= overlap*bRadio;

 
}

 
else{

 
ballA.x -= overlap*aRadio;

 
ballB.x += overlap*bRadio;

 
}

 
}

 
}

ballA.addEventListener(MouseEvent.MOUSE_DOWN,startDragHandler);

 
ballB.addEventListener(MouseEvent.MOUSE_DOWN,startDragHandler);

 
ballA.addEventListener(MouseEvent.MOUSE_OVER,MouseOverHandler);

 
ballA.addEventListener(MouseEvent.MOUSE_OUT,MouseOutHandler);


ballB.addEventListener(MouseEvent.MOUSE_OVER,MouseOverHandler);


ballB.addEventListener(MouseEvent.MOUSE_OUT,MouseOutHandler);

 
stage.addEventListener(MouseEvent.MOUSE_UP,stopDragHandler);


var obj:Ball;

 
var rect:Rectangle = new Rectangle(0,stage.stageHeight/2,stage.stageWidth,0);

 
function startDragHandler(e:MouseEvent):void {


Mouse.cursor = MouseCursor.HAND;

 
obj=e.currentTarget as Ball;


obj.startDrag();

 
}


function stopDragHandler(e:MouseEvent):void {

 
if (obj!=null) {

 
obj.stopDrag(true,rect);

 
obj=null;

 
Mouse.cursor = MouseCursor.AUTO;


}

 
}

 
function MouseOverHandler(e:MouseEvent):void{

 
Mouse.cursor = MouseCursor.HAND;

 
}

 
function MouseOutHandler(e:MouseEvent):void{


Mouse.cursor = MouseCursor.AUTO;

 
}

水平拖动小球故意让它们重叠,然后点击“分开”按钮测试一下,ok,管用了!

再回过头来解决运量守恒中的粘连问题:

只要把EnterFrameHandler中的

//相对位置处理  

 
xA+=vxAFinal;  

xB+=vxBFinal;

换成:

//相对位置处理(同时要防止粘连)


//xA+=vxAFinal;


//xB+=vxBFinal;


var sumRadius = ballA.radius + ballB.radius;

 
var overlap:Number=sumRadius-Math.abs(xA-xB);//计算重叠部分

 
//trace(overlap);


//计算每个球所占重叠部分中的比例


var aRadio:Number = ballA.radius/sumRadius;

var bRadio:Number = ballB.radius/sumRadius;

 
//分离判断

 
if (overlap>0){

if (xA>xB){


xA += overlap*aRadio;


xB -= overlap*bRadio;

 
}

 
else{

 
xA -= overlap*aRadio;

 
xB += overlap*bRadio;

 
}


}

最后老规矩:来一个群魔乱舞,把一堆球放在一块儿乱撞


package {

import flash.display.Sprite;


import flash.events.Event;

import flash.geom.Point;


public class MultiBilliard extends Sprite {

 
private var balls:Array;

 
private var numBalls:uint=8;

 
private var bounce:Number=-1.0;

 
public function MultiBilliard() {

 
init();

 
}


private function init():void {


balls = new Array();

 
for (var i:uint = 0; i < numBalls; i++) {

 
var radius:Number=Math.random()*40+10;

 
var ball:Ball=new Ball(radius,Math.random()*0xffffff);

 
ball.mass=radius;

 
ball.x=i*100;

 
ball.y=i*50;

 
ball.vx=Math.random()*10-5;

 
ball.vy=Math.random()*10-5;

 
addChild(ball);

 
balls.push(ball);

 
}


addEventListener(Event.ENTER_FRAME, onEnterFrame);


}

 
private function onEnterFrame(event:Event):void {

 
for (var i:uint = 0; i < numBalls; i++) {


var ball:Ball=balls[i];

 
ball.x+=ball.vx;

 
ball.y+=ball.vy;

 
checkWalls(ball);

 
}


for (i = 0; i < numBalls - 1; i++) {

 
var ballA:Ball=balls[i];

 
for (var j:Number = i + 1; j < numBalls; j++) {

 
var ballB:Ball=balls[j];

 
checkCollision(ballA, ballB);

 
}

 
}

 
}

 
//舞台边界检测

 
function checkWalls(b:Ball) {

 
if (b.x<b.radius) {

 
b.x=b.radius;


b.vx*=bounce;

 
} else if (b.x>stage.stageWidth-b.radius) {

 
b.x=stage.stageWidth-b.radius;

 
b.vx*=bounce;

 
}

 
if (b.y<b.radius) {

 
b.y=b.radius;

 
b.vy*=bounce;

 
} else if (b.y>stage.stageHeight-b.radius) {


b.y=stage.stageHeight-b.radius;

 
b.vy*=bounce;

 
}

 
}


private function rotate(x:Number, y:Number, sin:Number, cos:Number, reverse:Boolean):Point {

 
var result:Point = new Point();

 
if (reverse) {

 
result.x=x*cos+y*sin;

result.y=y*cos-x*sin;


} else {

 
result.x=x*cos-y*sin;

 
result.y=y*cos+x*sin;

 
}

return result;

 
}


private function checkCollision(ball0:Ball, ball1:Ball):void {

 
var dx:Number=ball1.x-ball0.x;

 
var dy:Number=ball1.y-ball0.y;

 
var dist:Number=Math.sqrt(dx*dx+dy*dy);


if (dist<ball0.radius+ball1.radius) {

 
// 计算角度和正余弦值 

 
var angle:Number=Math.atan2(dy,dx);

 
var sin:Number=Math.sin(angle);

 
var cos:Number=Math.cos(angle);

 
// 旋转 ball0 的位置 


var pos0:Point=new Point(0,0);

 
// 旋转 ball1 的速度 

 
var pos1:Point=rotate(dx,dy,sin,cos,true);

 
// 旋转 ball0 的速度 

 
var vel0:Point=rotate(ball0.vx,ball0.vy,sin,cos,true);

 
// 旋转 ball1 的速度 

 
var vel1:Point=rotate(ball1.vx,ball1.vy,sin,cos,true);

 
// 碰撞的作用力 

 
var vxTotal:Number=vel0.x-vel1.x;

 
vel0.x = ((ball0.mass - ball1.mass) * vel0.x + 2 * ball1.mass * vel1.x) / (ball0.mass + ball1.mass);

 
vel1.x = vxTotal+vel0.x;

 
// 更新位置 

 
var absV:Number=Math.abs(vel0.x)+Math.abs(vel1.x);

 

var overlap:Number = (ball0.radius + ball1.radius) - Math.abs(pos0.x - pos1.x);

 
pos0.x += vel0.x/absV*overlap;

 
pos1.x += vel1.x/absV*overlap;

 
// 将位置旋转回来 

 
var pos0F:Object=rotate(pos0.x,pos0.y,sin,cos,false);

 
var pos1F:Object=rotate(pos1.x,pos1.y,sin,cos,false);

 
// 将位置调整为屏幕的实际位置 


ball1.x=ball0.x+pos1F.x;

 
ball1.y=ball0.y+pos1F.y;

 
ball0.x=ball0.x+pos0F.x;

 
ball0.y=ball0.y+pos0F.y;

 
// 将速度旋转回来 

 
var vel0F:Object=rotate(vel0.x,vel0.y,sin,cos,false);

 
var vel1F:Object=rotate(vel1.x,vel1.y,sin,cos,false);

 
ball0.vx=vel0F.x;

 
ball0.vy=vel0F.y;

 
ball1.vx=vel1F.x;

 
ball1.vy=vel1F.y;

 
}

}

 
}

}

注:这段代码做了优化,把一些公用的部分提取出来封装成function了,同时对于粘连问题的解决,采用了更一种算法

后记:弄懂了本文中的这些玩意儿有啥用呢?让我想想,或许...公司需要开发一款桌面台球游戏时,这东西就能派上用场吧.

分享到:
评论

相关推荐

    Flash/Flex 框架应用 Cairngorm、Mate、PureMVC以及Swiz 的典型例子

    附件是关于 Flash/Flex 几个重要框架 Cairngorm、Mate、PureMVC以及Swiz 的典型例子,由 Tony Hillerson 提供 Homepage: http://insideria.com

    flex/Flash开发系列书籍:WEB3D应用研究

    flex/Flash开发系列书籍:基于FLASH的WEB3D应用研究

    flash/flex画曲线,绘图板

    在IT行业中,Flash/Flex是一种基于ActionScript编程语言和Adobe Flex框架的开发工具,用于创建交互式的、富媒体的Web应用程序。"Flash/Flex画曲线,绘图板"这个主题涉及的是如何使用这些技术来创建一个允许用户自由...

    RE/flex lexical analyzer generator:以正则表达式为中心的快速词法分析器生成器,用于C ++-开源

    语言:C ++许可证:BSD-3代码质量:A + https://lgtm.com/projects/g/Genivia/RE-flex/context:cpp文档:https://www.genivia.com/doc/reflex/html /index.html存储库:https://github.com/Genivia/RE-flex更改日志...

    [Flash/Flex] 使用css定义文本样式

    在IT行业中,Flash和Flex是曾经非常流行的富互联网应用程序(RIA)开发框架,它们主要用于创建交互式的网页内容和应用程序。本文将重点讲解如何在Flash或Flex项目中利用CSS(层叠样式表)来定义文本样式,提升用户...

    FDT-flash/flex devtoolkit for eclipse.

    **FDT - 一款强大的Flash/Flex开发工具集** FDT(Flash Development Tool)是一款专为Adobe Flash和Flex开发者设计的集成开发环境(IDE),它基于Eclipse平台,提供了高效、专业的开发工具和服务。FDT的出现极大地...

    flash/flex 的aqua皮肤

    在IT行业中,Flash/Flex是一种广泛使用的开发工具,主要用于创建交互式、富媒体的Web应用程序。Flex是基于ActionScript和MXML的开放源代码框架,它允许开发者构建可自定义的用户界面,而Flash则是其背后的动画和...

    FLEX安装方法 集成到eclipse中

    FLEX 安装方法 集成到 eclipse 中 ...* 汉化 FLEX 尤其是 FLEX/AIR 方面的中文资料 * 原创的关于 FLEX 的博客:http://liguoliang.com/ * Adobe 公司 FLEX 主页:http://www.adobe.com/cn/products/flex/

    Flex:登录

    标题“Flex:登录”指的是使用Adobe Flex技术实现用户登录功能的一种方法。Flex是Adobe公司推出的一款基于ActionScript的开源框架,主要用于...压缩包中的"Flex Login"可能包含示例代码或项目结构,供读者学习和参考。

    flex学习笔记 flex学习总结 flex学习教程

    Flex Builder(现已被Adobe Flash Builder取代)是一个集成开发环境,提供了代码提示、调试和项目管理等功能,使得开发更加高效。 3. **Flex组件库**:Flex提供了丰富的预定义组件,如Button、Label、Canvas等,可...

    RTMP直播例子--基于FLASH/FLEX(含源代码) 下载

    RTMP(Real-Time Messaging Protocol)...通过学习和理解源代码,你可以深入了解RTMP协议的实现细节,以及FLEX如何与服务器和客户端进行交互。这对于想要从事音视频直播开发的人员来说,是一个宝贵的实践和学习资源。

    解决flash/flex/as3 访问中文域名时的流错误示例

    在《潮汕IT男》网站的文章《解决flash/flex/as3 访问中文域名时的流错误》中,作者陈林生提供了详细的步骤和代码示例,帮助开发者理解和解决这个问题。文章地址是:[http://chenlinsheng.com/?p=990]...

    FLEX学习笔记

    《FLEX学习笔记》 FLEX,全称为Flex Builder,是由Adobe公司开发的一款基于MXML和ActionScript的开源框架,用于构建富互联网应用程序(RIA)。它允许开发者创建具有交互性、响应性和丰富用户体验的Web应用。FLEX的...

    Flex学习笔记.rar

    1. **Flex概述**:介绍Flex技术的基本概念,包括它的历史、目标和应用领域,以及它与Flash Player和Adobe AIR的关系。 2. **Flex开发环境**:可能会讲解如何安装和配置Flex Builder或IntelliJ IDEA等开发工具,以及...

    flex开源项目介绍.doc

    Flex开源项目介绍 Flex是一种用于构建富互联网应用程序(RIA)的开源框架,它基于ActionScript 3(AS3)编程语言和MXML标记语言。这些开源项目为开发者提供了丰富的组件库、工具和框架,帮助他们扩展Flex的功能,...

    4个简单的Flex例子(包含custom-class-mapping)共享

    总共有4个例子: 1.http://127.0.0.1:8080/flexDemo/HelloWorld/HelloWorld.html ...如果你的数据库配置和我的不一样,请修改flexDemo\WEB-INF\classes\下的DBSetting.properties文件,数据库建表的sql语句是user.sql

    Flex与Java的交互

    Flex与Java的交互是跨平台应用开发中的常见技术组合,允许前端用户界面(UI)与后端业务逻辑进行高效沟通。在本文中,我们将深入探讨如何使用Flex 4与Java进行通信,并通过三种不同的方法实现这一目标:RemoteObject...

    flex4cookbook

    xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" creationComplete="app_creationCompleteHandler(event)"&gt; &lt;fx:Script&gt; &lt;![CDATA[ import mx.events.FlexEvent; ...

    vs2012/2010 flex FluorineFx:认证与授权源码

    vs2012/2010 flex FluorineFx:认证与授权源码,FluorineFx对VS2012的配置都没有给出很好的方案,然后网上资料太少,所以我写了一份授权与认证,下载就可以直接使用了,对于授权与认证不了解的,参考这个文章...

    flex开发系列书籍:WebGIS开发实战

    本篇文章将对 Flex 开发系列书籍:WebGIS 开发实战进行详细的知识点总结,涵盖 Flex 概述、RIA 概述、Flex 开发基础、Flex 开发实践、Flex 与 WebGIS 开发框架、基于 Flex 的 WebGIS 基础开发、基于 Flex 的 WebGIS ...

Global site tag (gtag.js) - Google Analytics