没怎么玩过图形学,最近都需要做,又要复习物理和数学了~~~
以下是初成的作品,其实最终目的也不是这个球碰撞了,只是试试,有bug~~(就是球会偶尔粘在一起,是因为速度太快)
需要解决粘连问题,就需要加入“下一点位置”来做提前的碰撞预判。
可以简单加入下一点标记一下,在Ball类中,加EnterFrame监听,每一帧计算下一帧的位置,然后碰撞的测试函数改为使用nextX和nextY计算,而不是x和y。
效果如下:
直接上代码(没有更新“下一点标记”):
package { import flash.display.Sprite; import flash.events.Event; import flash.text.engine.Kerning; import flashx.textLayout.formats.BackgroundColor; [SWF(width = "600", height = "500", backgroundColor = "#000000", frameRate = "30")] public class Main extends Sprite { private var ballList:Vector.<Ball> = new Vector.<Ball>; public function Main() { this.graphics.beginFill(0xFFFFFF); this.graphics.drawRect(0, 0, 600, 500); this.graphics.endFill(); var colorArray:Array = [0x222222, 0x123456, 0xff2200, 0x11ff44, 0x4411ff, 0x132e00, 0x1df144, 0x40110f]; //随机初始化每个MC的运动速度和方向 for (var i:int = 0; i<8; i++) { var radius:int = 30; var ball:Ball = new Ball(colorArray[i], radius); ball.speed.x = -5 + 10*Math.random(); ball.speed.y = -5 + 10*Math.random(); ball.x = i*60 + 5; ball.y = i*60 + 5; ballList.push(ball); this.addChild(ball); } var sw:Number = this.width; var sh:Number = this.height; this.addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function onEnterFrame(event:Event):void { for (var i:int = 0; i<ballList.length; i++) { var ball:Ball = ballList[i]; //如果到了边界,就反射 if ((ball.x < 0) || (ball.x + 2*ball.radius > 600)) { ball.speed.x *= -1; } if ((ball.y < 0) || (ball.y + 2*ball.radius > 500)) { ball.speed.y *= -1; } //检测所有MC之间是否有碰撞,有就根据情况改变“增量”方向 for (var j:int = i+1; j<ballList.length; j++) { if (collisionTest(ball, ballList[j])) { collide(ball, ballList[j]); } } //移动一个“增量” ball.x += ball.speed.x; ball.y += ball.speed.y; } } //碰撞函数,根据两球碰撞方向和自身运动方向合成新的增量值 private function collide(ball1:Ball, ball2:Ball):void { //http://tina0152.blog.163.com/blog/static/119447958200910229109326/ var x1:int = ball1.x + ball1.radius; var y1:int = ball1.y + ball1.radius; var x2:int = ball2.x + ball2.radius; var y2:int = ball2.y + ball2.radius; //s向量是球心连线上的 var s:KVector = new KVector(x2-x1, y2-y1); s = s.unitfy(); //t向量是s的垂直线上的 var t:KVector = s.rotateClockwise(Math.PI/2); t = t.unitfy(); var v1:KVector = ball1.speed; var v2:KVector = ball2.speed; //先算v1(v1x, v1y)在s和t轴的投影值,分别设为v1s和v1t //再算v2(v2x, v2y)在s和t轴的投影值,分别设为v2s和v2t: var v1s:Number = v1.dotMultiply(s); var v1t:Number = v1.dotMultiply(t); var v2s:Number = v2.dotMultiply(s); var v2t:Number = v2.dotMultiply(t); //简单做法,当质量一样,直接交换速度 var temp:Number = v1s; v1s = v2s; v2s = temp; //首先求出v1t和v2t在t轴的向量v1t'和v2t'(将数值变为向量) //再求出v1s'和v2s'在s轴的向量v1s'和v2s'(将数值变为向量) var v1tVector:KVector = t.multiply(v1t); var v1sVector:KVector = s.multiply(v1s); var v2tVector:KVector = t.multiply(v2t); var v2sVector:KVector = s.multiply(v2s); ball1.speed = v1tVector.add(v1sVector); ball2.speed = v2tVector.add(v2sVector); } //碰撞侦测 private function collisionTest(ball1:Ball, ball2:Ball):Boolean { var deltaX:Number = ball1.x + ball1.radius - (ball2.x + ball2.radius); var deltaY:Number = ball1.y + ball1.radius - (ball2.y + ball2.radius); var a:Number=Math.sqrt(deltaX*deltaX + deltaY*deltaY); if(a <= ball1.radius+ball2.radius) { return true; } else { return false; } } } }
package { import flash.display.Sprite; public class Ball extends Sprite { private var _radius:int = 0; private var _speed:KVector = null; public function Ball(color:uint, radius:int) { super(); this.radius = radius; this.graphics.beginFill(color, 0.6); this.graphics.drawCircle(radius,radius,radius); this.graphics.endFill(); speed = new KVector(); } public function get radius():int { return _radius; } public function set radius(value:int):void { _radius = value; } public function get speed():KVector { return _speed; } public function set speed(value:KVector):void { _speed = value; } } }
package { public class KVector { private var _x:Number = 0; private var _y:Number = 0; public function KVector(x:Number = 0,y:Number = 0) { this.x = x; this.y = y; } public function add(value:KVector):KVector { var vector:KVector = new KVector(); vector.x = x + value.x; vector.y = y + value.y; return vector; } public function dotMultiply(vector:KVector):Number { return x * vector.x + y * vector.y; } public function multiply(value:Number):KVector { var vector:KVector = new KVector(); vector.x = x*value; vector.y = y*value; return vector; } public function unitfy():KVector { var vector:KVector = new KVector(); vector.x = x/Math.sqrt(x*x + y*y); vector.y = y/Math.sqrt(x*x + y*y); return vector; } public function divide(value:Number):KVector { var vector:KVector = new KVector(); vector.x = x/value; vector.y = y/value; return vector; } /** * angle是数学的弧度,以Math.PI为180度 */ public function rotateClockwise(angle:Number):KVector { var vector:KVector = new KVector(); vector.x = x*Math.cos(angle) + y*Math.sin(angle); vector.y = -x*Math.sin(angle) + y*Math.cos(angle); return vector; } public function get x():Number { return _x; } public function set x(value:Number):void { _x = value; } public function get y():Number { return _y; } public function set y(value:Number):void { _y = value; } } }