神奇的曲线

手头项目做到尾声了。 在整理代码的时候无意中想到,项目中大量的用到了 greenSock 的 TweenMax 和 TweenLite 甚至是 Loader

查询资料后发现 这个开源的缓动类库实际上不允许运用在 商业项目中的。项目要是在国内运营还好,问题是项目是运营在facebook 上的,这样就比较危险了。
于是动手自己编写了一个缓动类库进行替换(还好项目中只有4处用到了缓动)。 但是!! 由于项目中打击怪物掉落物品的这一个效果是使用 TweenMax 的俱乐部插件绘制的抛物线,这块要自行模拟就比较复杂了。

由于要实现的效果是物品上抛时减速,下落时加速的效果。
于是我先根据抛物线公式,通过x轴偏移计算当前y轴高度。

下面这个类来源:http://www.cnblogs.com/meteoric_cry/archive/2012/04/16/2452925.html
[cc lang=”actionscript3″ nowrap=”false”]
package
{
import flash.geom.Point;
/**
* …
* @author Meteoric
*/
public class Parabola
{
private var startPt:Point;
private var endPt:Point;
private var vertexPt:Point;
private var a:Number;
private var b:Number;
private var c:Number;

public function Parabola(pt1:Point, pt2:Point)
{
startPt = pt1;
endPt = pt2;
parse();
}
public function parse(waveHeight:Number=140):void
{
vertexPt = new Point(startPt.x + (endPt.x – startPt.x) / 2, endPt.y – waveHeight);
var x1:Number = startPt.x;
var x2:Number = endPt.x;
var x3:Number = vertexPt.x;
var y1:Number = startPt.y;
var y2:Number = endPt.y;
var y3:Number = vertexPt.y;
b = ((y1 – y3) * (x1 * x1 – x2 * x2) – (y1 – y2) * (x1 * x1 – x3 * x3)) / ((x1 – x3) * (x1 * x1 – x2 * x2) – (x1 – x2) * (x1 * x1 – x3 * x3));
a = ((y1 – y2) – b * (x1 – x2)) / (x1 * x1 – x2 * x2);
c = y1 – a * x1 * x1 – b * x1;
trace(a, b, c);
}
public function getY(posX:Number):Number
{
var posY:Number = a * posX * posX + b * posX + c;
return posY;
}
}
}
[/cc]

曲线的效果是有了,但却是匀速运动的。 于是试着对x轴进行加速缓动。 但是效果很假,加速效果和曲线的上升和下降的过程无法契合。

接着,我想到了物理加速度算法,这个是经典的2D游戏中,人物跳跃的算法

[cc lang=”actionscript3″ nowrap=”false”]

import flash.display.DisplayObject;
import flash.utils.Dictionary;
import flash.events.Event;
import flash.events.KeyboardEvent;

stage.addEventListener(Event.ENTER_FRAME, onEnter);
stage.addEventListener(KeyboardEvent.KEY_DOWN,isDown);

var jumpCache : Dictionary = new Dictionary(true);

function isDown(e:KeyboardEvent) : void
{
jump(ball,{gravity : .98, power : 10, speed : Math.random()*6 – 3, ground : 300});
}

function jump(target : DisplayObject, params : Object) : void
{
jumpCache[target] = {
gravity : params.gravity,
power : params.power,
speedX : params.speed,
ground : params.ground,
key : target,
speedY : 0,
hasJump : false
};
}

function onEnter(e:Event) : void
{
var obj : Object;

for each(obj in jumpCache){
if(!obj.hasJump){
obj.hasJump = true;
obj.speedY = – obj.power;
//trace(getTimer());
}
obj.key.x += obj.speedX;
obj.speedY += obj.gravity;
obj.key.y += obj.speedY;
if(obj.key.y >= obj.ground){
obj.key.y = obj.ground;

delete jumpCache[obj.key];
obj = null;
//trace(getTimer());
}
}
}
[/cc]

可以说,效果完全满足了,但是却有个极大的缺陷,即无法准确的控制下坠地点及整个下落过程的持续时间。
思索了许久,查阅了很多资料后,终于发现了这货 – 贝赛尔曲线
贝塞尔曲线的特征和重力加速的一样,在靠近2点时的速度极快,在过程中减速。 重点是贝塞尔曲线的一切都是可控的。

源码:
[cc lang=”actionscript3″ nowrap=”false”]
import flash.geom.Point;
import flash.events.Event;
import flash.events.MouseEvent;
import fl.controls.Label;

btnStart.addEventListener(MouseEvent.CLICK,onClick);

var ps : Vector. = new Vector.();
var t:Number = 0;
var index:int = 0;

for(var i : int = 0; i < 3 ; i ++){ this["drag" + i].addEventListener(MouseEvent.MOUSE_DOWN,onDragDown); } function onDragDown(e:MouseEvent) : void { e.target.addEventListener(MouseEvent.MOUSE_MOVE, onDragMove); e.target.addEventListener(MouseEvent.MOUSE_UP, onDragUp); } function onDragMove(e:MouseEvent) : void { e.target.startDrag(); } function onDragUp(e:MouseEvent) : void { e.target.stopDrag(); e.target.removeEventListener(MouseEvent.MOUSE_MOVE, onDragMove); e.target.removeEventListener(MouseEvent.MOUSE_UP, onDragUp); } function onClick(e:MouseEvent):void { stage.removeEventListener(Event.ENTER_FRAME, onEnter); index = 0; t = 0; var p0:Point = new Point(drag0.x,drag0.y); var p1:Point = new Point(drag1.x,drag1.y); var p2:Point = new Point(drag2.x,drag2.y); var time:Number = Number(duration.text); var count:Number = time / 40; var speed:Number = 1 / count; countPs(speed,p0,p1,p2); } function countPs(speed : Number, p0 : Point, p1 : Point, p2 : Point):void { ps.splice(0,ps.length); while (t <=1) { var posX : Number = Math.pow(1-t,2) * p0.x + 2 * t * (1-t) * p1.x + Math.pow(t,2) * p2.x; var posY : Number = Math.pow(1-t,2) * p0.y + 2 * t * (1-t) * p1.y + Math.pow(t,2) * p2.y; ps.push(new Point(posX,posY)); t += speed; } stage.addEventListener(Event.ENTER_FRAME, onEnter); } function onEnter(e:Event):void { var nextP:Point = ps[(index + 1) % ps.length]; ball.x = nextP.x; ball.y = nextP.y; index++; } [/cc] 贝塞尔曲线的所有公式 : http://zh.wikipedia.org/wiki/%E8%B2%9D%E8%8C%B2%E6%9B%B2%E7%B7%9A

发表评论

电子邮件地址不会被公开。 必填项已用*标注