[Flash] Motion

  • Motion
  • Download: BallMotion.zip

    原先只是要簡單介紹get/set function以及interface的運用,結果卻寫了一個不小的範例,畫面如下:


    球體的產生程式碼如下:

    /* Ball.as */
    package xinyu.geom{
    import flash.display.Sprite;
    import flash.geom.Matrix;
    import flash.display.GradientType;
    import flash.display.SpreadMethod;
    import flash.display.DisplayObject;
    import flash.display.Shape;

    import xinyu.science.Science;
    import xinyu.motions.Motions;
    import xinyu.motions.CircleMotion2D;

    public class Ball extends Sprite{
    private var shape:Shape;
    public var motion:Motions;

    public function Ball(innCol:int, outCol:int, radius:Number = 20, degree:Number = 0){
    shape = new Shape();

    var fillType:String = GradientType.RADIAL;
    var colors:Array = [innCol, outCol];
    var alphas:Array = [1, 1];
    var ratios:Array = [0x00, 0xAA];
    var matr:Matrix = new Matrix();
    var spreadMethod:String = SpreadMethod.PAD;

    var radian:Number = Science.degToRad(degree);

    matr.createGradientBox(4*radius, 4*radius, 0, 0.5*radius*Math.cos(radian), 0.5*radius*Math.sin(radian));
    shape.graphics.beginGradientFill(fillType, colors, alphas, ratios, matr, spreadMethod);
    shape.graphics.drawCircle(2*radius,2*radius,radius);
    shape.graphics.endFill();

    shape.x = -2*radius;
    shape.y = -2*radius;
    addChild(shape);
    }

    public function setMotion(m:Motions){
    if(motion != null){
    motion.stop();
    removeChild(motion as DisplayObject);
    }
    motion = m;
    addChild(motion as DisplayObject);
    }
    }
    }

    主要的重點是將球體繪製在shape裡,setMotion()由設計者自己決定是否要讓motion特效重疊,這裡我設定為單一DisplayObject僅能有一個Motions Object,Motions為一個Interface,為了不要跟fl.motion相衝,所以將名稱宣告為Motions如下:

    /* Motions.as */
    package xinyu.motions{
    public interface Motions {
    function run():void;
    function stop():void;
    function get running():Boolean;
    }
    }

    run()跟stop()是控制motion內的timer的啟動與關閉,而get running()則是回傳timer內的running的值,我設定這三個function為時做Motion必要的函式。

    實做Motion的二維球體運動程式碼:

    /* CircleMotion2D.as */
    package xinyu.motions{
    import flash.display.Sprite;
    import flash.utils.Timer;
    import flash.events.TimerEvent

    import xinyu.motions.Motions;

    public class CircleMotion2D extends Sprite implements Motions{
    private var timer:Timer;
    private var rad:Number = 0;
    private var radius:Number;
    private var speed:Number;
    private var dir:int;
    private var xOffset:Number;
    private var yOffset:Number;

    public static const CW:int = 1;
    public static const CCW:int = -1;

    public function CircleMotion2D(xOffset:Number = 0 ,yOffset:Number = 0, radius:Number = 50, speed:Number = 0.1, fps:Number = 25, dir:Number = CircleMotion2D.CW){
    this.radius = radius;
    this.speed = Math.min(1, Math.max(speed, 0.001));
    this.dir = dir;
    this.xOffset = xOffset;
    this.yOffset = yOffset;

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

    private function onTimer(event:TimerEvent):void{
    this.parent.x = 100+radius*Math.cos(rad) + xOffset;
    this.parent.y = 100+radius*Math.sin(rad) + yOffset;

    rad += dir*speed;
    if(rad > 2*Math.PI){
    rad = 0;
    }
    }

    public function run():void{
    timer.start();
    }

    public function stop():void{
    timer.stop();
    }

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

    實做Motion的二維自由運動程式碼:

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

    import xinyu.motions.Motions;
    import xinyu.science.Science;

    public class SpaceMotion2D extends Sprite implements Motions{
    private var timer:Timer;
    private var x_dir:int;
    private var y_dir:int;
    private var speed:Number;
    private var range:Rectangle;

    public function SpaceMotion2D(range:Rectangle, speed:Number = 0.1, fps:Number = 25){
    this.range = range;
    this.speed = Math.min(20, Math.max(speed, 0.001));

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

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

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

    private function onTimer(event:TimerEvent):void{
    if(this.parent.x + this.parent.width/2 > range.width){
    x_dir = -1;
    }

    if(this.parent.x - this.parent.width/2 < range.x){
    x_dir = 1;
    }

    if(this.parent.y + this.parent.height/2 > range.height){
    y_dir = -1;
    }

    if(this.parent.y - this.parent.height/2 < range.y){
    y_dir = 1;
    }

    this.parent.x += x_dir*speed;
    this.parent.y += y_dir*speed;
    }

    public function run():void{
    timer.start();
    }

    public function stop():void{
    timer.stop();
    }

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

    這些運動函式多半會需要用到基本的數學物理的轉換,我把他寫在一個Class底下:

    /* Science */
    package xinyu.science{
    public class Science{
    public function Science(){
    }

    public static function radToDeg(rad:Number):Number{
    return rad/Math.PI*180;
    }

    public static function degToRad(deg:Number):Number{
    return deg/180*Math.PI;
    }

    public static function randInt(from:int = 0, end:int = 100):int{
    if(from > end){
    var temp:int = end;
    end = from;
    from = temp;
    }
    return Math.round(Math.random()*(end-from))-Math.abs(from);
    }
    }
    }

    最後在fla裡的第一個影格加上如下程式碼即可編譯執行:

    import xinyu.geom.Ball;
    import xinyu.motions.CircleMotion2D;
    import xinyu.motions.SpaceMotion2D;

    var ball1:Ball = new Ball(0xff0000, 0x0000ff, 20, -45);
    addChild(ball1);

    ball1.x = 100;
    ball1.y = 70;

    ball1.setMotion(new CircleMotion2D(ball1.x, ball1.y, 100, 0.1, 30, CircleMotion2D.CCW));
    ball1.motion.run();

    var ball2:Ball = new Ball(0x00ff00, 0x0000ff, 20, -45);
    addChild(ball2);

    ball2.x = 100;
    ball2.y = 100;

    ball2.setMotion(new SpaceMotion2D(new Rectangle(0,0,stage.stageWidth, stage.stageHeight), 5, 30));
    ball2.motion.run();

    這樣的寫法目的是要讓每個物件都可以套用已經設計好的Motion函式,而不必對每一個顯示物件重新設計過動作,如果要增加新的Motion也比較容易點。

No comments:

Post a Comment

Orange - data analysis tool

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