zoukankan      html  css  js  c++  java
  • Flash/Flex学习笔记(44):万有引力与粒子系统

    万有引用公式:

    其中G为万有引力常数

    show sourceview source

    print?

    001
    var numParticles:uint=50;//粒子总数

    002
    var G:Number=0.03;//万有引力常数

    003
    var particles:Array=new Array(numParticles);

    004
    var bounce:Number=-0.4;//边界反弹系统

    005

    006
    //初始化

    007
    function init():void {

    008
    particles = new Array();

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

    010
    var size:Number=Math.random()*12+3;

    011
    var particle:Ball=new Ball(size,Math.random()*0xffffff);

    012
    particle.x=Math.random()*stage.stageWidth;

    013
    particle.y=Math.random()*stage.stageHeight;

    014
    particle.mass=Math.PI * size * size;//质量与球截面积关联,即从视觉效果上看,个头越大,越重

    015
    addChild(particle);

    016
    particles.push(particle);

    017
    }

    018
    addEventListener(Event.ENTER_FRAME, EnterFrameHandler);

    019
    }

    020

    021

    022
    function EnterFrameHandler(event:Event):void {

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

    024
    var particle:Ball=particles[i];

    025
    particle.x+=particle.vx;

    026
    particle.y+=particle.vy;

    027
    }

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

    029
    var partA:Ball=particles[i];

    030
    for (var j:uint = i + 1; j < numParticles; j++) {

    031
    var partB:Ball=particles[j];

    032
    checkCollision(partA,partB);//检测碰撞

    033
    gravitate(partA, partB);//万有引力处理

    034
    }

    035
    checkWalls(partA);//边界检测

    036
    }

    037
    }

    038

    039
    //万有引力处理

    040
    function gravitate(partA:Ball, partB:Ball):void {

    041
    var dx:Number=partB.x-partA.x;

    042
    var dy:Number=partB.y-partA.y;

    043
    var distSQ:Number=dx*dx+dy*dy;

    044
    var dist:Number=Math.sqrt(distSQ);

    045
    var force:Number=G*partA.mass*partB.mass/distSQ;//计算partA与partB的万有引力

    046
    var forceX:Number=force*dx/dist;//即:force * cos(a) --万有引力在x方向上的分量

    047
    var forceY:Number=force*dy/dist;//即:force * sin(a) --万有引力在y方向上的分量

    048
    partA.vx+=forceX/partA.mass;//牛顿定律a = F/m 在这里得到体现

    049
    partA.vy+=forceY/partA.mass;

    050
    partB.vx-=forceX/partB.mass;

    051
    partB.vy-=forceY/partB.mass;

    052
    }

    053

    054
    //动量守恒的碰撞检测

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    069
    vel1.x=vxTotal+vel0.x;

    070
    var sumRadius:Number=ball0.radius+ball1.radius;

    071
    var overlap:Number=sumRadius-Math.abs(pos0.x-pos1.x);

    072
    var aRadio:Number=ball0.radius/sumRadius;

    073
    var bRadio:Number=ball1.radius/sumRadius;

    074
    if (overlap>0) {

    075
    if (pos0.x>pos1.x) {

    076
    pos0.x+=overlap*aRadio;

    077
    pos1.x-=overlap*bRadio;

    078
    } else {

    079
    pos0.x-=overlap*aRadio;

    080
    pos1.x+=overlap*bRadio;

    081
    }

    082
    }

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

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

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

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

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

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

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

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

    091
    ball0.vx=vel0F.x;

    092
    ball0.vy=vel0F.y;

    093
    ball1.vx=vel1F.x;

    094
    ball1.vy=vel1F.y;

    095
    }

    096
    }

    097

    098
    //坐标旋转辅助方法

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

    100
    var result:Point = new Point();

    101
    if (reverse) {

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

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

    104
    } else {

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

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

    107
    }

    108
    return result;

    109
    }

    110

    111

    112
    //舞台边界检测  

    113
    function checkWalls(b:Ball) {

    114
    if (b.x<b.radius) {

    115
    b.x=b.radius;

    116
    b.vx*=bounce;

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

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

    119
    b.vx*=bounce;

    120
    }

    121
    if (b.y<b.radius) {

    122
    b.y=b.radius;

    123
    b.vy*=bounce;

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

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

    126
    b.vy*=bounce;

    127
    }

    128
    }

    129

    130

    131
    init();

    132

    133
    btnReset.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);

    134

    135
    function MouseDownHandler(e:MouseEvent):void {

    136
    removeEventListener(Event.ENTER_FRAME, EnterFrameHandler);

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

    138
    var particle:Ball=particles[i];

    139
    particle.x=Math.random()*stage.stageWidth;

    140
    particle.y=Math.random()*stage.stageHeight;

    141
    particle.vx=0;

    142
    particle.vy=0;

    143
    }

    144
    addEventListener(Event.ENTER_FRAME, EnterFrameHandler);

    145
    }

    代码虽然很长,但是其中有很多都是上一篇里封装好的方法直接复制过来的,应该不难理解

    再来模拟一下地球绕着太阳转:

    show sourceview source

    print?

    01
    var numParticles:uint=2;//粒子总数

    02
    var G:Number=0.03;//万有引力常数

    03
    var particles:Array=new Array(numParticles);

    04
    var i:Number=0;

    05

    06

    07
    //初始化

    08
    function init():void {

    09
    particles = new Array(); 

    10
    var sun:Ball = new Ball(30, 0xff0000); 

    11
    sun.x = stage.stageWidth / 2

    12
    sun.y = stage.stageHeight / 2

    13
    sun.mass = 900000

    14
    addChild(sun); 

    15
    particles.push(sun); 

    16
    var planet:Ball = new Ball(10, 0x0000ff); 

    17
    planet.x = stage.stageWidth / 2 + 200

    18
    planet.y = stage.stageHeight / 2

    19
    planet.vy = 8

    20
    planet.mass = 1

    21
    addChild(planet); 

    22
    particles.push(planet); 

    23
    addEventListener(Event.ENTER_FRAME, EnterFrameHandler);

    24
    graphics.lineStyle(1,0xdddddd);

    25
    graphics.moveTo(planet.x,planet.y);

    26
    }

    27

    28

    29
    function EnterFrameHandler(event:Event):void {

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

    31
    var particle:Ball=particles[i];

    32
    particle.x+=particle.vx;

    33
    particle.y+=particle.vy;

    34
    }

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

    36
    var partA:Ball=particles[i];

    37
    for (var j:uint = i + 1; j < numParticles; j++) {

    38
    var partB:Ball=particles[j];            

    39
    gravitate(partA, partB);//万有引力处理

    40
    }       

    41
    }

    42
    }

    43

    44
    //万有引力处理

    45
    function gravitate(partA:Ball, partB:Ball):void {   

    46

    47
    var dx:Number=partB.x-partA.x;

    48
    var dy:Number=partB.y-partA.y;

    49
    var distSQ:Number=dx*dx+dy*dy;

    50
    var dist:Number=Math.sqrt(distSQ);

    51
    var force:Number=G*partA.mass*partB.mass/distSQ;//计算partA与partB的万有引力

    52
    var forceX:Number=force*dx/dist;//即:force * cos(a) --万有引力在x方向上的分量

    53
    var forceY:Number=force*dy/dist;//即:force * sin(a) --万有引力在y方向上的分量

    54
    /*

    55
    partA.vx+=forceX/partA.mass;//牛顿定律a = F/m 在这里得到体现

    56
    partA.vy+=forceY/partA.mass;

    57
    */

    58
    partB.vx-=forceX/partB.mass;

    59
    partB.vy-=forceY/partB.mass;

    60
    trace(i);

    61
    if (i<=1000){

    62
    graphics.lineTo(partB.x,partB.y);

    63
    i++;        

    64
    }

    65
    else{

    66
    graphics.clear();

    67
    graphics.lineStyle(1,0xdddddd);

    68
    graphics.moveTo(partB.x,partB.y);

    69
    i=0;

    70
    }

    71

    72
    }

    73

    74
    init();

    代码就是在第一段的基础上修改的,可以看到在"远日点"速度较慢(因为距离越远,万有引力越小,对应的加速度也较小),在"近日点"速度较快(距离越近,万有引力越大,对应的加速度也较大)

    节点花园NodeGarden:

    为啥叫这个名字,我也说不上来,反正ActionScript3.0 in Animation一书的作者是这么叫的。

    show sourceview source

    print?

    01
    var particles:Array;

    02
    var numParticles:uint=60;

    03
    var minDist:Number=100;

    04
    var springAmount:Number=0.0004;

    05
    var friction:Number = 0.9995;

    06

    07
    function init():void {

    08
    stage.scaleMode=StageScaleMode.NO_SCALE;

    09
    stage.align=StageAlign.TOP_LEFT;

    10
    particles = new Array();

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

    12
    var particle:Ball=new Ball(Math.random()*3+2,0xffffff);

    13
    particle.x=Math.random()*stage.stageWidth;

    14
    particle.y=Math.random()*stage.stageHeight;

    15
    particle.vx=Math.random()*6-3;

    16
    particle.vy=Math.random()*6-3;

    17
    addChild(particle);

    18
    particles.push(particle);

    19
    }

    20
    addEventListener(Event.ENTER_FRAME, EnterFrameHandler);

    21
    }

    22

    23
    function EnterFrameHandler(event:Event):void {

    24
    graphics.clear();

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

    26
    var particle:Ball=particles[i];

    27
    particle.x+=particle.vx;

    28
    particle.y+=particle.vy;

    29

    30
    //屏幕环绕处理

    31
    if (particle.x>stage.stageWidth) {

    32
    particle.x=0;

    33
    } else if (particle.x < 0) {

    34
    particle.x=stage.stageWidth;

    35
    }

    36
    if (particle.y>stage.stageHeight) {

    37
    particle.y=0;

    38
    } else if (particle.y < 0) {

    39
    particle.y=stage.stageHeight;

    40
    }

    41
    }

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

    43
    var partA:Ball=particles[i];

    44
    for (var j:uint = i + 1; j < numParticles; j++) {

    45
    var partB:Ball=particles[j];

    46
    spring(partA, partB);//每个粒子均与其它粒子进行弹性运动处理

    47
    }   

    48

    49
    partA.vx *= friction;

    50
    partA.vy *= friction;

    51
    }

    52
    }

    53

    54
    function spring(partA:Ball, partB:Ball):void {

    55
    var dx:Number=partB.x-partA.x;

    56
    var dy:Number=partB.y-partA.y;

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

    58
    if (dist<minDist) {      

    59
    graphics.lineStyle(1, 0x00ff00, 1 - dist / minDist);//注意这里的透明度设置:二球越来越近时,线条越来越明显,距离越来越远时,线条越来越淡

    60
    graphics.moveTo(partA.x, partA.y);

    61
    graphics.lineTo(partB.x, partB.y);

    62
    //类似弹性运动处理

    63
    var ax:Number=dx*springAmount;

    64
    var ay:Number=dy*springAmount;

    65
    //A球加速

    66
    partA.vx+=ax;

    67
    partA.vy+=ay;

    68
    //B球减速

    69
    partB.vx-=ax;

    70
    partB.vy-=ay;

    71
    //一个球越来越快,一个球越来越慢,所以会不断拉近(当然:前提是在有效距离内)

    72

    73

    74
    }

    75

    76
    }

    77

    78
    init();

    关于这个效果,建议初次接触的同学们,先回顾一下弹性运动:Flash/Flex学习笔记(40):弹性运动续--弹簧

    可以稍加改进,加入质量因素:

    show sourceview source

    print?

    01
    var particles:Array;

    02
    var numParticles:uint=30;

    03
    var minDist:Number=120;

    04
    var springAmount:Number=0.03;

    05
    var friction:Number = 0.998;

    06
    var stageHeight:Number = stage.stageHeight;

    07
    var stageWidth:Number = stage.stageWidth;

    08

    09
    function init():void {

    10
    stage.scaleMode=StageScaleMode.NO_SCALE;

    11
    stage.align=StageAlign.TOP_LEFT;

    12
    particles = new Array();

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

    14
    var particle:Ball=new Ball(Math.random()*5+2,0xffffff);

    15
    particle.x=Math.random()*stageWidth;

    16
    particle.y=Math.random()*stageHeight;

    17
    particle.vx=Math.random()*6-3;

    18
    particle.vy=Math.random()*6-3;

    19
    particle.mass = Math.PI*particle.radius*particle.radius;//加入质量

    20
    addChild(particle);

    21
    particles.push(particle);

    22
    }

    23
    addEventListener(Event.ENTER_FRAME, EnterFrameHandler);

    24
    stage.addEventListener(MouseEvent.MOUSE_MOVE,MouseMoveHandler);

    25
    }

    26

    27
    //鼠标互动

    28
    function MouseMoveHandler(e:MouseEvent):void{   

    29
    var dx:Number = mouseX - stageWidth/2;

    30
    var dy:Number = mouseY - stageHeight/2;     

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

    32
    var b:Ball=particles[i];        

    33
    b.x -= dx/b.mass;

    34
    b.y -= dy/b.mass;

    35
    }   

    36
    }

    37

    38
    function EnterFrameHandler(e:Event):void {

    39
    graphics.clear();

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

    41
    var particle:Ball=particles[i];

    42
    particle.x+=particle.vx;

    43
    particle.y+=particle.vy;        

    44
    //屏幕环绕处理

    45
    if (particle.x>stageWidth) {

    46
    particle.x=0;

    47
    } else if (particle.x < 0) {

    48
    particle.x=stageWidth;

    49
    }

    50
    if (particle.y>stageHeight) {

    51
    particle.y=0;

    52
    } else if (particle.y < 0) {

    53
    particle.y=stageHeight;

    54
    }

    55
    }

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

    57
    var partA:Ball=particles[i];

    58
    for (var j:uint = i + 1; j < numParticles; j++) {

    59
    var partB:Ball=particles[j];

    60
    spring(partA, partB);//每个粒子均与其它粒子进行弹性运动处理

    61
    }   

    62

    63
    partA.vx *= friction;

    64
    partA.vy *= friction;

    65
    }

    66
    }

    67

    68
    function spring(partA:Ball, partB:Ball):void {

    69
    var dx:Number=partB.x-partA.x;

    70
    var dy:Number=partB.y-partA.y;

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

    72
    if (dist<minDist) {      

    73
    graphics.lineStyle(1, 0x00ff00, 1 - dist / minDist);//注意这里的透明度设置:二球越来越近时,线条越来越明显,距离越来越远时,线条越来越淡

    74
    graphics.moveTo(partA.x, partA.y);

    75
    graphics.lineTo(partB.x, partB.y);

    76
    //类似弹性运动处理

    77
    var ax:Number=dx*springAmount;

    78
    var ay:Number=dy*springAmount;

    79
    //A球加速

    80
    partA.vx+=ax/partA.mass;

    81
    partA.vy+=ay/partA.mass;

    82
    //B球减速

    83
    partB.vx-=ax/partB.mass;

    84
    partB.vy-=ay/partB.mass;

    85
    //一个球越来越快,一个球越来越慢,所以会不断拉近(当然:前提是在有效距离内)     

    86
    }   

    87
    }

    88

    89
    init();

    下面这种效果也是很多Flash网站上都有的,效果还不错,而且原理也很简单:

    show sourceview source

    print?

    01
    var ballCount:uint = 100;

    02
    var friction:Number = 0.95;

    03
    var massRadio = 0.005;

    04
    var arrBall:Array = new Array(ballCount);

    05
    var stageWidth:Number = stage.stageWidth;

    06
    var stageHeight:Number = stage.stageHeight;

    07

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

    09
    arrBall[i] = new Ball(Math.random()*10+3,Math.random()*0xffffff);

    10
    arrBall[i].x = Math.random()*stageWidth;

    11
    arrBall[i].y = Math.random()*stageHeight;

    12
    arrBall[i].mass = massRadio * arrBall[i].radius;

    13
    addChild(arrBall[i]);

    14
    }

    15

    16

    17
    stage.addEventListener(Event.ENTER_FRAME,EnterFrameHandler);

    18
    stage.addEventListener(MouseEvent.MOUSE_MOVE,MouseMoveHandler);

    19

    20
    function EnterFrameHandler(e:Event):void{       

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

    22
    var b:Ball = arrBall[i];        

    23
    b.vx *=friction;

    24
    b.vy *=friction;

    25
    b.x += b.vx;

    26
    b.y += b.vy;

    27

    28
    //屏幕环绕处理

    29
    if (b.x>stageWidth+b.radius){

    30
    b.x=-b.radius;

    31
    }

    32
    else if (b.x<-b.radius){

    33
    b.x = stageWidth+b.radius;

    34
    }       

    35
    if (b.y>stageHeight+b.radius){

    36
    b.y=-b.radius;

    37
    }

    38
    else if (b.y<-b.radius){

    39
    b.y = stageHeight+b.radius;

    40
    }

    41
    }       

    42
    }

    43

    44
    function MouseMoveHandler(e:MouseEvent):void{   

    45
    var CenterX:Number = 0.5*stageWidth;

    46
    var CenterY:Number = 0.5*stageHeight;

    47
    var dx:Number = mouseX - CenterX;

    48
    var dy:Number = mouseY - CenterY;   

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

    50
    var b:Ball = arrBall[i];

    51
    //设置速度

    52
    b.vx = -dx*b.mass;

    53
    b.vy = -dy*b.mass;      

    54
    }       

    55
    }

    下面这个是它的变种:

    show sourceview source

    print?

  • 相关阅读:
    jquery插件库收集网站
    百度地图api笔记
    css3 hover 动画
    使用Slip.js快速创建整屏滑动的手机网页
    mobile移动端,PC桌面端页面无刷新过场JS骨架
    zepto.js手机端网页上下手指滑动图片切换效果代码
    onepage-scroll – jQuery单页/全屏滚动插件
    css3loading动画
    onepage scorll全屏滚动插件
    css3动画集
  • 原文地址:https://www.cnblogs.com/happysky97/p/1884580.html
Copyright © 2011-2022 走看看