[Flash] abstract class & virtual function

  • abstract class & virtual function
  • 在c++裡我們有virtual function可以用,在Java裡則可以宣告abstract class ,而在actionscript 3.0雖然有undocumented的virtual specifier可以使用,但卻無法達到pure virtual function的效果,所幸還有override可以發揮,我們一樣也可以在actionscript 3.0達到abstract class的效果,一個簡易的範例如下:

    /* Motion.as */
    package com.xinyu.motion{
    public class Motion{
    public virtual function get running():Boolean{
    return false;
    }

    public virtual function start():void{
    }

    public virtual function stop():void{
    }
    }
    }

    借用之前motion那一篇文章裡的程式碼,只是這裡我們不使用interface的方式來設定,並且將整個motion獨立出來。可以看到我在Motion裡所宣告的函式都加上virtual關鍵字,實際上有沒有加上都不會有任何差別,只是這麼做是為了一個良好的設計習慣。

    底下則是一個SpaceMotion2D繼承於Motion的撰寫方式。

    /* SpaceMotion2D */
    package com.xinyu.motion{
    import flash.display.Sprite;
    import flash.utils.Timer;
    import flash.events.TimerEvent
    import flash.geom.Rectangle;
    import flash.display.DisplayObject;

    import com.xinyu.motion.Motion;
    import com.xinyu.science.Science;

    public class SpaceMotion2D extends Motion{
    private var _timer:Timer;
    protected var _xDir:int;
    protected var _yDir:int;
    protected var _speed:Number;
    protected var _range:Rectangle;
    protected var _obj:DisplayObject;

    public function SpaceMotion2D(obj:DisplayObject, range:Rectangle, speed:Number = 0.1, fps:Number = 25){
    _obj = obj;
    _range = range;
    _speed = Math.min(20, Math.max(speed, 0.001));

    do{
    _xDir = Science.randInt(-1,1);
    }while(_xDir == 0);

    do{
    _yDir = Science.randInt(-1,1);
    }while(_yDir == 0);

    _timer = new Timer(1000/fps);
    _timer.addEventListener(TimerEvent.TIMER, onTimer);
    }

    protected function onTimer(event:TimerEvent):void{
    if(_obj.x + _obj.width/2 + _speed > _range.width){
    _xDir = -1;
    }

    if(_obj.x - _obj.width/2 - _speed < _range.x){
    _xDir = 1;
    }

    if(_obj.y + _obj.height/2 + _speed > _range.height){
    _yDir = -1;
    }

    if(_obj.y - _obj.height/2 - _speed < _range.y){
    _yDir = 1;
    }

    _obj.x += _xDir * _speed;
    _obj.y += _yDir * _speed;
    }

    override public function start():void{
    _timer.start();
    }

    override public function stop():void{
    _timer.stop();
    }

    override public function get running():Boolean{
    return _timer.running;
    }
    }
    }

    如同剛剛所說的,為了培養良好的設計模式,請在start(), stop(), running()前面都加上override以表示這些functions是從Motion繼承而來重新實做的。

    所以大致上AS3裡的abstract class就是以這種方式來實現,至於AS4裡會怎麼去定義這個性質就請拭目以待啦!

    另外如果你有興趣的話也可以將SpaceMotion2D改成3D,下面就是一個SpaceMotion3D繼承於SpaceMotion2D的寫法:

    /* SpaceMotion3D */
    package com.xinyu.motion{
    import flash.display.Sprite;
    import flash.utils.Timer;
    import flash.events.TimerEvent;
    import flash.geom.Rectangle;
    import flash.display.DisplayObject;

    import com.xinyu.motion.SpaceMotion2D;
    import com.xinyu.science.Science;

    public class SpaceMotion3D extends SpaceMotion2D {
    private var _zDir:int;
    private var _z:Number;
    private var _depth:Number;
    private var xyScaleRatio:Number;
    private var objScaleRatio:Number;

    public function SpaceMotion3D(obj:DisplayObject, range:Rectangle, depth:Number, speed:Number = 1, fps:Number=25) {
    super(obj, range, speed, fps);

    _z = depth;
    _depth = depth;

    calXYScaleRatio();
    calObjScaleRatio();

    do {
    _zDir = Science.randInt(-1, 1);
    } while (_zDir == 0);
    }

    override protected function onTimer(event:TimerEvent):void {
    var zRatio:Number = _z / _depth;

    if (_obj.x + _obj.width / 2 + _speed > _range.width - _range.width * xyScaleRatio * zRatio ) {
    _xDir=-1;
    }
    if (_obj.x - _obj.width / 2 - _speed < _range.x + _range.width * xyScaleRatio * zRatio) {
    _xDir=1;
    }
    if (_obj.y + _obj.height / 2 + _speed > _range.height - _range.height * xyScaleRatio * zRatio ) {
    _yDir=-1;
    }
    if (_obj.y - _obj.height / 2 - _speed < _range.y + _range.height * xyScaleRatio * zRatio) {
    _yDir=1;
    }

    if (_z - _speed < 0) {
    _zDir = 1;
    }else if (_z + _speed > _depth) {
    _zDir = -1;
    }

    _obj.x += _xDir * _speed;
    _obj.y += _yDir * _speed;
    _z += _zDir * _speed;
    _obj.scaleX = 1 - objScaleRatio * zRatio;
    _obj.scaleY = 1 - objScaleRatio * zRatio;
    }

    private function calXYScaleRatio():void{
    var max: Number = Science.findMax(_range.width, _range.height);
    xyScaleRatio = _depth / ( 4*max);
    xyScaleRatio = Math.min(0.9, Math.max(xyScaleRatio, 0.1));
    }

    private function calObjScaleRatio():void{
    var min: Number = Science.findMin(_range.width, _range.height);
    objScaleRatio = min / (2 * _depth);
    objScaleRatio = Math.min(0.9, Math.max(objScaleRatio, 0.1));
    }
    }
    }

    這裡的3D效果是我簡單以視覺的判斷產生出來的,並沒有透過嚴謹的mathematical計算來達成,也就是說SpaceMotion3D.as並不是仰賴Flash CS4的z-axes的功能,想要更完善的功能請使用PaperVision3D吧!

No comments:

Post a Comment

Orange - data analysis tool

Installation pip install orange3 Run orange python -m Orange.canvas