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;
}
}