MoveEx效果

  Flex有一个Move效果,播放该效果时,目标对象会沿直线运动。有时候我们需要更丰富一些的运动效果,比如抛物线运动,Move就显得无能为力了。基于这种需求,我创建了一个MoveEx类,可以播放大多数的运动效果。
  通过查看Flex源代码可以看出,Move以及MoveInstance分别继承自TweenEffect与TweenEffectInstance,Move效果实际就是创建Tween对象,并通过它来改变目标的x与y属性。因此可以考虑只用Tween来改变目标的x属性,而y属性则根据一个函数得出结果,那样一来,如果在函数里指定为直线方程,那么效果就是直线运动,指定为抛物线方程,效果就是抛物线运动…… 这样会灵活许多。
  有人可能会问了,如果实现垂直运动效果,x属性是不变的,所以也就没办法播放垂直运动效果了。其实针对这种情况,可以设计让Tween来改变目标的y属性,然后根据一个函数得出x属性的值。甚至我们需要加一个额外属性,指定Tween改变目标的哪个属性:x或y。因为我只想要一个简单的开口向下的抛物线效果,所以就不考虑这种情况了。
  实现代码如下所示:

[b]MoveEx.as[/b]

package com.thornbird.effects
{

import com.swoondazzle.plantsVSAnimals.effects.effectClasses.MoveExInstance;

import mx.effects.IEffectInstance;
import mx.effects.TweenEffect;

/**
* 移动扩展效果
*/
public class MoveEx extends TweenEffect
{

//--------------------------------------------------------------------------
//
// Class constants
//
//--------------------------------------------------------------------------

/**
* @private
* 影响的属性
*/
private static var AFFECTED_PROPERTIES:Array = ["x", "y"];

//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------

/**
* Constructor
*/
public function MoveEx(target:Object = null)
{
super(target);
instanceClass = MoveExInstance;
}

//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------

/**
* @private
*/
private var beelineParameters:Array = null;

/**
* @private
*/
private var parabolaParameters:Array = null;

//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------

//----------------------------------
// xFrom
//----------------------------------

/**
* 起点x坐标
*/
public var xFrom:Number = NaN;

//----------------------------------
// xTo
//----------------------------------

/**
* 终点x坐标
*/
public var xTo:Number = NaN;

//----------------------------------
// track
//----------------------------------

/**
* 运动轨迹函数
*/
public var track:Function = null;

//--------------------------------------------------------------------------
//
// Overridden methods
//
//--------------------------------------------------------------------------

/**
* @private
*/
override public function getAffectedProperties():Array
{
return AFFECTED_PROPERTIES;
}

/**
* @private
*/
override protected function initInstance(instance:IEffectInstance):void
{
super.initInstance(instance);
var moveExInstance:MoveExInstance = instance as MoveExInstance;
moveExInstance.xFrom = xFrom;
moveExInstance.xTo = xTo;
moveExInstance.track = track;
}

//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------

/**
* 创建直线运动轨迹函数
* @param startX 起点x坐标
* @param startY 起点y坐标
* @param endX 终点x坐标
* @param endY 终点y坐标
*/
public function createBeelineTrack(startX:Number, startY:Number,
endX:Number, endY:Number):void
{
// 此时起点与终点已经确定
xFrom = startX;
xTo = endX;
var x1:Number = startX;
var y1:Number = startY;
var x2:Number = endX;
var y2:Number = endY;
// 将k, b分别代入 y = k * x + b 得出k, b的值:
var k:Number = (y1 - y2) / (x1 - x2);
var b:Number = b = y1 - x1 * k;
beelineParameters = [k, b];
track = beeline;
}

/**
* 创建抛物线轨迹函数
* @param startX 起点x坐标
* @param startY 起点y坐标
* @param distance 距离
* @param height高度
*/
public function createParabolaTrack(startX:Number, startY:Number,
distance:Number, height:Number):void
{
// 此时起点与终点已经确定
xFrom = startX;
xTo = startX + distance;
var x1:Number = xFrom;
var y1:Number = 0;
var x2:Number = xTo;
var y2:Number = 0;
var x0:Number = x1 + distance / 2;
var y0:Number = height;
// 将x1, y1, x2, y2, x0, y0分别代入 y = a * Math.pow(x, 2) + b * x + c
// 得出a, b, c的值:
var a:Number = ((x1 - x0) * (y1 - y2) - (x1 - x2) * (y1 - y0))
/ ((x1 - x0) * (Math.pow(x1, 2) - Math.pow(x2, 2))
- (x1 - x2) * (Math.pow(x1, 2) - Math.pow(x0, 2)));
var b:Number = ((y1 - y2) - (Math.pow(x1, 2) - Math.pow(x2, 2)) * a)
/ (x1 - x2);
var c:Number = y1 - Math.pow(x1, 2) * a + x1 * b;
parabolaParameters = [a, b, c, startY];
track = parabola;
}

/**
* @private
*/
public function beeline(x:Number):Number
{
var k:Number = beelineParameters[0];
var b:Number = beelineParameters[1];
return (x * k + b);
}

/**
* @private
*/
public function parabola(x:Number):Number
{
var a:Number = parabolaParameters[0];
var b:Number = parabolaParameters[1];
var c:Number = parabolaParameters[2];
var y:Number = parabolaParameters[3];
var h:Number = parabolaParameters[4];
return (y - ((Math.pow(x, 2) * a + x * b + c)
- (Math.pow(xFrom, 2) * a + xFrom * b + c)));
}

}

}


[b]MoveExInstance.as[/b]

package com.thornbird.effects.effectClasses
{

import flash.events.Event;

import mx.core.Container;
import mx.core.EdgeMetrics;
import mx.core.IUIComponent;
import mx.core.mx_internal;
import mx.effects.EffectManager;
import mx.effects.effectClasses.TweenEffectInstance;
import mx.events.MoveEvent;

use namespace mx_internal;

/**
* 移动扩展效果实例
*/
public class MoveExInstance extends TweenEffectInstance
{

//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------

/**
* @private
*/
private var forceClipping:Boolean = false;

/**
* @private
*/
private var checkClipping:Boolean = true;

//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------

/**
* Constructor
*/
public function MoveExInstance(target:Object)
{
super(target);
}

//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------

//----------------------------------
// xFrom
//----------------------------------

/**
* 起点x坐标
*/
public var xFrom:Number = NaN;

//----------------------------------
// xTo
//----------------------------------

/**
* 终点x坐标
*/
public var xTo:Number = NaN;

//----------------------------------
// track
//----------------------------------

/**
* 运动轨迹函数
*/
public var track:Function = null;

//--------------------------------------------------------------------------
//
// Overridden methods
//
//--------------------------------------------------------------------------

/**
* @private
*/
override public function initEffect(event:Event):void
{
super.initEffect(event);
if (event is MoveEvent && event.type == MoveEvent.MOVE)
{
if (isNaN(xFrom) && isNaN(xTo))
{
xFrom = MoveEvent(event).oldX;
xTo = target.x;
}
}
}

/**
* @private
*/
override public function play():void
{
super.play();
EffectManager.startBitmapEffect(IUIComponent(target));
tween = createTween(this, [xFrom], [xTo], duration);
var targetParent:Container = target.parent as Container;
if (targetParent != null)
{
var yFrom:Number = calculateYCoord(xFrom);
var yTo:Number = calculateYCoord(xTo);
var vm:EdgeMetrics = targetParent.viewMetrics;
var l:Number = vm.left;
var r:Number = targetParent.width - vm.right;
var t:Number = vm.top;
var b:Number = targetParent.height - vm.bottom;
if (xFrom < l || xTo < l
|| xFrom + target.width > r
|| xTo + target.width > r
|| yFrom < t || yTo < t
|| yFrom + target.height > b
|| yTo + target.height > b)
{
forceClipping = true;
targetParent.forceClipping = true;
}
}
applyTweenStartValues();
}

/**
* @private
*/
override public function onTweenUpdate(value:Object):void
{
EffectManager.suspendEventHandling();
var x:Number = value[0];
var y:Number = calculateYCoord(x);
if (!forceClipping && checkClipping)
{
var targetParent:Container = target.parent as Container;
if (targetParent != null)
{
var vm:EdgeMetrics = targetParent.viewMetrics;
var l:Number = vm.left;
var r:Number = targetParent.width - vm.right;
var t:Number = vm.top;
var b:Number = targetParent.height - vm.bottom;
if (x < l || x + target.width > r
|| y < t || y + target.height > b)
{
forceClipping = true;
targetParent.forceClipping = true;
}
}
}
target.move(x, y);
EffectManager.resumeEventHandling();
}

/**
* @private
*/
override public function onTweenEnd(value:Object):void
{
EffectManager.endBitmapEffect(IUIComponent(target));
if (forceClipping)
{
var targetParent:Container = target.parent as Container;
if (targetParent != null)
{
forceClipping = false;
targetParent.forceClipping = false;
}
}
checkClipping = false;
super.onTweenEnd(value);
}

//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------

/**
* @private
* 根据x坐标计算y坐标
* @param x x坐标
*/
private function calculateYCoord(x:Number):Number
{
var y:Number = 0;
if (track != null)
return track(x);
return target.y;
}

}

}


[b]示例代码[/b]

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:effect="com.thornbird.effects.*"
layout="absolute">

<mx:Script>
<![CDATA[
private function beginMove():void
{
moveEx.createParabolaTrack(0, 100, 800, 100);
moveEx.play([button]);
}
]]>
</mx:Script>

<effect:MoveEx id="moveEx" xFrom="0" xTo="700" duration="1000" />
<mx:Button id="button" x="0" y="100" label="Button" click="beginMove()" />

</mx:Application>


  这样一个简单的抛物线效果就完成了。这是我山寨植物大战僵尸游戏时用到的,代码很简单,主要是初中的几何知识几乎都忘光了,解方程还算了半天。不胜唏嘘。
  另外,MoveInstance类的onTweenUpdate()方法中,有这么一行代码:EffectManager.suspendEventHandling(); 这行代码屏蔽了move,需要注意一下。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值