In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Dot Poison Effect(ドットの毒エフェクト)

drawCircleで描写した円をドットに変換し、それを利用してファミコン風の毒エフェクトを作成しました。
/**
 * Copyright TTI ( http://wonderfl.net/user/TTI )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/sS1B
 */

/**
* drawCircleで描写した円をドットに変換し、それを利用してファミコン風の毒エフェクトを作成しました。
* クラスの簡単な説明は下記の通り。
*
* EffectPoisonクラス・・・インターフェースの作成、配置及び、エフェクトボタンを押した際の処理(SetDotPoisonクラスを実行)
* SetDotPoisonクラス・・・毒エフェクト作成管理用クラス。毒の数だけPoisonクラスを実行し毒の玉を作成。
* Poisonクラス・・・毒の玉用クラス。Bombクラスで描写した円をCreateDotBmpクラスへ渡してドット風に変換。
* CreateDotBmpクラス・・・オブジェクトをドット風に変換。
* NormalBtnクラス・・・ボタン作成用。
*/

package 
{
    import flash.display.*;
    import flash.events.*;
    import flash.text.*;
    import flash.net.*;
    import flash.system.Security;
    
    [SWF(backgroundColor = 0x000000, width = 465, height = 465, frameRate = 30)]
    
    /**
    * インターフェースの配置及び、エフェクトボタンを押した際の処理(SetDotPoisonクラスを実行)
    */
    public class EffectPoison extends Sprite
    {
        private var num:int = 10; //初期毒の数
        private var size:int = 4; //初期ドット値
        private var radius:int = 12; //初期毒の半径
        private var speedY:int = 2; //初期毒の移動スピード
        private var incidence:int = 30; //毒の散らばる範囲
        private var valueMaxArr:Array = [40, 20, 40, 5, 99]; //毒の数、ドットのサイズ、毒の半径、移動距離、範囲の最大値
        private var valueMinArr:Array = [1, 1, 10, 0, 0]; //毒の数、ドットのサイズ、毒の半径、移動距離、範囲の最小値
        private var tfArr:Array = []; //値入力テキストフィールドを管理する配列
        private var poison:SetDotPoison;//毒エフェクト
        private var effectBtn:NormalBtn; //エフェクトをかけるボタン
        private var loader:Loader; //キャラクター画像
        
        public function EffectPoison()
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        public function init(e:Event=null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            
            //ステージ初期設定-------------------------------------
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            stage.quality = StageQuality.BEST;
            
            
            //左部のンターフェースを作成-------------------------------------
            this.graphics.beginFill(0x000000, 1);
            this.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
            this.graphics.endFill();
            
            var tfBg:Sprite = new Sprite();
            tfBg.graphics.beginFill(0x333333, 1);
            tfBg.graphics.drawRect(0, 0, 220, stage.stageHeight);
            stage.addChild(tfBg);
            
            var txtArr:Array = [
                "毒の数(" + String(valueMinArr[0]) + "~" + String(valueMaxArr[0]) + "を入力)",
                "ドットのサイズ(" + String(valueMinArr[1]) + "~" + String(valueMaxArr[1]) + "を入力)",
                "毒の半径(" + String(valueMinArr[2]) + "~" + String(valueMaxArr[2]) + "を入力)",
                "Y座標の移動距離(" + String(valueMinArr[3]) + "~" + String(valueMaxArr[3]) + "を入力)",
                "毒の表示範囲(" + String(valueMinArr[4]) + "~" + String(valueMaxArr[4]) + "を入力)"];
            var baseValueArr:Array = [num, size, radius, speedY, incidence];
            var tfm1:TextFormat = new TextFormat(null, 11, 0xffffff);
            var tfm2:TextFormat = new TextFormat(null, 12, 0x333333);
            tfm2.align = TextFormatAlign.CENTER;
            
            for (var i:int=0; i<5; i++)
            {
                //入力説明テキスト
                var tf_txt:TextField = new TextField();
                stage.addChild(tf_txt);
                tf_txt.autoSize = TextFieldAutoSize.LEFT;
                tf_txt.text = txtArr[i];
                tf_txt.x = 20;
                tf_txt.y = 20 + 30 * i;
                tf_txt.defaultTextFormat = tfm1;
                tf_txt.setTextFormat(tfm1);
                
                //入力欄
                var tf_input:TextField = new TextField();
                tfArr.push(tf_input);
                stage.addChild(tf_input);
                tf_input.border = true;
                tf_input.background = true;
                tf_input.backgroundColor = 0xffffff;
                tf_input.maxChars = 2;
                tf_input.restrict = "0-9";
                tf_input.type = TextFieldType.INPUT;
                tf_input.text = String(baseValueArr[i]);
                tf_input.width = 30;
                tf_input.height = 20;
                tf_input.x = 170;
                tf_input.y = tf_txt.y - 2;
                tf_input.wordWrap = true;
                tf_input.defaultTextFormat = tfm2;
                tf_input.setTextFormat(tfm2);
            }
            
            //エフェクトボタン
            effectBtn = new NormalBtn(140, 20, "エフェクトをかける");
            stage.addChild(effectBtn);
            effectBtn.x = 20;
            effectBtn.y = tfArr[tfArr.length - 1].y + 40;
            effectBtn.addEventListener(MouseEvent.CLICK, btnEventHandler);
            
            
            //キャラクター画像の読み込み-------------------------------------
            
            //画像のURL
            var url:String = "http://wonderfl.net/static/tmp/related_images/ba79c6711cfa6458f6eb5a79b314704bdfc5ca87m";
            
            //画像をロード
            var urlReq:URLRequest = new URLRequest(url);
            loader = new Loader();
            loader.load(urlReq);
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onComplete);
            stage.addChild(loader);
            loader.x = 275;
            loader.y = stage.stageHeight - 280;
        }
        /**
         * キャラクター画像のロード完了時の処理
         * @param    $e
         */
        private function onComplete($e:Event):void
        {
            loader.width = 142;
            loader.height = 142;
            loader.y = int((stage.stageHeight - loader.height) * 0.5);
        }
        
        /**
         * エフェクトボタンを押した際の処理
         * @param    $e
         */
        private function btnEventHandler($e:MouseEvent):void
        {
            //入力された各パラメータのチェック(範囲外の場合は調整)
            for (var i:int=0; i<5; i++)
            {
                var value:int = int(tfArr[i].text);
                if (value < valueMinArr[i]) value = valueMinArr[i];
                else if (value > valueMaxArr[i]) value = valueMaxArr[i];
                tfArr[i].text = String(value);
                if (i == 0) num = value;
                else if (i == 1) size = value;
                else if (i == 2) radius = value;
                else if (i == 3) speedY = value;
                else if (i == 4) incidence = value;
            }
            
            //エフェクトの作成
            poison = new SetDotPoison(num, radius, size, speedY, incidence);
            poison.addEventListener(SetDotPoison.HIDE, removeEffect);
            stage.addChild(poison);
            poison.x = loader.x + int(loader.width * 0.5);
            poison.y = loader.y + int(loader.height * 0.5) + 20;
            
            effectBtn.setEnabled(false); //ボタンを無効にする
        }
        
        /**
         * エフェクトが終了するとエフェクトを削除
         * @param    $e
         */
        private function removeEffect($e:Event):void
        {
            stage.removeChild(poison);
            effectBtn.setEnabled(true); //ボタンを有効にする
        }
    }
}



//-----------------------------------
// 毒エフェクト作成用クラス
//-----------------------------------
import flash.display.*;
import flash.events.*;
import flash.utils.Timer;
class SetDotPoison extends Sprite 
{
    public static const HIDE:String = "hide";
    private var  _num:int //毒の数
    private var  _radius:Number //毒の基本半径
    private var  _size:int //1ドットのピクセル数
    private var  _speedY:int //毒の移動スピード
    private var  _incidence:int //毒の表示範囲
    private var hideCnt:int = 0; //毒の表示終了をカウント
    private var poisonArr:Array; //毒を管理する配列
    private var springCntMax:int = 3; //毒のバネ運動の回数
    
    /**
     * 毒エフェクト作成用クラス
     * @param    $num 毒の数
     * @param    $radius 毒の半径
     * @param    $size 1ドットのサイズ
     * @param    $speedY 毒の移動スピード
     * @param    $incidence 毒の表示範囲
     */
    public function SetDotPoison($num:int, $radius:Number, $size:int, $speedY:int, $incidence:int):void 
    {
        _num = $num;
        _radius = $radius;
        _size = $size;
        _speedY = $speedY;
        _incidence = $incidence;
        
        if (stage) init();
        else addEventListener(Event.ADDED_TO_STAGE, init);
        addEventListener(Event.REMOVED_FROM_STAGE, destroy );
    }
    
    private function init(e:Event = null):void 
    {
        removeEventListener(Event.ADDED_TO_STAGE, init);
        
        poisonArr = [];
        stage.addEventListener(Event.ENTER_FRAME, changeScale);
        
        //一定間隔ごとに毒の玉を作り出すcreate関数を_numの回数実行
        var timer:Timer = new Timer(50, _num);
        timer.addEventListener(TimerEvent.TIMER, create);
        timer.start();
    }
    
    /**
     * 毒の作成
     * @param    $e
     */
    private function create($e:TimerEvent):void 
    {
        var poison:Poison = new Poison(_num, _radius, _size);
        addChild(poison);
        poison.x = int(Math.random() * _incidence - _incidence * 0.5);
        poison.y = int(Math.random() * _incidence - _incidence * 0.5);
        poison.scaleX = poison.scaleY = 0;
        poisonArr.push(poison);
    }
    
    /**
     * 毒の拡大
     * @param    $e
     */
    private function changeScale($e:Event):void 
    {
        //毒の数だけ繰り返す
        for (var i:int=0; i<poisonArr.length; i++)
        {
            //バネの運動方向の切り替わり回数がspringCntMaxより少ない場合、バネ運動を行う
            if (poisonArr[i].springCnt < springCntMax)
            {
                poisonArr[i].vx += (1 - poisonArr[i].scaleX) * 0.2;
                poisonArr[i].scaleX += poisonArr[i].vx;
                poisonArr[i].scaleY = poisonArr[i].scaleX;
                poisonArr[i].y -= _speedY;
                poisonArr[i].vx *= 0.8;
                
                if (poisonArr[i].vx >= 0 && poisonArr[i].vx2 >= 0 || poisonArr[i].vx < 0 && poisonArr[i].vx2 < 0)
                {
                    //1フレーム前と運動の方向性は同じ
                }
                else
                {
                    //1フレーム前とvxの符号が違うため、運動の方向が変わったと判断しカウントを増やす
                    poisonArr[i].springCnt ++;
                }
                poisonArr[i].vx2 = poisonArr[i].vx; //比較が終わったので、今回のvxを一フレーム前のvxとして上書き
                
                //運動の方向がspringCntMax回変わると、バネ運動停止
                if (poisonArr[i].springCnt >= springCntMax)
                {
                    hide(poisonArr[i])
                }
            }
        }
    }
    
    /**
     * 毒のバネ運動が一定回数行われると、毒を非表示にする
     * @param    $sp
     */
    private function hide($sp:Sprite):void 
    {
        $sp.visible = false;
        checkHideCnt();
    }
    
    /**
     * 消えた毒の数をカウント。全て消えたらエフェクト自体を削除する合図を出す
     */
    private function checkHideCnt($e:Event = null):void 
    {
        hideCnt ++;
        if (hideCnt >= _num) dispatchEvent(new Event(HIDE));
    }
    
    /**
     * ステージからremoveされると全てのイベントリスナーと要素を削除。
     * @param    $e
     */
    private function destroy(e:Event):void
    {
        //イベントリスナーの削除
        removeEventListener(Event.REMOVED_FROM_STAGE, destroy );
        stage.removeEventListener(Event.ENTER_FRAME, changeScale);
        
        //要素の削除
        while (this.numChildren > 0){ this.removeChildAt(0);}
    }
}



//-----------------------------------
// 毒の玉用クラス
// (Bombクラスで毒を描写し、CreateDotBmpクラスでそれをドット風に変換)
//-----------------------------------
class Poison extends Sprite
{
    private var  _num:int //毒の数
    private var  _radius:Number //毒の基本半径
    private var  _size:int //1ドットのピクセル数
    private var _springCnt:int = 0; //バネ運動の方向が切り替わった回数
    private var _vx:Number = 0; //バネ運動のスピード
    private var _vx2:Number = 0; //1つ前のバネ運動のスピード(_vxと比較することで運動の方向が切り替わったか調べる)
    
    /**
     * 毒の玉用クラス
     * @param    $num 毒の数
     * @param    $radius 毒の基本半径
     * @param    $size 1ドットのピクセル数
     */
    public function Poison($num:int, $radius:Number, $size:int)
    {
        _num = $num;
        _radius = $radius;
        _size = $size;
        
        if (stage) init();
        else addEventListener(Event.ADDED_TO_STAGE, init);
        addEventListener(Event.REMOVED_FROM_STAGE, destroy );
    }
    
    private function init($e:Event=null)
    {
        //毒の玉作成
        var color:uint = 0xbe05f3;
        var poison:Bomb = new Bomb(color, _radius);
        addChild(poison);
        poison.visible = false;
        
        //作成した毒の玉をドットに変換
        var dotPoison:CreateDotBmp = new CreateDotBmp(poison, _size, true);
        addChild(dotPoison);
        dotPoison.x = int(dotPoison.width * -0.5);
        dotPoison.y = int(dotPoison.height * -0.5);
    }
    
    /**
     * 変数の受け渡し
     */
    public function get springCnt():int { return _springCnt; }
    public function set springCnt( value:int ):void { _springCnt = value; }
    public function get vx():Number { return _vx; }
    public function set vx( value:Number ):void { _vx = value; }
    public function get vx2():Number { return _vx2; }
    public function set vx2( value:Number ):void { _vx2 = value; }
    
    /**
     * ステージからremoveされると全てのイベントリスナーと要素を削除。
     * @param    $e
     */
    private function destroy(e:Event):void
    {
        //イベントリスナーの削除
        removeEventListener(Event.REMOVED_FROM_STAGE, destroy );
        
        //要素の削除
        while (this.numChildren > 0){ this.removeChildAt(0);}
    }
}



//-----------------------------------
// 円の描写用クラス
//-----------------------------------
import flash.display.*;
import flash.events.*;
class Bomb extends Sprite 
{
    private var  _color:uint; //円の色
    private var _radius:Number; //円の半径
    
    /**
     * 円の描写用クラス
     * @param    $color 円の色
     * @param    $radius 円の半径
     */
    public function Bomb($color:uint, $radius:Number=0):void 
    {
        _color = $color;
        _radius = $radius;
        
        if (stage) init();
        else addEventListener(Event.ADDED_TO_STAGE, init);
        addEventListener(Event.REMOVED_FROM_STAGE, destroy );
    }
    
    private function init(e:Event = null):void 
    {
        removeEventListener(Event.ADDED_TO_STAGE, init);
        
        //半径
        _radius = _radius + int(Math.random() * 6) - 3
        
        //基本となる円
        graphics.lineStyle(1, 0x000000, 0.5);
        graphics.beginFill(_color, 1)
        graphics.drawCircle(0, 0, _radius);
        graphics.endFill();
        
        //円の上に重なる白い光
        var light:Sprite = new Sprite();
        light.graphics.beginFill(0xffffff, 0.5)
        light.graphics.drawCircle(0, 0, _radius/2);
        light.graphics.endFill();
        addChild(light)
        light.x = -_radius/2 + 2;
        light.y = -_radius/2 + 2;
    }
    
    /**
     * ステージからremoveされると全てのイベントリスナーと要素を削除。
     * @param    $e
     */
    private function destroy(e:Event):void
    {
        //イベントリスナーの削除
        removeEventListener(Event.REMOVED_FROM_STAGE, destroy );
        
        //要素の削除
        while (this.numChildren > 0){ this.removeChildAt(0);}
    }
}



//-----------------------------------
// ドット画像作成用クラス
//-----------------------------------
import flash.display.*;
import flash.events.*;
import flash.geom.Matrix;
import flash.geom.Rectangle;
class CreateDotBmp extends Bitmap
{
   /**
     * ドット画像作成用クラス
     * @param    $obj 元の画像
     * @param    $size ドットのサイズ
     * @param    $centerFlag リターンするbitamapの基準点を真ん中にするか
     */
    public function CreateDotBmp($obj:DisplayObject, $size:int, $centerFlag:Boolean = false)
    {
        //受け取ったobjをbitmapdataにする
        var bmd : BitmapData = new BitmapData( $obj.width , $obj.height , true , 0x00000000);
        
        var moveX:int = ($centerFlag)? int($obj.width / 2) : 0;
        var moveY:int = ($centerFlag)? int($obj.height / 2) : 0;
        bmd.draw($obj, new Matrix(1,0,0,1,moveX,moveY));
        
        //縦横のドット数
        var dotNumW:int = Math.ceil($obj.width / $size);
        var dotNumH:int = Math.ceil($obj.height / $size);
        
        //ドットを書くbitmapdata
        var bmd2 : BitmapData = new BitmapData( $obj.width , $obj.height , true , 0x00000000);
        
        //ドットの描写
        bmd2.lock();
        for(var i:int=0; i<dotNumH; i++)
        {
            for(var k:int=0; k<dotNumW; k++)
            {
                //ドットとなる中心の色を取得
                var dotColor:uint = bmd.getPixel32(int($size * k + int($size / 2)), int($size * i + int($size / 2)));
                
                //ドット描写
                var rect:Rectangle = new Rectangle(int($size * k), int($size * i), $size, $size);
                bmd2.fillRect(rect , dotColor);
            }
        }
        bmd2.unlock();
        this.bitmapData = bmd2;
    }
    
    /**
     * ステージからremoveされると全てのイベントリスナーと要素を削除。
     * @param    $e
     */
    private function destroy(e:Event):void
    {
        //イベントリスナーの削除
        removeEventListener(Event.REMOVED_FROM_STAGE, destroy );
        
        //メモリ開放
        this.bitmapData.dispose();
    }
}



//-----------------------------------
// ボタン作成用クラス
//-----------------------------------
import flash.display.*;
import flash.text.*;
class NormalBtn extends Sprite
{
    public function NormalBtn($w:Number, $h:Number, $label:String):void
    {
        this.graphics.lineStyle(1, 0x000000, 1);
        this.graphics.beginFill(0xdddddd, 1);
        this.graphics.drawRect(0, 0, $w, $h);
        this.graphics.endFill();
        
        var tf:TextField = new TextField();
        addChild(tf);
        tf.text = $label;
        tf.autoSize = TextFieldAutoSize.LEFT;
        tf.x = int(($w - tf.width ) / 2);
        
        var cover:Sprite = new Sprite();
        cover.graphics.beginFill(0xffffff, 0);
        cover.graphics.drawRect(0, 0, $w, $h);
        cover.graphics.endFill();
        addChild(cover);
        
        this.buttonMode = true;
    }
    
    /**
     * ボタンの有効・無効を切り替え
     * @param    $flag true…有効 false…無効
     */
    public function setEnabled($flag:Boolean):void
    {
        this.mouseChildren = this.mouseEnabled = $flag;
        this.alpha = ($flag)? 1 : 0.3;
    }
}