Flex Actionscript 3 小球碰撞 多球碰撞

没怎么玩过图形学,最近都需要做,又要复习物理和数学了~~~

以下是初成的作品,其实最终目的也不是这个球碰撞了,只是试试,有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;
		}


	}
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏chenjx85的技术专栏

leetcode-476-Number Complement

17950
来自专栏aCloudDeveloper

算法导论第八章线性时间排序

一、线性时间排序算法历史概览       计数排序首先是由 Harold H. Seward 于1954年提出,而且他还提出将计数排序和基数排序进行结合的思想;...

24460
来自专栏蜉蝣禅修之道

LeetCode之Jump Game II

17740
来自专栏mathor

matlab—回归与内插(完结)

61740
来自专栏chenjx85的技术专栏

leetcode-507-Perfect Number

14940
来自专栏MyBlog

数值分析读书笔记(5)数值逼近问题(I)----插值极其数值计算

当给定插值函数是多项式函数的时候, 我们可以产生一种插值的方案, 下面介绍一下Lagrange插值

18310
来自专栏小狼的世界

利用JS实现的根据经纬度计算地球上两点之间的距离

第一种是默认地球是一个光滑的球面,然后计算任意两点间的距离,这个距离叫做大圆距离(The Great Circle Distance)。

15720
来自专栏繁花云

[C语言]7-3笔记

对数的定义:一般地,如果ax=N(a>0,且a≠1),那么数x叫做以a为底N的对数,记作x=logaN,读作以a为底N的对数,其中a叫做对数的底数,N叫做真数。

9600
来自专栏程序生活

Leetcode-Easy 657. Judge Route Circle

657. Judge Route Circle 描述: 题目很简单,就是判断路线能否组成一圈。向“右”走的步数一定要等于向“左”走的步数;向“下”走的步数一...

30640
来自专栏数据结构与算法

04:垂直直方图

4:垂直直方图 总时间限制: 1000ms 内存限制: 65536kB描述 输入4行全部由大写字母组成的文本,输出一个垂直直方图,给出每个字符出现的次数。注...

38370

扫码关注云+社区

领取腾讯云代金券