実験中:反応拡散×STG
反応拡散系をSTGに組み込めるか確認するための実験コード。
クリックで弾を発射。Shiftを押しながらマウスを動かすと連射。
/**
* Copyright o_healer ( http://wonderfl.net/user/o_healer )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/ojot
*/
/*
「反応拡散もどきをSTGに応用する実験」
概要
・弾で反応拡散を消すとどうなるのかの確認コード。
動作説明
・マウスで弾を発射し、それが当たると周囲を消す
*/
package {
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import flash.net.*;
import flash.system.*;
import flash.text.*;
import flash.media.*;
[SWF(width="465", height="465", frameRate="30", backgroundColor="0x000000")]
public class GameMain extends Sprite {
//==Const==
//サイズ
static public const SCL:int = 2;//4;//大きくすると荒くなる(高速化される)
static public const BMD_W:int = 465/SCL;//100;
static public const BMD_H:int = BMD_W/2;
//速度
static public const SPEED:int = 1;//試行回数(何倍速で実行するか)
//Utility
static public const BMD_RECT:Rectangle = new Rectangle(0,0,BMD_W,BMD_H);
static public const POS_ZERO:Point = new Point(0,0);
/*
//拡散反応もどき:乱数バージョン
//Alphaが大きいと離れた位置に自然発生が起こり、小さいと四角い移動パターンになる
//Betaが大きいと広がりやすく、小さいと広がりにくい
//再現のため、乱数に桁数制限を入れてみる
static public const Alpha:Number = 1;//1.0 - 4.0*int(Math.random()*100)/100;//1.0~-3.0:実際には2.1~-5くらいまでOK
//閾値
static public const A:Number = 5;
//上下
static public const B:Number = 2 + Alpha;
static public const D:Number = -0.1 - Alpha;
//斜め
static public const C:Number = 0.2;
static public const E:Number = -1.2 - 0.5*Alpha;
static public const F:Number = -1 + Alpha;
static public const Blur:Number = 4.5;//4.5;
//左下にデバッグ表示
static public const DEBUG_NUMBER_LEN:int = 3;//桁数表示制限
static public const DEBUG_STR:String =
"A:" + A.toFixed(DEBUG_NUMBER_LEN) + " " +
"B:" + B.toFixed(DEBUG_NUMBER_LEN) + " " +
"C:" + C.toFixed(DEBUG_NUMBER_LEN) + " " +
"D:" + D.toFixed(DEBUG_NUMBER_LEN) + " " +
"E:" + E.toFixed(DEBUG_NUMBER_LEN) + " " +
"F:" + F.toFixed(DEBUG_NUMBER_LEN);
/*/
static public const DEBUG_STR:String = "";
//*/
//==Var==
//表示用
public var m_BitmapData_View:BitmapData;
public var PALLETE_MAP:Array;
//拡散反応用
public var m_BitmapData_Data:BitmapData;
public var m_BitmapData_Mask_Before:BitmapData;
public var m_BitmapData_Mask_After:BitmapData;
//弾管理用
public var m_Layer_Bullet:Sprite = new Sprite();
//テキスト
public var m_Text:TextField = new TextField();
//==Function==
//Init
public function GameMain():void {
//表示用
{
//画像
{
m_BitmapData_View = new BitmapData(BMD_W, BMD_H, false, 0x000000);
var bmp_view:Bitmap = new Bitmap(m_BitmapData_View);
bmp_view.scaleX = SCL;
bmp_view.scaleY = SCL;
addChild(bmp_view);
}
//Palette
{
const COLOR_00:uint = 0x111111;
const COLOR_FF:uint = 0xCCCC33;
const COLOR_00_R:uint = (COLOR_00 >> 16) & 0xFF;
const COLOR_00_G:uint = (COLOR_00 >> 8) & 0xFF;
const COLOR_00_B:uint = (COLOR_00 >> 0) & 0xFF;
const COLOR_FF_R:uint = (COLOR_FF >> 16) & 0xFF;
const COLOR_FF_G:uint = (COLOR_FF >> 8) & 0xFF;
const COLOR_FF_B:uint = (COLOR_FF >> 0) & 0xFF;
const Lerp:Function = function(in_Src:uint, in_Dst:uint, in_Ratio:Number):uint{
return (in_Src * (1-in_Ratio)) + (in_Dst * in_Ratio);
};
PALLETE_MAP = new Array(256);
for(var i:int = 0; i < 256; i++){
var ratio:Number = i / (255.0);
ratio = 0.5 - 0.5*Math.cos(Math.PI*ratio);//色をややくっきり分けてみる
ratio = 0.5 - 0.5*Math.cos(Math.PI*ratio);//さらにくっきり
ratio = 0.5 - 0.5*Math.cos(Math.PI*ratio);//さらにくっきり
var r:uint = Lerp(COLOR_00_R, COLOR_FF_R, ratio);
var g:uint = Lerp(COLOR_00_G, COLOR_FF_G, ratio);
var b:uint = Lerp(COLOR_00_B, COLOR_FF_B, ratio);
PALLETE_MAP[i] = (r << 16) | (g << 8) | (b << 0);
}
}
}
//拡散反応用
{
//生成
{
m_BitmapData_Data = new BitmapData(BMD_W, BMD_H, false, 0x000000);
m_BitmapData_Mask_Before = new BitmapData(BMD_W, BMD_H, false, 0x000000);
m_BitmapData_Mask_After = new BitmapData(BMD_W, BMD_H, false, 0x000000);
}
//初期値設定
{
/*
//パーリンノイズ
m_BitmapData_Data.perlinNoise(BMD_W, BMD_H, 2, Math.random()*100, false, true, BitmapDataChannel.BLUE);
//*/
/*
//完全ランダム
m_BitmapData_Data.noise(Math.random()*100, 0x00,0xFF, BitmapDataChannel.BLUE);
//*/
//*
//中央に四角
m_BitmapData_Data.fillRect(new Rectangle(BMD_W*3/8, BMD_H*3/8, BMD_W/4, BMD_H/4), 0x0000FF);
//*/
/*
//中央に四角
m_BitmapData_Data.fillRect(new Rectangle(BMD_W/2-1, BMD_H/2-1, 2, 2), 0x0000FF);
//*/
}
{//m_BitmapData_Mask_Before
//移動させたくない部分にFFを描いてマスク
var mask_shape:Shape = new Shape();
var mask_g:Graphics = mask_shape.graphics;
mask_g.lineStyle(0,0,0);
/*
//左上隅
m_BitmapData_Mask_Before.fillRect(new Rectangle(0, 0, BMD_W/5, BMD_H/5), 0x0000FF);
//*/
//*
//円
mask_g.beginFill(0x000000, 1.0);
mask_g.drawCircle(BMD_W/2, BMD_H/2, BMD_H/2);
mask_g.endFill();
m_BitmapData_Mask_Before.fillRect(m_BitmapData_Mask_Before.rect, 0x0000FF);
m_BitmapData_Mask_Before.draw(mask_shape);
//*/
}
{//m_BitmapData_Mask_After
//上のやつを足してこいつを引くが、その際に上で描いたやつが少し拡散するので、引く際も少し拡散しておく
const Filter_Blur:BlurFilter = new BlurFilter(2,2);
m_BitmapData_Mask_After.applyFilter(m_BitmapData_Mask_Before, m_BitmapData_Mask_Before.rect, POS_ZERO, Filter_Blur);
}
}
//Mouse
{
addEventListener(
Event.ADDED_TO_STAGE,
function(e:Event):void{
stage.addEventListener(
MouseEvent.MOUSE_DOWN,
function(event:MouseEvent):void{
//弾発射
m_Layer_Bullet.addChild(new Bullet(mouseX, mouseY, m_BitmapData_Data));
}
);
stage.addEventListener(
MouseEvent.MOUSE_MOVE,
function(event:MouseEvent):void{
//弾発射
if(event.buttonDown && event.shiftKey){//Shiftを押してる間は連射
m_Layer_Bullet.addChild(new Bullet(mouseX, mouseY, m_BitmapData_Data));
}
}
);
}
);
}
//Bullet
{
addChild(m_Layer_Bullet);
}
//Text
{
m_Text.selectable = false;
m_Text.autoSize = TextFieldAutoSize.LEFT;
m_Text.defaultTextFormat = new TextFormat('Verdana', 12, 0x00FFFF, true);
m_Text.text = DEBUG_STR;
m_Text.filters = [new GlowFilter(0x000000, 1.0, 4,4, 255)];
m_Text.x = 0;
m_Text.y = 465 - 24;
addChild(m_Text);
}
//Update
{
addEventListener(Event.ENTER_FRAME, Update);
}
}
//Update
public function Update(e:Event=null):void{
//var DeltaTime:Number = 1.0 / stage.frameRate;
//弾管理
{
var num:int = m_Layer_Bullet.numChildren;
for(i = 0; i < num; i++){
//
var obj:Bullet = m_Layer_Bullet.getChildAt(i) as Bullet;
//更新
obj.Update();
//Kill(removeChild)があった時用の対応
if(obj.parent == null){//登録が解除された
num -= 1;//更新
i--;//相殺
continue;
}
}
}
//拡散反応処理
for(var i:int = 0; i < SPEED; i++){
Update_ReactionDiffusion();
}
//結果を可視化
Redraw();
}
//Update:拡散反応(もどき)
public function Update_ReactionDiffusion():void{
//ライフゲーム相当
//基本的な考え方
//・隣接方向には拡大しようとする(中心に近い部分はプラス)
//・まわりを全て囲まれたら消えようとする(配列の値を全て合計したらマイナス)
/*
//ノーマル(曲がろうとする直線メイン、分離あり)
const A:Number = 5;
const B:Number = 1;
const C:Number = 0.5;
const D:Number = -1;
const E:Number = -0.8;
const F:Number = 0;
const Blur:Number = 5.0;
//*/
/*
//やや分離ありの直角メイン
const A:Number = 5.82;
const B:Number = 1;
const C:Number = 0.2;
const D:Number = -1;
const E:Number = -0.71;
const F:Number = 0;
const Blur:Number = 5.0;
//*/
/*
//分離あり
const A:Number = 5.82;
const B:Number = 1.1;
const C:Number = 0.1;
const D:Number = -0.88;
const E:Number = -0.80;
const F:Number = 0;
const Blur:Number = 5.0;
//*/
//*
//分離・合体
const A:Number = 5.82;
const B:Number = 2.2;
const C:Number = 0.2;
const D:Number = -0.1;
const E:Number = -1.2;
const F:Number = -1.25;
const Blur:Number = 4.5;
//*/
/*
//分離・合体2
const A:Number = 5.82;
const B:Number = 1.692;
const C:Number = 0.2;
const D:Number = 0.208;
const E:Number = 1.046;
const F:Number = -1.303;
const Blur:Number = 4.5;
//*/
/*
//遠隔発生
const A:Number = 5.82;
const B:Number = 4.0;
const C:Number = 0.2;
const D:Number = -2.1;
const E:Number = -2.2;
const F:Number = 1.0;
const Blur:Number = 4.5;
//*/
/*
//四角
const A:Number = 5.82;
const B:Number = -2.0;
const C:Number = 0.2;
const D:Number = 3.9;
const E:Number = 0.8;
const F:Number = -5.0;
const Blur:Number = 4.5;
//*/
/*
//振動は残るが、反応拡散系っぽい挙動を示す
const A:Number = 16.5;
const B:Number = 1;
const C:Number = -5;
const Blur:Number = 4.1;
//*/
/*
//序盤だけ振動するが、後半は安定
const A:Number = 16.7;//~16.99
const B:Number = 1;
const C:Number = -5;
const Blur:Number = 4.0;
//*/
/*
//枠のまま広がる
const A:Number = 10.7;//~10.7
const B:Number = 1;
const C:Number = -3.5;
const Blur:Number = 4.0;
//*/
/*
//
const A:Number = 6.7;
const B:Number = 1;
const C:Number = -2.5;
const Blur:Number = 4.0;
//*/
/*
//
const A:Number = 8.7;//~16.99
const B:Number = 3;
const C:Number = -5;
const Blur:Number = 4.0;
//*/
//Mask : Before
m_BitmapData_Data.draw(m_BitmapData_Mask_Before, null, null, BlendMode.ADD);
const filter_conv:ConvolutionFilter = new ConvolutionFilter(
/*
3,3,
[
C, B, C,
B, A, B,
C, B, C,
]
/*/
5,5,
[
F, E, D, E, F,
E, C, B, C, E,
D, B, A, B, D,
E, C, B, C, E,
F, E, D, E, F,
],
1, 0, true,
false, 0x0000FF, 1.0//画面外はFFにしておき、避けるようにする
//*/
);
m_BitmapData_Data.applyFilter(m_BitmapData_Data, BMD_RECT, POS_ZERO, filter_conv);
//拡散
const filter_blur:BlurFilter = new BlurFilter(Blur, Blur);
m_BitmapData_Data.applyFilter(m_BitmapData_Data, BMD_RECT, POS_ZERO, filter_blur);
//Mask : After
m_BitmapData_Data.draw(m_BitmapData_Mask_After, null, null, BlendMode.SUBTRACT);
}
//Redraw
public function Redraw():void{
//可視化
{
//m_BitmapData_Dataの可視化(Src側に今回の結果がフィードバックされているものとする)
m_BitmapData_View.paletteMap(m_BitmapData_Data, BMD_RECT, POS_ZERO, null, null, PALLETE_MAP);
}
}
}
}
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import flash.net.*;
import flash.system.*;
import flash.text.*;
class Bullet extends Sprite
{
static public const BOMB_RAD:int = 8;//16;
static public var BOMB_SPRITE:Sprite;
static public var BOMB_SHAPE:Shape;
public var m_BitmapData_Nrm:BitmapData;
public function Bullet(in_X:int, in_Y:int, in_BitmapData_Nrm:BitmapData){
//Init Static
{
if(BOMB_SPRITE == null){
BOMB_SPRITE = new Sprite();
{
BOMB_SHAPE = new Shape();
var g:Graphics = BOMB_SHAPE.graphics;
g.lineStyle(0,0,0);
g.beginFill(0x000000, 1.0);
g.drawCircle(0,0, BOMB_RAD);
g.endFill();
BOMB_SPRITE.addChild(BOMB_SHAPE);
}
}
}
//Param
{
this.x = in_X;
this.y = in_Y;
m_BitmapData_Nrm = in_BitmapData_Nrm;
}
//Graphic
{
var shape:Shape = new Shape();
g = shape.graphics;
g.lineStyle(0,0,0);
g.beginFill(0xFFFFFF, 1.0);
g.drawCircle(0,0, 4);
g.endFill();
addChild(shape);
}
}
public function Update(e:Event=null):void{
//Move
{
this.y -= 5;
}
//Check
{
var index_x:int = this.x / GameMain.SCL;
var index_y:int = this.y / GameMain.SCL;
if(m_BitmapData_Nrm.rect.contains(index_x, index_y)){
var color:uint = m_BitmapData_Nrm.getPixel(index_x, index_y);
if((color & 0xFF) >= 0x40){
//Vanish
BOMB_SHAPE.x = index_x; BOMB_SHAPE.y = index_y;
m_BitmapData_Nrm.draw(BOMB_SPRITE);
//Kill
parent.removeChild(this);
}
}
}
}
}