[AS3.0] ドットの光 (7)

光るドットの表現をAS3.0で! :boy:

dotLight37

:caution: 要 Flash Player 9 以上
:caution: 要注意 サウンドが鳴ります。

This movie requires Flash Player 9.0.0

DotLight.as (jp.nya.project.effects.DotLight.as)
package jp.nya.project.effects {

  import flash.display.Sprite;
  import flash.display.Bitmap;
  import flash.display.BitmapData;
  import flash.display.PixelSnapping;
  import flash.display.BlendMode;
  import flash.geom.Matrix;
  import flash.geom.Rectangle;
  import flash.events.Event;
  import jp.nya.project.effects.EmitLight;
  import jp.nya.project.effects.Fireworks;


  public class DotLight extends Sprite {
    // プロパティ
    private var rect:Rectangle;
    private var canvas:BitmapData;
    private var sparkle:BitmapData;
    private var sky:BitmapData;
    private static var scale:uint = 4;
    private var matrix:Matrix;
    private var light:EmitLight;
    private var fireworks:Array;
    private var garbage:Array;

    // コンストラクタ
    public function DotLight(r:Rectangle) {
      rect = r;
      init();
    }

    // メソッド
    private function init():void {
      sky = new BitmapData(rect.width, rect.height, false, 0xFF000000);
      var bitmap:Bitmap = new Bitmap(sky);

      addChild(bitmap);
      canvas = new BitmapData(rect.width, 20, false, 0xFF000000);
      var cBitmap:Bitmap = new Bitmap(canvas);

      cBitmap.y = rect.height - 20;
      addChild(cBitmap);
      sparkle = new BitmapData(rect.width/scale, 20/scale, false, 0xFF000000);
      var sBitmap:Bitmap = new Bitmap(sparkle);

      sBitmap.smoothing = true;
      sBitmap.blendMode = BlendMode.ADD;
      sBitmap.scaleX = sBitmap.scaleY = scale;

      sBitmap.y = rect.height - 20;
      addChild(sBitmap);
      matrix = new Matrix(1/scale, 0, 0, 1/scale, 0, 0);
      light = new EmitLight(canvas);
      fireworks = new Array();
      garbage = new Array();
      addEventListener(Event.ENTER_FRAME, draw, false, 0, true);
    }
    public function launch():void {
      var firework:Fireworks = new Fireworks(sky);
      firework.id = fireworks.length;
      firework.create();
      firework.addEventListener(Fireworks.COMPLETE, complete, false, 0, true);
      fireworks.push(firework);
    }
    private function draw(evt:Event):void {
      light.create(10);
      canvas.lock();
      canvas.fillRect(canvas.rect, 0x00000000);
      light.emit();
      canvas.unlock();
      sky.lock();
      sky.fillRect(sky.rect, 0x00000000);
      if (garbage.length > 0) remove();
      for (var n:uint = 0; n < fireworks.length; n++) {
        var firework:Fireworks = fireworks[n];
        firework.emit();

      }
      sky.unlock();
      sparkle.lock();
      sparkle.draw(canvas, matrix);
      sparkle.unlock();
    }
    private function complete(evt:Event):void {
      var firework:Fireworks = Fireworks(evt.target);
      firework.removeEventListener(Fireworks.COMPLETE, complete);
      garbage.push(firework.id);
    }
    private function remove():void {
      for (var n:uint = 0; n < garbage.length; n++) {
        var id:uint = garbage[n];
        var firework:Fireworks = fireworks[id];
        firework = null;
        fireworks.splice(id, 1);
      }
      reset();
    }
    private function reset():void {
      for (var n:uint = 0; n < fireworks.length; n++) {
        var firework:Fireworks = fireworks[n];
        firework.id = n;
      }
      garbage = new Array();
    }

  }

}

EmitLight.as (jp.nya.project.effects.EmitLight.as)
package jp.nya.project.effects {

  import flash.display.BitmapData;
  import flash.geom.Rectangle;

  import frocessing.color.ColorHSV;
  import jp.nya.project.particle.Dot;

  public class EmitLight {
    // プロパティ
    private var canvas:BitmapData;
    private var rect:Rectangle;
    private var launcher:Dot;
    private static var deceleration:Number = 0.1;
    private var color:ColorHSV;

    // コンストラクタ
    public function EmitLight(c:BitmapData) {
      canvas = c;
      rect = canvas.rect;
      init();
    }

    // メソッド
    private function init():void {
      color = new ColorHSV(0, 0.4);
    }
    public function create(max:uint):void {
      for (var n:uint = 0; n < max; n++) {
        var px:Number = Math.random()*rect.width;
        var py:Number = rect.height - Math.random()*5;
        var energy:Number = Math.random() + 0.5;
        var dot:Dot = new Dot(px, py, energy);
        color.h = Math.random()*360;
        dot.rgb = color.value;
      }
    }
    public function emit():void {
      for (var n:uint = 0; n < dots.length; n++) {
        dot.energy -= deceleration;
        canvas.setPixel(dot.x, dot.y, dot.rgb);
        if (dot.energy < 0) {
          dots.splice(n, 1);
          dot = null;
        }
      }
    }

  }

}

Fireworks.as (jp.nya.project.effects.Fireworks.as)
package jp.nya.project.effects {

  import flash.events.EventDispatcher;
  import flash.display.BitmapData;
  import flash.geom.Rectangle;
  import flash.geom.Point;
  import flash.events.Event;

  import frocessing.color.ColorHSV;
  import jp.nya.project.geom.Bresenham;
  import jp.nya.project.particle.Dot;


  public class Fireworks extends EventDispatcher {
    // プロパティ
    public var id:uint;
    private var sky:BitmapData;
    private var rect:Rectangle;
    private var dots:Array;
    private var dots:Array;
    private static var speed:Number = 10;
    private static var deceleration:Number = 0.95;
    private static var gravity:Number = 0.05;
    private var color:ColorHSV;
    private static var length:Number = 2;
    private var manager:Bresenham;
    public var emit:Function;
    private var se:SoundEffect;
    public static const COMPLETE:String = Event.COMPLETE;

    // コンストラクタ
    public function Fireworks(s:BitmapData) {
      sky = s;
      rect = sky.rect;
      init();
    }

    // メソッド
    private function init():void {
      dots = new Array();
      dots = new Array();
      color = new ColorHSV(0, 0.4);
      manager = new Bresenham(sky);
      emit = ready;
    }
    private function ready():void {
    }
    public function create():void {
      var px:Number = (0.2 + Math.random()*0.6)*rect.width;
      var energy:Number = 1 + Math.random()*0.05;
      launcher = new Dot(px, rect.height, energy);
      launcher.vy = - speed*launcher.energy;
      color.h = 60;
      launcher.rgb = color.value;
      launchers.push(launcher);
      emit = launch;
    }
    private function launch():void {
      launcher.vy += gravity;
      launcher.y += launcher.vy;
      sky.setPixel(launcher.x, launcher.y, launcher.rgb);
      if (Math.abs(launcher.vy) < 9) {
        explode(200, new Point(launcher.x, launcher.y), launcher.rgb);
        launchers.splice(n, 1);
        launcher = null;
      }
    }
    private function explode(max:uint, point:Point, rgb:uint):void {
      for (var n:uint = 0; n < max; n++) {
        var energy:Number = Math.random()*5;
        var angle:Number = Math.random()*360;
        var dot:Dot = new Dot(point.x, point.y, energy, angle);
        dot.velocity = Math.random()*5;
        dot.vx = Math.cos(dot.angle*Math.PI/180)*dot.velocity;
        dot.vy = Math.sin(dot.angle*Math.PI/180)*dot.velocity;
        dot.px = dot.x;
        dot.py = dot.y;
        dot.rgb = rgb;
        dots.push(dot);
      }
      emit = spread;
    }
    private function spread():void {
      for (var n:uint = 0; n < dots.length; n++) {
        var dot:Dot = dots[n];
        dot.vx *= deceleration;
        dot.vy *= deceleration;
        dot.vy += gravity;
        dot.x += dot.vx;
        dot.y += dot.vy;
        dot.energy *= deceleration;
        var x0:int = dot.x;
        var y0:int = dot.y;
        var x1:int = dot.x - (dot.x - dot.px)*length;
        var y1:int = dot.y - (dot.y - dot.py)*length;
        manager.draw(x0, y0, x1, y1, dot.rgb, 1);
        dot.px = dot.x;
        dot.py = dot.y;
        if (dot.energy < 0.05) {
          dots.splice(n, 1);
          dot = null;
          if (dots.length < 1) {
            dispatchEvent(new Event(Fireworks.COMPLETE));
          }
        }
      }
    }

  }

}

Bresenham.as (jp.nya.project.geom.Bresenham.as)
:banana: [AS3.0] ドットの光 (3) 参照。

Dot.as (jp.nya.project.particle.Dot.as)
package jp.nya.project.particle {

  public class Dot {
    // プロパティ
    public var x:Number = 0;
    public var y:Number = 0;
    public var vx:Number = 0;
    public var vy:Number = 0;
    public var px:Number = 0;
    public var py:Number = 0;
    public var energy:Number = 1;
    public var angle:Number = 0;
    public var velocity:Number = 1;
    public var rgb:uint = 0xFFFFFF;

    // コンストラクタ
    public function Dot(_x:Number, _y:Number, e:Number = 1, a:Number = 0) {
      cx = _x;
      cy = _y;
      energy = e;
      angle = a;
    }

    // メソッド

  }

}

Main.as
package {

  import flash.display.Sprite;
  import flash.geom.Rectangle;
  import flash.events.MouseEvent;
  import jp.nya.project.effects.DotLight;
  import jp.nya.project.controls.Btn;


  [SWF(backgroundColor="#000000", width="600", height="400", frameRate="30")]

  public class Main extends Sprite {
    // プロパティ
    private var light:DotLight;
    private var launchBtn:Btn;

    // コンストラクタ
    public function Main() {
      init();
    }

    // メソッド
    private function init():void {
      light = new DotLight(new Rectangle(0, 0, 600, 360));
      addChild(light);
      launchBtn = new Btn();
      addChild(launchBtn);
      launchBtn.x = 300;
      launchBtn.y = 380;
      launchBtn.init({label: "launch", width: 80, type: 2});
      launchBtn.addEventListener(MouseEvent.CLICK, launch, false, 0, true);
    }
    private function launch(evt:MouseEvent):void {
      light.launch();
    }

  }

}

Xcode + Flex 2 SDK + Terminal
$ mxmlc Main.as
とする。