- 浏览: 1064824 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (695)
- 心情日记 (14)
- AS开发工具 (12)
- 文章转载 (99)
- AIR (5)
- 问题总结 (46)
- SWF格式 (7)
- 测试总结 (10)
- 外文资料 (9)
- 算法技术 (33)
- AS3常用开源库 (43)
- 源码范例 (102)
- FLEX (72)
- FLASH 优化 (33)
- 游戏开发 (49)
- 开发技术 (11)
- 工作应用 (34)
- AS3收集 (140)
- WebBase (0)
- 开发构想 (4)
- 设计模式 (2)
- 框架和框架范例 (19)
- RED5 (3)
- java开发 (3)
- JAVA (1)
- FLASH-3D (23)
- 3D (6)
- 书籍 (10)
- 业界信息资料 (3)
- C# (1)
- JavaScript (12)
- HTML5 (6)
- Flixel (1)
- D5Power RPG网页游戏引擎 (0)
- ColorMatrixFilter - 获得相应颜色的色调 函数 (0)
- Starling (0)
最新评论
-
老顽童203:
字体
水果忍者鼠标跟随特效制作[转载] -
hairball00:
[转] 放出超多的Flash组件源代码 -
he74552775:
flash AS3 RegExp简单功能用法(转) -
hanshuai1232000:
第四点,有利也有弊,等你做了大型的aprg,你就知道了
[转]位图数据内存优化 -
yangfantao:
太感谢
[转] 放出超多的Flash组件源代码
http://uh.9ria.com/space-29516-do-blog-id-7303.html
注:这里转载一篇文章,不较有意思,辛苦了这位作者,谢谢他的分享。因为是转载的,所以有些链接可能没过来,想看效果的,可以去作者这边去看 http://www.cnblogs.com/yjmyzz/archive/2010/04/20/1716504.html
坐标旋转是个啥概念呢?
如上图,(蓝色)小球 绕某一中心点旋转a角度后,到达(红色)小球的位置,则红色小球相对中心点的坐标为:
x1 = dx * cos(a) - dy * sin(a)
y1 = dy * cos(a) + dx * sin(a)
这个就是坐标旋转公式,如果要反向旋转,则公式要修正一下,有二种方法:
1.将a变成-a,即:
x1 = dx * cos(-a) - dy * sin(-a)
y1 = dy * cos(-a) + dx * sin(-a)
2.将正向旋转公式中的相减号交换
x1 = dx * cos(a) + dy * sin(a);
y1 = dy * cos(a) - dx * sin(a);
先来回顾一个经典的小球圆周运动:
var ball:Ball = new Ball(10);
var centerX:Number = stage.stageWidth/2;
var centerY:Number = stage.stageHeight/2;
var radius:Number = 50;
var angle:Number = 0;
addChild(ball);
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
ball.x = centerX + Math.cos(angle) * radius;
ball.y = centerY + Math.sin(angle) * radius;
graphics.lineStyle(1,0x999999);
graphics.moveTo(ball.x,ball.y);
function EnterFrameHandler(e:Event):void{
ball.x = centerX + Math.cos(angle) * radius;
ball.y = centerY + Math.sin(angle) * radius;
angle += 0.02;
if (angle<=2*Math.PI+0.02){
graphics.lineTo(ball.x,ball.y);
}
}
这个没啥特别的,接下来我们用坐标旋转公式换一种做法验证一下是否有效:
var ball:Ball = new Ball(10);
var centerX:Number = stage.stageWidth/2;
var centerY:Number = stage.stageHeight/2;
var radius:Number = 50;
var angle:Number = 0;
ball.vr = 0.02;//旋转角速度
ball.x = centerX + radius;
ball.y = centerY;
var cos:Number = Math.cos(ball.vr);
var sin:Number = Math.sin(ball.vr);
addChild(ball);
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
graphics.lineStyle(1,0x999999);
graphics.moveTo(ball.x,ball.y);
var i:Number = 0;
function EnterFrameHandler(e:Event):void{
var dx:Number = ball.x - centerX;
var dy:Number = ball.y - centerY;
var x2:Number = cos * dx - sin * dy;
var y2:Number = cos * dy + sin * dx;
ball.x = centerX + x2;
ball.y = centerY + y2;
i++;
if (i<=(2*Math.PI+ball.vr)/ball.vr){
trace(i);
graphics.lineTo(ball.x,ball.y);
}
}
效果完全相同,说明坐标旋转公式完全是有效的,问题来了:原本一个简单的问题,经过这样复杂的处理后,效果并没有变化,为何要化简为繁呢?
好处1:提高运行效率
下面演示的多个物体旋转的传统做法:
var arrBalls:Array = new Array(30);
var centerX:Number = stage.stageWidth/2;
var centerY:Number = stage.stageHeight/2;
for(var i:uint=0,j:uint=arrBalls.length;i<j;i++){
arrBalls[i] = new Ball(3 + Math.random()*5,Math.random()*0xffffff);
arrBalls[i].x = centerX + 100 * (Math.random()*2-1);
arrBalls[i].y = centerY + 100 * (Math.random()*2-1);
addChild(arrBalls[i]);
}
graphics.lineStyle(1);
graphics.moveTo(centerX,centerY-5);
graphics.lineTo(centerX,centerY+5);
graphics.moveTo(centerX-5,centerY);
graphics.lineTo(centerX+5,centerY);
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
function EnterFrameHandler(e:Event):void{
for(var i:uint=0,j:uint=arrBalls.length;i<j;i++){
var ball:Ball = arrBalls[i];
var dx:Number = ball.x - stage.stageWidth/2;
var dy:Number = ball.y - stage.stageHeight/2;
var dist:Number = Math.sqrt(dx*dx + dy*dy); //1次Math调用
ball.vr = Math.atan2(dy,dx);//2次Math调用
ball.vr += 0.005;
ball.x = centerX + dist * Math.cos(ball.vr);//3次Math调用
ball.y = centerY + dist * Math.sin(ball.vr);//4次Math调用
}
}
坐标旋转的新做法:
var arrBalls:Array = new Array(30);
var centerX:Number = stage.stageWidth/2;
var centerY:Number = stage.stageHeight/2;
var vr:Number = 0.01;
for(var i:uint=0,j:uint=arrBalls.length;i<j;i++){
arrBalls[i] = new Ball(3 + Math.random()*5,Math.random()*0xffffff);
arrBalls[i].x = centerX + 100 * (Math.random()*2-1);
arrBalls[i].y = centerY + 100 * (Math.random()*2-1);
arrBalls[i].vr = vr;
addChild(arrBalls[i]);
}
graphics.lineStyle(1);
graphics.moveTo(centerX,centerY-5);
graphics.lineTo(centerX,centerY+5);
graphics.moveTo(centerX-5,centerY);
graphics.lineTo(centerX+5,centerY);
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
//将Math函数的调用放到到循环体外
var cos:Number = Math.cos(vr);
var sin:Number = Math.sin(vr);
function EnterFrameHandler(e:Event):void{
for(var i:uint=0,j:uint=arrBalls.length;i<j;i++){
var ball:Ball = arrBalls[i];
var dx:Number = ball.x - stage.stageWidth/2;
var dy:Number = ball.y - stage.stageHeight/2;
var x2:Number = cos * dx - sin * dy;
var y2:Number = cos * dy + sin * dx;
ball.x = centerX + x2;
ball.y = centerY + y2;
}
}
对比代码可以发现,同样的效果用坐标旋转处理后,Math的调用全部提升到循环外部了,对于30个小球来讲,每一帧至少减少了30 * 4 = 120次的三角函数运算
好处2:可以方便的处理斜面反弹
先来看下正向/反向旋转的测试
var ball:Ball=new Ball(15);
addChild(ball);
var centerX:Number=stage.stageWidth/2;
var centerY:Number=stage.stageHeight/2;
var radius:Number=100;
ball.x=centerX+radius;
ball.y=centerY;
graphics.lineStyle(1,0xdddddd);
graphics.moveTo(centerX,centerY);
graphics.lineTo(ball.x,ball.y);
graphics.lineStyle(1);
graphics.moveTo(centerX,centerY -10);
graphics.lineTo(centerX,centerY +10);
graphics.moveTo(centerX-10,centerY);
graphics.lineTo(centerX+10,centerY);
var angle:Number=30*Math.PI/180;
btn1.addEventListener(MouseEvent.MOUSE_DOWN,btn1Click);
//旋转
function btn1Click(e:MouseEvent):void {
var cos:Number=Math.cos(angle);
var sin:Number=Math.sin(angle);
var dx:Number=ball.x-centerX;
var dy:Number=ball.y-centerY;
var x1:Number=dx*cos-dy*sin;
var y1:Number=dy*cos+dx*sin;
ball.x=centerX+x1;
ball.y=centerY+y1;
graphics.lineStyle(1,0xdddddd);
graphics.moveTo(centerX,centerY);
graphics.lineTo(ball.x,ball.y);
}
btn2.addEventListener(MouseEvent.MOUSE_DOWN,btn2Click);
//反转1
function btn2Click(e:MouseEvent):void {
var dx:Number=ball.x-centerX;
var dy:Number=ball.y-centerY;
var cos:Number=Math.cos(-angle);
var sin:Number=Math.sin(-angle);
var x1:Number=dx*cos-dy*sin;
var y1:Number=dy*cos+dx*sin;
ball.x=centerX+x1;
ball.y=centerY+y1;
graphics.lineStyle(1,0xdddddd);
graphics.moveTo(centerX,centerY);
graphics.lineTo(ball.x,ball.y);
}
btn3.addEventListener(MouseEvent.MOUSE_DOWN,btn3Click);
//反转2
function btn3Click(e:MouseEvent):void{
var dx:Number=ball.x-centerX;
var dy:Number=ball.y-centerY;
var cos:Number=Math.cos(angle);
var sin:Number=Math.sin(angle);
//反转公式
var x1:Number=dx*cos+dy*sin;
var y1:Number=dy*cos-dx*sin;
ball.x=centerX+x1;
ball.y=centerY+y1;
graphics.lineStyle(1,0xdddddd);
graphics.moveTo(centerX,centerY);
graphics.lineTo(ball.x,ball.y);
}
对于水平或垂直的反弹运动,实现起来并不复杂,但对于斜面而言,情况就复杂多了,首先:物体反弹并不是光学中的反射,所以用“入射角=反射角”来模拟并不准确,其次我们还要考虑到重力因素/摩擦力因素,这些都会影响到速度的大小和方向。
如果用坐标旋转的思维方式去考虑这一复杂的问题,解决办法就变得非常简单。
所有向量(物理学中也常称矢量,虽然这二者在严格意义上讲并不相同)都可应用坐标旋转,我们可以把整个系统(包括斜面以及相对斜面运行物体的速度向量)都通过坐标旋转变成水平面或垂直面,这样就把问题简单化了,等一切按水平或垂直的简单方式处理完成以后,再把系统旋转回最初的样子。
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.ui.Mouse;
import flash.ui.MouseCursor;
import flash.geom.Rectangle;
public class AngleBounce extends Sprite {
private var ball:Ball;
private var line:Sprite;
private var gravity:Number=0.25;
private var bounce:Number=-0.6;
private var rect:Rectangle;
public function AngleBounce() {
init();
}
private function init():void {
Mouse.cursor=MouseCursor.BUTTON;
ball=new Ball(10);
addChild(ball);
ball.x=100;
ball.y=100;
line=new Sprite ;
line.graphics.lineStyle(1);
line.graphics.lineTo(300,0);
addChild(line);
line.x=50;
line.y=200;
line.rotation=25;//将line旋转形成斜面
stage.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);
rect = line.getBounds(this);//获取line的矩形边界
graphics.beginFill(0xefefef)
graphics.drawRect(rect.left,rect.top,rect.width,rect.height);
graphics.endFill();
}
private function MouseDownHandler(e:Event) {
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
}
private function EnterFrameHandler(e:Event):void {
//line.rotation = (stage.stageWidth/2 - mouseX)*0.1;
//普通的运动代码
ball.vy+=gravity;
ball.x+=ball.vx;
ball.y+=ball.vy;
/*//只有二者(的矩形边界)碰撞了才需要做处理
if (ball.hitTestObject(line)) {*/
//也可以换成下面的方法检测
if (ball.x > rect.left && ball.x < rect.right && ball.y >rect.top && ball.y < rect.bottom){
//trace("true");
//获得角度及正余弦值
var angle:Number=line.rotation*Math.PI/180;
var cos:Number=Math.cos(angle);
var sin:Number=Math.sin(angle);
//获得 ball 与 line 的相对位置
var dx:Number=ball.x-line.x;
var dy:Number=ball.y-line.y;
//反向旋转坐标(得到ball“相对”斜面line的坐标)
var x2:Number=cos*dx+sin*dy;
var y2:Number=cos*dy-sin*dx;
//反向旋转速度向量(得到ball“相对”斜面的速度)
var vx2:Number=cos*ball.vx+sin*ball.vy;
var vy2:Number=cos*ball.vy-sin*ball.vx;
//实现反弹
if (y2>- ball.height/2) {
y2=- ball.height/2;
vy2*=bounce;
//将一切再正向旋转回去
dx=cos*x2-sin*y2;
dy=cos*y2+sin*x2;
ball.vx=cos*vx2-sin*vy2;
ball.vy=cos*vy2+sin*vx2;
//重新定位
ball.x=line.x+dx;
ball.y=line.y+dy;
}
}
//跑出舞台边界后将其重新放到原始位置
if (ball.x>=stage.stageWidth-ball.width/2||ball.y>=stage.stageHeight-ball.height/2) {
ball.x=100;
ball.y=100;
ball.vx=0;
ball.vy=0;
removeEventListener(Event.ENTER_FRAME,EnterFrameHandler);
}
}
}
}
多角度斜面反弹:
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.geom.Rectangle;
import flash.events.MouseEvent;
import flash.ui.Mouse;
import flash.ui.MouseCursor;
public class MultiAngleBounce extends Sprite {
private var ball:Ball;
private var lines:Array;
private var numLines:uint=5;
private var gravity:Number=0.3;
private var bounce:Number=-0.6;
public function MultiAngleBounce() {
init();
}
private function init():void {
stage.scaleMode=StageScaleMode.NO_SCALE;
stage.align=StageAlign.TOP_LEFT;
ball=new Ball(20);
addChild(ball);
ball.x=100;
ball.y=50;
// 创建 5 个 line 影片
lines = new Array();
for (var i:uint = 0; i < numLines; i++) {
var line:Sprite = new Sprite();
line.graphics.lineStyle(1);
line.graphics.moveTo(-50, 0);
line.graphics.lineTo(50, 0);
addChild(line);
lines.push(line);
}
// 放置并旋转
lines[0].x=100;
lines[0].y=100;
lines[0].rotation=30;
lines[1].x=100;
lines[1].y=230;
lines[1].rotation=45;
lines[2].x=250;
lines[2].y=180;
lines[2].rotation=-30;
lines[3].x=150;
lines[3].y=330;
lines[3].rotation=10;
lines[4].x=230;
lines[4].y=250;
lines[4].rotation=-30;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
ball.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);
ball.addEventListener(MouseEvent.MOUSE_OVER,MouseOverHandler);
stage.addEventListener(MouseEvent.MOUSE_UP,MouseUpHandler);
}
function MouseOverHandler(e:MouseEvent):void {
Mouse.cursor=MouseCursor.HAND;
}
function MouseDownHandler(e:MouseEvent):void {
Mouse.cursor=MouseCursor.HAND;
var bounds:Rectangle = new Rectangle(ball.width,ball.height,stage.stageWidth-2*ball.width,stage.stageHeight-2*ball.height);
ball.startDrag(true,bounds);
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
function MouseUpHandler(e:MouseEvent):void {
ball.stopDrag();
ball.vx=0;
ball.vy=0;
Mouse.cursor=MouseCursor.AUTO;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(event:Event):void {
// normal motion code
ball.vy+=gravity;
ball.x+=ball.vx;
ball.y+=ball.vy;
// 舞台四周的反弹
if (ball.x+ball.radius>stage.stageWidth) {
ball.x=stage.stageWidth-ball.radius;
ball.vx*=bounce;
} else if (ball.x - ball.radius < 0) {
ball.x=ball.radius;
ball.vx*=bounce;
}
if (ball.y+ball.radius>stage.stageHeight) {
ball.y=stage.stageHeight-ball.radius;
ball.vy*=bounce;
} else if (ball.y - ball.radius < 0) {
ball.y=ball.radius;
ball.vy*=bounce;
}
// 检查每条线
for (var i:uint = 0; i < numLines; i++) {
checkLine(lines[i]);
}
}
private function checkLine(line:Sprite):void {
// 获得 line 的边界
var bounds:Rectangle=line.getBounds(this);
if (ball.x>bounds.left&&ball.x<bounds.right) {
// 获取角度与正余弦值
var angle:Number=line.rotation*Math.PI/180;
var cos:Number=Math.cos(angle);
var sin:Number=Math.sin(angle);
// 获取 ball 与 line 的相对位置
var x1:Number=ball.x-line.x;
var y1:Number=ball.y-line.y;
// 旋转坐标
var y2:Number=cos*y1-sin*x1;
// 旋转速度向量
var vy1:Number=cos*ball.vy-sin*ball.vx;
// 实现反弹
if (y2>- ball.height/2&&y2<vy1) {
// 旋转坐标
var x2:Number=cos*x1+sin*y1;
// 旋转速度向量
var vx1:Number=cos*ball.vx+sin*ball.vy;
y2=- ball.height/2;
vy1*=bounce;
// 将一切旋转回去
x1=cos*x2-sin*y2;
y1=cos*y2+sin*x2;
ball.vx=cos*vx1-sin*vy1;
ball.vy=cos*vy1+sin*vx1;
ball.x=line.x+x1;
ball.y=line.y+y1;
}
}
}
}
}
作者:菩提树下的杨过
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
注:这里转载一篇文章,不较有意思,辛苦了这位作者,谢谢他的分享。因为是转载的,所以有些链接可能没过来,想看效果的,可以去作者这边去看 http://www.cnblogs.com/yjmyzz/archive/2010/04/20/1716504.html
坐标旋转是个啥概念呢?
如上图,(蓝色)小球 绕某一中心点旋转a角度后,到达(红色)小球的位置,则红色小球相对中心点的坐标为:
x1 = dx * cos(a) - dy * sin(a)
y1 = dy * cos(a) + dx * sin(a)
这个就是坐标旋转公式,如果要反向旋转,则公式要修正一下,有二种方法:
1.将a变成-a,即:
x1 = dx * cos(-a) - dy * sin(-a)
y1 = dy * cos(-a) + dx * sin(-a)
2.将正向旋转公式中的相减号交换
x1 = dx * cos(a) + dy * sin(a);
y1 = dy * cos(a) - dx * sin(a);
先来回顾一个经典的小球圆周运动:
var ball:Ball = new Ball(10);
var centerX:Number = stage.stageWidth/2;
var centerY:Number = stage.stageHeight/2;
var radius:Number = 50;
var angle:Number = 0;
addChild(ball);
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
ball.x = centerX + Math.cos(angle) * radius;
ball.y = centerY + Math.sin(angle) * radius;
graphics.lineStyle(1,0x999999);
graphics.moveTo(ball.x,ball.y);
function EnterFrameHandler(e:Event):void{
ball.x = centerX + Math.cos(angle) * radius;
ball.y = centerY + Math.sin(angle) * radius;
angle += 0.02;
if (angle<=2*Math.PI+0.02){
graphics.lineTo(ball.x,ball.y);
}
}
这个没啥特别的,接下来我们用坐标旋转公式换一种做法验证一下是否有效:
var ball:Ball = new Ball(10);
var centerX:Number = stage.stageWidth/2;
var centerY:Number = stage.stageHeight/2;
var radius:Number = 50;
var angle:Number = 0;
ball.vr = 0.02;//旋转角速度
ball.x = centerX + radius;
ball.y = centerY;
var cos:Number = Math.cos(ball.vr);
var sin:Number = Math.sin(ball.vr);
addChild(ball);
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
graphics.lineStyle(1,0x999999);
graphics.moveTo(ball.x,ball.y);
var i:Number = 0;
function EnterFrameHandler(e:Event):void{
var dx:Number = ball.x - centerX;
var dy:Number = ball.y - centerY;
var x2:Number = cos * dx - sin * dy;
var y2:Number = cos * dy + sin * dx;
ball.x = centerX + x2;
ball.y = centerY + y2;
i++;
if (i<=(2*Math.PI+ball.vr)/ball.vr){
trace(i);
graphics.lineTo(ball.x,ball.y);
}
}
效果完全相同,说明坐标旋转公式完全是有效的,问题来了:原本一个简单的问题,经过这样复杂的处理后,效果并没有变化,为何要化简为繁呢?
好处1:提高运行效率
下面演示的多个物体旋转的传统做法:
var arrBalls:Array = new Array(30);
var centerX:Number = stage.stageWidth/2;
var centerY:Number = stage.stageHeight/2;
for(var i:uint=0,j:uint=arrBalls.length;i<j;i++){
arrBalls[i] = new Ball(3 + Math.random()*5,Math.random()*0xffffff);
arrBalls[i].x = centerX + 100 * (Math.random()*2-1);
arrBalls[i].y = centerY + 100 * (Math.random()*2-1);
addChild(arrBalls[i]);
}
graphics.lineStyle(1);
graphics.moveTo(centerX,centerY-5);
graphics.lineTo(centerX,centerY+5);
graphics.moveTo(centerX-5,centerY);
graphics.lineTo(centerX+5,centerY);
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
function EnterFrameHandler(e:Event):void{
for(var i:uint=0,j:uint=arrBalls.length;i<j;i++){
var ball:Ball = arrBalls[i];
var dx:Number = ball.x - stage.stageWidth/2;
var dy:Number = ball.y - stage.stageHeight/2;
var dist:Number = Math.sqrt(dx*dx + dy*dy); //1次Math调用
ball.vr = Math.atan2(dy,dx);//2次Math调用
ball.vr += 0.005;
ball.x = centerX + dist * Math.cos(ball.vr);//3次Math调用
ball.y = centerY + dist * Math.sin(ball.vr);//4次Math调用
}
}
坐标旋转的新做法:
var arrBalls:Array = new Array(30);
var centerX:Number = stage.stageWidth/2;
var centerY:Number = stage.stageHeight/2;
var vr:Number = 0.01;
for(var i:uint=0,j:uint=arrBalls.length;i<j;i++){
arrBalls[i] = new Ball(3 + Math.random()*5,Math.random()*0xffffff);
arrBalls[i].x = centerX + 100 * (Math.random()*2-1);
arrBalls[i].y = centerY + 100 * (Math.random()*2-1);
arrBalls[i].vr = vr;
addChild(arrBalls[i]);
}
graphics.lineStyle(1);
graphics.moveTo(centerX,centerY-5);
graphics.lineTo(centerX,centerY+5);
graphics.moveTo(centerX-5,centerY);
graphics.lineTo(centerX+5,centerY);
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
//将Math函数的调用放到到循环体外
var cos:Number = Math.cos(vr);
var sin:Number = Math.sin(vr);
function EnterFrameHandler(e:Event):void{
for(var i:uint=0,j:uint=arrBalls.length;i<j;i++){
var ball:Ball = arrBalls[i];
var dx:Number = ball.x - stage.stageWidth/2;
var dy:Number = ball.y - stage.stageHeight/2;
var x2:Number = cos * dx - sin * dy;
var y2:Number = cos * dy + sin * dx;
ball.x = centerX + x2;
ball.y = centerY + y2;
}
}
对比代码可以发现,同样的效果用坐标旋转处理后,Math的调用全部提升到循环外部了,对于30个小球来讲,每一帧至少减少了30 * 4 = 120次的三角函数运算
好处2:可以方便的处理斜面反弹
先来看下正向/反向旋转的测试
var ball:Ball=new Ball(15);
addChild(ball);
var centerX:Number=stage.stageWidth/2;
var centerY:Number=stage.stageHeight/2;
var radius:Number=100;
ball.x=centerX+radius;
ball.y=centerY;
graphics.lineStyle(1,0xdddddd);
graphics.moveTo(centerX,centerY);
graphics.lineTo(ball.x,ball.y);
graphics.lineStyle(1);
graphics.moveTo(centerX,centerY -10);
graphics.lineTo(centerX,centerY +10);
graphics.moveTo(centerX-10,centerY);
graphics.lineTo(centerX+10,centerY);
var angle:Number=30*Math.PI/180;
btn1.addEventListener(MouseEvent.MOUSE_DOWN,btn1Click);
//旋转
function btn1Click(e:MouseEvent):void {
var cos:Number=Math.cos(angle);
var sin:Number=Math.sin(angle);
var dx:Number=ball.x-centerX;
var dy:Number=ball.y-centerY;
var x1:Number=dx*cos-dy*sin;
var y1:Number=dy*cos+dx*sin;
ball.x=centerX+x1;
ball.y=centerY+y1;
graphics.lineStyle(1,0xdddddd);
graphics.moveTo(centerX,centerY);
graphics.lineTo(ball.x,ball.y);
}
btn2.addEventListener(MouseEvent.MOUSE_DOWN,btn2Click);
//反转1
function btn2Click(e:MouseEvent):void {
var dx:Number=ball.x-centerX;
var dy:Number=ball.y-centerY;
var cos:Number=Math.cos(-angle);
var sin:Number=Math.sin(-angle);
var x1:Number=dx*cos-dy*sin;
var y1:Number=dy*cos+dx*sin;
ball.x=centerX+x1;
ball.y=centerY+y1;
graphics.lineStyle(1,0xdddddd);
graphics.moveTo(centerX,centerY);
graphics.lineTo(ball.x,ball.y);
}
btn3.addEventListener(MouseEvent.MOUSE_DOWN,btn3Click);
//反转2
function btn3Click(e:MouseEvent):void{
var dx:Number=ball.x-centerX;
var dy:Number=ball.y-centerY;
var cos:Number=Math.cos(angle);
var sin:Number=Math.sin(angle);
//反转公式
var x1:Number=dx*cos+dy*sin;
var y1:Number=dy*cos-dx*sin;
ball.x=centerX+x1;
ball.y=centerY+y1;
graphics.lineStyle(1,0xdddddd);
graphics.moveTo(centerX,centerY);
graphics.lineTo(ball.x,ball.y);
}
对于水平或垂直的反弹运动,实现起来并不复杂,但对于斜面而言,情况就复杂多了,首先:物体反弹并不是光学中的反射,所以用“入射角=反射角”来模拟并不准确,其次我们还要考虑到重力因素/摩擦力因素,这些都会影响到速度的大小和方向。
如果用坐标旋转的思维方式去考虑这一复杂的问题,解决办法就变得非常简单。
所有向量(物理学中也常称矢量,虽然这二者在严格意义上讲并不相同)都可应用坐标旋转,我们可以把整个系统(包括斜面以及相对斜面运行物体的速度向量)都通过坐标旋转变成水平面或垂直面,这样就把问题简单化了,等一切按水平或垂直的简单方式处理完成以后,再把系统旋转回最初的样子。
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.ui.Mouse;
import flash.ui.MouseCursor;
import flash.geom.Rectangle;
public class AngleBounce extends Sprite {
private var ball:Ball;
private var line:Sprite;
private var gravity:Number=0.25;
private var bounce:Number=-0.6;
private var rect:Rectangle;
public function AngleBounce() {
init();
}
private function init():void {
Mouse.cursor=MouseCursor.BUTTON;
ball=new Ball(10);
addChild(ball);
ball.x=100;
ball.y=100;
line=new Sprite ;
line.graphics.lineStyle(1);
line.graphics.lineTo(300,0);
addChild(line);
line.x=50;
line.y=200;
line.rotation=25;//将line旋转形成斜面
stage.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);
rect = line.getBounds(this);//获取line的矩形边界
graphics.beginFill(0xefefef)
graphics.drawRect(rect.left,rect.top,rect.width,rect.height);
graphics.endFill();
}
private function MouseDownHandler(e:Event) {
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
}
private function EnterFrameHandler(e:Event):void {
//line.rotation = (stage.stageWidth/2 - mouseX)*0.1;
//普通的运动代码
ball.vy+=gravity;
ball.x+=ball.vx;
ball.y+=ball.vy;
/*//只有二者(的矩形边界)碰撞了才需要做处理
if (ball.hitTestObject(line)) {*/
//也可以换成下面的方法检测
if (ball.x > rect.left && ball.x < rect.right && ball.y >rect.top && ball.y < rect.bottom){
//trace("true");
//获得角度及正余弦值
var angle:Number=line.rotation*Math.PI/180;
var cos:Number=Math.cos(angle);
var sin:Number=Math.sin(angle);
//获得 ball 与 line 的相对位置
var dx:Number=ball.x-line.x;
var dy:Number=ball.y-line.y;
//反向旋转坐标(得到ball“相对”斜面line的坐标)
var x2:Number=cos*dx+sin*dy;
var y2:Number=cos*dy-sin*dx;
//反向旋转速度向量(得到ball“相对”斜面的速度)
var vx2:Number=cos*ball.vx+sin*ball.vy;
var vy2:Number=cos*ball.vy-sin*ball.vx;
//实现反弹
if (y2>- ball.height/2) {
y2=- ball.height/2;
vy2*=bounce;
//将一切再正向旋转回去
dx=cos*x2-sin*y2;
dy=cos*y2+sin*x2;
ball.vx=cos*vx2-sin*vy2;
ball.vy=cos*vy2+sin*vx2;
//重新定位
ball.x=line.x+dx;
ball.y=line.y+dy;
}
}
//跑出舞台边界后将其重新放到原始位置
if (ball.x>=stage.stageWidth-ball.width/2||ball.y>=stage.stageHeight-ball.height/2) {
ball.x=100;
ball.y=100;
ball.vx=0;
ball.vy=0;
removeEventListener(Event.ENTER_FRAME,EnterFrameHandler);
}
}
}
}
多角度斜面反弹:
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.geom.Rectangle;
import flash.events.MouseEvent;
import flash.ui.Mouse;
import flash.ui.MouseCursor;
public class MultiAngleBounce extends Sprite {
private var ball:Ball;
private var lines:Array;
private var numLines:uint=5;
private var gravity:Number=0.3;
private var bounce:Number=-0.6;
public function MultiAngleBounce() {
init();
}
private function init():void {
stage.scaleMode=StageScaleMode.NO_SCALE;
stage.align=StageAlign.TOP_LEFT;
ball=new Ball(20);
addChild(ball);
ball.x=100;
ball.y=50;
// 创建 5 个 line 影片
lines = new Array();
for (var i:uint = 0; i < numLines; i++) {
var line:Sprite = new Sprite();
line.graphics.lineStyle(1);
line.graphics.moveTo(-50, 0);
line.graphics.lineTo(50, 0);
addChild(line);
lines.push(line);
}
// 放置并旋转
lines[0].x=100;
lines[0].y=100;
lines[0].rotation=30;
lines[1].x=100;
lines[1].y=230;
lines[1].rotation=45;
lines[2].x=250;
lines[2].y=180;
lines[2].rotation=-30;
lines[3].x=150;
lines[3].y=330;
lines[3].rotation=10;
lines[4].x=230;
lines[4].y=250;
lines[4].rotation=-30;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
ball.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);
ball.addEventListener(MouseEvent.MOUSE_OVER,MouseOverHandler);
stage.addEventListener(MouseEvent.MOUSE_UP,MouseUpHandler);
}
function MouseOverHandler(e:MouseEvent):void {
Mouse.cursor=MouseCursor.HAND;
}
function MouseDownHandler(e:MouseEvent):void {
Mouse.cursor=MouseCursor.HAND;
var bounds:Rectangle = new Rectangle(ball.width,ball.height,stage.stageWidth-2*ball.width,stage.stageHeight-2*ball.height);
ball.startDrag(true,bounds);
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
function MouseUpHandler(e:MouseEvent):void {
ball.stopDrag();
ball.vx=0;
ball.vy=0;
Mouse.cursor=MouseCursor.AUTO;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(event:Event):void {
// normal motion code
ball.vy+=gravity;
ball.x+=ball.vx;
ball.y+=ball.vy;
// 舞台四周的反弹
if (ball.x+ball.radius>stage.stageWidth) {
ball.x=stage.stageWidth-ball.radius;
ball.vx*=bounce;
} else if (ball.x - ball.radius < 0) {
ball.x=ball.radius;
ball.vx*=bounce;
}
if (ball.y+ball.radius>stage.stageHeight) {
ball.y=stage.stageHeight-ball.radius;
ball.vy*=bounce;
} else if (ball.y - ball.radius < 0) {
ball.y=ball.radius;
ball.vy*=bounce;
}
// 检查每条线
for (var i:uint = 0; i < numLines; i++) {
checkLine(lines[i]);
}
}
private function checkLine(line:Sprite):void {
// 获得 line 的边界
var bounds:Rectangle=line.getBounds(this);
if (ball.x>bounds.left&&ball.x<bounds.right) {
// 获取角度与正余弦值
var angle:Number=line.rotation*Math.PI/180;
var cos:Number=Math.cos(angle);
var sin:Number=Math.sin(angle);
// 获取 ball 与 line 的相对位置
var x1:Number=ball.x-line.x;
var y1:Number=ball.y-line.y;
// 旋转坐标
var y2:Number=cos*y1-sin*x1;
// 旋转速度向量
var vy1:Number=cos*ball.vy-sin*ball.vx;
// 实现反弹
if (y2>- ball.height/2&&y2<vy1) {
// 旋转坐标
var x2:Number=cos*x1+sin*y1;
// 旋转速度向量
var vx1:Number=cos*ball.vx+sin*ball.vy;
y2=- ball.height/2;
vy1*=bounce;
// 将一切旋转回去
x1=cos*x2-sin*y2;
y1=cos*y2+sin*x2;
ball.vx=cos*vx1-sin*vy1;
ball.vy=cos*vy1+sin*vx1;
ball.x=line.x+x1;
ball.y=line.y+y1;
}
}
}
}
}
作者:菩提树下的杨过
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
发表评论
-
水果忍者鼠标跟随特效制作[转载]
2012-03-01 16:06 2404实现这效果其实比较简单,主要是思路~! package ... -
[转]三次贝尔曲线
2011-11-10 01:09 1878http://bbs.9ria.com/viewt ... -
轻量级Eval库Grak轻量级Eval库Grak
2011-09-22 03:07 0轻量级Eval库Grak -
[转]AS3与数据结构
2011-09-14 01:08 0http://www.nshen.net/dataSt ... -
井字棋算法
2011-08-18 15:04 0井字棋算法井字棋算法 -
[转 自己改的一个滚动条类,理论上什么都能“滚”
2011-08-11 23:14 0http://bbs.9ria.com/viewthread. ... -
[转] 关于一段时间内鼠标没有移动,执行某函数
2011-08-10 00:22 0http://bbs.9ria.com/viewthread. ... -
很好的FLEX表情聊天界面
2011-08-09 02:06 0很好的FLEX表情聊天界面 -
Flash版《植物大战僵尸》源码
2011-08-09 01:34 0本帖最后由 IJUST 于 2 ... -
愤怒的小鸟 BOX2D FLASH
2011-08-09 01:27 0姊妹篇:Flash版《植物大战僵尸》源码今年就要大四啦,放暑假 ... -
[转]如何计算线段和圆的交点
2011-08-09 00:53 0http://www.thecodeway.com/b ... -
[转] 45度地图坐标转换
2011-07-30 02:41 0昨天有朋友问我 45度地图中关于鼠标点击如果进行坐标转化 ... -
[转]一个Collision类,其中的block方法可以实现两个物体之间的碰撞检测。
2011-07-30 02:35 1332第二个是书中的源代码给出了一个Collision类,其中 ... -
AS3的一些优化计算方法
2011-07-06 12:56 0http://www.cnitblog.com/flashli ... -
[转]AS3类:CRC32校验类
2011-07-06 12:54 2568http://www.cnitblog.com/flashli ... -
基于哈希表数据源的A星寻路算法 - [as 3.0]
2011-06-16 17:03 0在这贴的代码是为了有需要的人学习而不是 提供源码给别人用的 ... -
计算几何算法概览
2011-06-14 17:28 2097计算几何算法概览 一、引言 ... -
[演示] 判断点是否处于三角形内的算法分析
2011-06-14 17:26 3254http://bbs.wow8.org/thread-9429 ... -
判断点在直线的哪一侧
2011-06-14 17:04 0判断点在直线的哪一侧 2.2.1下面开始程序的设计: ... -
[转]动画中坐标旋转公式的原理
2011-05-25 23:30 1465有一定的其它语言编程基础,所以学习新语言还是比较快的。正在进军 ...
相关推荐
1、A点绕B点旋转X度,A点的新坐标算法。 2、两点坐标之间的距离
关于坐标旋转的公式推导,包括原点旋转以及坐标系的旋转公式推导
通量碳坐标旋转,用于校正数据,很好用很好用的
数学公式,关于坐标系上的坐标通过一定角度旋转,求旋转后坐标的公式
实现空间某点,以指定空间点为坐标,进行任意方向旋转,得到空间坐标
本程序实现了基于七参数法的旋转平移矩阵,可以实现对三维坐标图像的旋转、平移,其中旋转包含了六种旋转顺序(xyz,xzy,yxz,yzx,zyx,zxy)可根据需要选择对应的参数,开发环境VS2013 程序实现参考了文章《朱宁宁. 三...
三维空间坐标的旋转算法
机器人坐标系变换 坐标变换-旋转部分 二维坐标旋转的向量和几何表示 对于以前数学学习不好的人来说,在机器人的坐标变换里,总是各种蒙。 这个图片来给你解答。
使用opencv对图像进行旋转,分为图像尺寸不变和尺寸变大两种,对尺寸变大时计算旋转后对应的坐标值。
Unity 3D 观察物体 旋转查看物体 世界坐标与局部坐标旋转转换 旋转物体问题
可以在excel中显示三维x、y、z散点图,坐标旋转公式、vba编程
今天小编就为大家分享一篇python实现一个点绕另一个点旋转后的坐标,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
讲解旋转坐标变化的几种方法
if p==1 xx = x; yy = y*cos(ang)-z*sin(ang); zz = z*cos(ang)+y*sin(ang); elseif p==2 xx = x*cos(ang)+z*sin(ang); yy = y; zz = z*cos(ang)-x*sin(ang); else xx = x*cos(ang)-y*sin(ang);...end
VC++ Graphic图形坐标旋转,可实现任意角度旋转,很好的学习源代码
惯性导航中一些比较常用的坐标系转换的matlab代码。
当屏幕旋转时重新设置控件的布局,使之适合新的布局
RationalDMIS 7.0 旋转坐标系http://blog.sina.com.cn/jianhongwei1989
在sfunction中,纯C代码写的三相双同步旋转坐标系锁相环,同时输出三相电压波形和锁相环三角波形,效果很好,运行环境MATLAB2014B,请对应版本,用于学习,不可用于商业用途。打开仿真模型后,先运行mex一下C函数,...