家畜伝染病のシミュレーション
家畜伝染病のシミュレーション
左クリックで、殺処分
SHIFTキー+左クリックで、消毒薬を散布
消毒薬は一日毎に補充されます。感染拡大を食い止めてください
感染拡大を防ぐためには、初動の対処が必要不可欠
赤:発症
黄:潜伏期間
緑:健康
灰:殺処分
参考:口蹄疫と消毒薬
http://d.hatena.ne.jp/Yosyan/20100510
解説など:
http://game.g.hatena.ne.jp/Nao_u/20100512
//
// 家畜伝染病のシミュレーション
//
//
// 左クリックで、殺処分
// SHIFTキー+左クリックで、消毒薬を散布
//
// 消毒薬は一日毎に補充されます。感染拡大を食い止めてください
//
// 感染拡大を防ぐためには、初動の対処が必要不可欠
//
//
// 赤:発症
// 黄:潜伏期間
// 緑:健康
// 灰:殺処分
//
// 参考:口蹄疫と消毒薬
// http://d.hatena.ne.jp/Yosyan/20100510
//
// 解説など:
// http://game.g.hatena.ne.jp/Nao_u/20100512
package {
import flash.display.Sprite;
import flash.events.*;
[SWF(width="465", height="465", backgroundColor="0xFFFFFF", frameRate="5")]
public class FlashTest extends Sprite {
public function FlashTest() {
Main = this;
initialize();
stage.addEventListener(Event.ENTER_FRAME,update);
stage.addEventListener(MouseEvent.MOUSE_DOWN, viewClickEvent);
stage.addEventListener(KeyboardEvent.KEY_UP, keyCheckUp);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyCheckDown);
}
}
}
var kansen:int = 80; // 感染率(%)
var dokusei:int = 1; // 毒性の強さ
var senpuku:int = 2; // 潜伏期間
var hassyou:int = 70; // 発症時間
var meneki:int = 5; // 免疫期間
var OcrockLength:Number = 5; // 一時間の長さ
var DayLength:Number = OcrockLength*24; // 一日の長さ
var moveRate:Number = 0.25; // 移動の自由度
var kakuri:Number = 0;
var MoveRateAry:Array = new Array();
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.*
import flash.text.TextField;
import flash.geom.*;
import flash.utils.getTimer;
var Main:Sprite;
var SCREEN_W:Number = 465;
var SCREEN_H:Number = 465;
var View: Bitmap;
var BmpData: BitmapData;
var BgColor:int = 0x101010;
var WallColor:int = 0xf08080;
var WallColor2:int = 0x807070;
var ColGreen:int = 0x408040;
var ColYellow:int = 0xffff40;
var ColRed0:int = 0xff6060;
var ColRed1:int = 0xff4040;
var ColBlue:int = 0x2070a0;
var ColGray:int = 0x404040;
var BITMAP_W:int = 465;
var BITMAP_H:int = 384;
var AgentAry:Vector.<Agent> = new Vector.<Agent>;
var CarAry:Vector.<Car> = new Vector.<Car>;
var FarmAry:Vector.<Farm> = new Vector.<Farm>;
var DisinfectantAry:Vector.<Disinfectant> = new Vector.<Disinfectant>;
var Text0:TextField = new TextField();
var Text1:TextField = new TextField();
var Text2:TextField = new TextField();
var Time:int = 0;
var StateAry:Array = new Array();
var ResetButton:Button;
var KakuriButton:Button;
var Idou:TextField = new TextField();
var Kokkyou:TextField = new TextField();
var IdouType:int = 1;
var KokkyouType:int = 2;
var Syoudoku:int;
var SyoudokuPlus:Number;
var Tex:ProcTex;
var Month:int;
var Day:int;
var DaysTable:Array = [0, 31, 28, 31, 30, 31, 30, 31, 30, 31, 31, 30, 31];
function initialize():void{
MoveRateAry.push( 0.05 );
MoveRateAry.push( 0.25 );
MoveRateAry.push( 0.55 );
MoveRateAry.push( 0.85 );
BmpData = new BitmapData(BITMAP_W, BITMAP_H, false, 0xffffff);
View = new Bitmap(BmpData);
View.scaleX = 1.0;
View.scaleY = 1.0;
Main.addChild(View);
Tex = new ProcTex( BITMAP_W, BITMAP_H,BmpData );
Tex.Bmp.x = 0;
Tex.Bmp.y = 0;
Text0.x = 10;
Text0.y = 386;
Text0.defaultTextFormat = new TextFormat( "AXIS Std R", 13, 0, false );
Main.addChild(Text0);
Text1.x = 89;
Text1.y = 388;
Text1.width = 384;
Text1.defaultTextFormat = new TextFormat( "AXIS Std R", 10, 0, false );
Main.addChild(Text1);
Text2.x = 20;
Text2.y = 406;
Text2.defaultTextFormat = new TextFormat( "AXIS Std R", 13, 0, false );
Main.addChild(Text2);
reset();
createResetButton();
createKakuriButton();
}
function viewClickEvent(event:MouseEvent):void{
var mx:Number = Main.stage.mouseX;
var my:Number = Main.stage.mouseY;
if( KeyData & KEY_SHIFT ){
if( Syoudoku > 0 ){
Syoudoku--;
new Disinfectant( mx,my, 16, 128 );
}
}else{
killAgent(mx,my);
}
}
function createAgent():void{
new Farm( 35, 50, 50, 50, 20, 0.05 );
// new Farm( 35, 50, 50, 50, 80, 0.95 );
new Farm( 150, 50, 50, 50, 256, 0 );
new Farm( 250, 50, 70, 50, 14, 0.0 );
new Farm( 350, 50, 75, 45, 10, 0.0 );
new Farm( 30,110, 110, 60, 16, 0 );
new Farm( 190,110, 25, 25, 64, 0.0 );
new Farm( 290,110, 50,120, 50, 0.0 );
new Farm( 390,110, 50, 50, 127, 0 );
new Farm( 50,190, 40, 80, 16, 0 );
new Farm( 110,220, 30, 50, 160, 0 );
new Farm( 90,280, 50, 50, 40, 0 );
new Farm( 150,150, 80, 80, 128, 0.0 );
new Farm( 290,250, 150,60, 100, 0.01 );
new Farm( 150,260, 65, 30, 20, 0 );
new Farm( 270,320, 25, 40, 90, 0 );
new Farm( 220,250, 35, 80, 20, 0 );
new Farm( 20,300, 45, 50, 30, 0 );
new Farm( 235,160, 45, 20, 30, 0 );
new Farm( 380,190, 25, 30, 30, 0 );
new Farm( 310,345, 45, 18, 10, 0 );
new Farm( 395,340, 35, 18, 80, 0 );
for( var i:int=0; i<5; i++ ){
new Car( 0,50, 50,100 );
new Car( 100,0, 200,200 );
new Car( 100,100, 300,300 );
new Car( 100,100, 300,300 );
}
/* new Car( 0,0, 100,100 );
new Car( 0,0, 100,100 );
new Car( 0,0, 100,100 );
new Car( 0,0, 100,100 );
new Car( 0,0, 100,100 );
*/
}
function createKakuriButton():void{
KakuriButton = new Button(64, 18, 8, "人の移動 通常", 10);
KakuriButton.x = 468-120
KakuriButton.y = 468-52
KakuriButton.addEventListener(MouseEvent.CLICK,
function(event:MouseEvent):void{
if( kakuri == 0.0 ) {
KakuriButton.setLabel("人の移動 制限");
kakuri = 1.0;
}else{
KakuriButton.setLabel("人の移動 通常");
kakuri = 0.0;
}
}
);
Main.addChild(KakuriButton);
}
function reset():void{
AgentAry = new Vector.<Agent>;
CarAry = new Vector.<Car>;
FarmAry = new Vector.<Farm>;
DisinfectantAry = new Vector.<Disinfectant>;
Tex.clear();
clearBmp();
createAgent();
Month = 4;
Day = 20;
Time = 0;
Syoudoku = 1;
SyoudokuPlus = 1;
kakuri = 0.0;
// KakuriButton.setLabel("人の移動 通常");
}
function createResetButton():void{
ResetButton = new Button(64, 18, 8, "Reset", 16);
ResetButton.x = 468-120;
ResetButton.y = 468-22;
ResetButton.addEventListener(MouseEvent.CLICK,
function(event:MouseEvent):void{reset();Time=0;}
);
Main.addChild(ResetButton);
}
function updateTex():void{
Tex.draw();
}
function update(e :Event):void{
var num:int = 0;
for( var i:int=0; i<5; i++ ) StateAry[i] = 0;
for each( var agent:Agent in AgentAry ) { agent.update(); num++; }
for each( var car:Car in CarAry ) car.update();
for each( var dis:Disinfectant in DisinfectantAry ) dis.update();
clearBmp();
for each( dis in DisinfectantAry ) dis.draw();
for each( var farm:Farm in FarmAry ) farm.draw();
for each( agent in AgentAry ) agent.draw();
for each( var cr:Car in CarAry ) cr.draw();
updateTex();
Time++;
var ocrock:int = Time/OcrockLength;
if( ocrock == 24 ) {
ocrock = 0;
Time=0;
Day++;
Syoudoku += SyoudokuPlus;
SyoudokuPlus += 0.75;
}
if( Day > DaysTable[Month] ) {
Day = 1;
Month++;
if( Month == 13 ) Month = 1;
}
var n0:String = (StateAry[0]*10).toFixed(0);
var n1:String = (StateAry[1]*10).toFixed(0);
var n2:String = (StateAry[2]*10).toFixed(0);
// var n3:String = (StateAry[3]*10).toFixed(0);
var n4:String = (StateAry[4]*10).toFixed(0);
Text0.text = Month+"月"+ Day +"日 "+ocrock+"時";
Text1.htmlText =
"<font color='#006000'>健康</font>: "+n0+" " +
"<font color='#b0b000'>潜伏</font>: "+n1+" " +
"<font color='#b00000'>発症</font>: "+n2+" " +
"<font color='#303030'>殺処分</font>: "+n4+" " ;
Text2.text = "消毒薬:" + Syoudoku;
}
function darwWall( sx:int, sy:int, w:int, h:int, col:int ):void{
var ex:int = sx+w;
var ey:int = sy+h;
for( var x:int=sx; x<sx+w; x++){
BmpData.setPixel(x, sy, col);
BmpData.setPixel(x, ey, col);
}
for( var y:int=sy; y<sy+h; y++){
BmpData.setPixel(sx, y, col);
BmpData.setPixel(ex, y, col);
}
}
function darwCircle( sx:int, sy:int, r:int, col:int ):void{
var x:Number, y:Number;
for( var i:Number=0; i<3.14*2; i+=3.14/64 ){
x = sx + r*Math.sin(i);
y = sy + r*Math.cos(i);
BmpData.setPixel(x, y, col);
}
}
function clearBmp():void{
var col:int = 0xc0c0c0;
var x:int;
var y:int;
for( x=0; x<BITMAP_W; x++){
for( y=0; y<BITMAP_H; y++){
BmpData.setPixel(x, y, BgColor);
}
}
}
class Car{
public var X:Number;
public var Y:Number;
public var Sx:Number;
public var Sy:Number;
public var Ex:Number;
public var Ey:Number;
public var SpdX:Number;
public var SpdY:Number;
public var CountDown:int = 0;
public var Poison:Number = 0;
public function Car( x:Number, y:Number, ex:Number, ey:Number ){
do{
X = x + ex*Math.random();
Y = y + ey*Math.random();
} while( BmpData.getPixel(X, Y) != BgColor );
CarAry.push(this);
}
public function update():void{
{
var rate:Number = 1.5;
var nomove:Boolean = false;
if( kakuri == 1.0 ) { rate *= 0.1; Poison = 0; }
if( CountDown <= 0 ){
CountDown = 30;
var rad:Number = Math.random()*3.14*2;
SpdX = rate * Math.sin(rad);
SpdY = rate * Math.cos(rad);
}else{
CountDown--;
}
var bgCol:int = BmpData.getPixel(X+SpdX, Y+SpdY);
if( bgCol != WallColor )
{
X += SpdX;
Y += SpdY;
if( X < 2 ){ X = 2; SpdX*=-1; nomove = true; }
if( X > BITMAP_W-4 ){ X = BITMAP_W-4; SpdX*=-1; nomove = true; }
if( Y < 2 ){ Y = 2; SpdY*=-1; nomove = true; }
if( Y > BITMAP_H-4 ){ Y = BITMAP_H-4; SpdY*=-1;nomove = true; }
}else{
SpdX*=-1;
SpdY*=-1;
nomove = true;
}
if( nomove == true ) Poison *= 0.1;
}
var pow:Number = 0.5 * Tex.getPower(X, Y);
if( Poison < pow ) Poison = pow;
if( kakuri == 1.0 ) { Poison = 0; }
Tex.addPower( X, Y, Poison*0.2 );
Poison *= 0.99;
if( Poison > 1 ) Poison = 1;
if( Poison < 0 ) Poison = 0;
}
public function draw():void{
var col0:int, col1:int;
col1 = ColBlue;
BmpData.setPixel(X, Y, col1);
setPixel(X+1, Y, col1);
setPixel(X, Y+1, col1);
setPixel(X+1, Y+1, col1);
}
}
class Agent{
public var X:Number;
public var Y:Number;
public var Hp:int, HpMax:int;
public var Status:int = 0; // 0:健康 1:潜伏期間 2:発病
public var CountDown:int = 0;
public var Poison:Number = 0;
public function Agent( x:Number, y:Number, px:Number, py:Number, status:int ){
do{
X = x + px*Math.random();
Y = y + py*Math.random();
} while( BmpData.getPixel(X, Y) != BgColor );
Hp = 15000 + Math.random() * 25000;
AgentAry.push(this);
Status = status;
if( Status == 1 ){
Tex.addPower( X, Y, 0.7 );
Tex.addPower( X-3, Y, 0.7 );
Tex.addPower( X+3, Y, 0.7 );
Tex.addPower( X, Y+3, 0.7 );
Tex.addPower( X, Y-3, 0.7 );
}
}
public function update():void{
StateAry[Status]++;
if( Status != 4 ){
var sx:Number = moveRate * (Math.random()*5 - 2.5);
var sy:Number = moveRate * (Math.random()*5 - 2.5);
var bgCol:int = BmpData.getPixel(X+sx, Y+sy);
if( bgCol != WallColor && !(Status == 2 && KokkyouType == 1 && bgCol == WallColor2) ){
X += sx;
Y += sy;
if( X < 2 ) X = 2;
if( X > BITMAP_W-4 ) X = BITMAP_W-4;
if( Y < 2 ) Y = 2;
if( Y > BITMAP_H-4 ) Y = BITMAP_H-4;
}
}
if( Status == 0 ){
if( Hp < HpMax ) {
Hp+=3;
}
Poison += Tex.getPower(X+sx, Y+sy);
Poison -= 0.0005;
if( Poison < 0 ) Poison = 0;
if( Poison > 5.0 ){
if( Math.random()*100 < kansen ) { // 感染力
Status = 1;
CountDown = senpuku * DayLength; // 潜伏期間
}
}
}
if( Status == 1 ){
CountDown--;
if( CountDown <= 0 ) {
CountDown = hassyou * DayLength; // 発症時間
Status = 2;
Tex.addPower( X, Y, 0.5 );
}
}
if( Status == 2 ){
Tex.addPower( X, Y, 0.030 );
Hp-= dokusei * 10; // 毒性の強さ
CountDown--;
if( CountDown <= 0 ) {
CountDown = meneki * DayLength; // 免疫期間
Status = 3;
}
if( Hp <= 0 ) {
Status = 4;
}
}
if( Status == 3 ){
CountDown--;
if( CountDown <= 0 ) {
CountDown = 0; //
Status = 0;
}
}
}
public function getColYellowRatio():int{
var max:Number = senpuku * DayLength;
var ratio:Number = CountDown / max;
ratio = 1 - ratio;
ratio = ratio*ratio*ratio;
ratio = 1 - ratio;
var invRatio:Number = 1.0 - ratio;
var r:int = 0x40 * ratio + 0xff * invRatio;
var g:int = 0x80 * ratio + 0xff * invRatio;
var b:int = 0x40;
return (r<<16) + (g<<8) + (b);
}
public function draw():void{
var col0:int, col1:int;
switch( Status ){
case 0: col0 = col1 = ColGreen; break;
case 1: col0 = col1 = getColYellowRatio(); break;
case 2: col0 = ColRed0; col1 = ColRed1; break;
case 3: col0 = col1 = ColBlue; break;
case 4: col0 = col1 = ColGray; break;
}
BmpData.setPixel(X, Y, col0);
setPixel(X+1, Y, col1);
setPixel(X, Y+1, col1);
setPixel(X+1, Y+1, col1);
}
}
function setPixel( x:int, y:int, col:int):void{
if( BmpData.getPixel(x, y) == BgColor ){
BmpData.setPixel(x,y, col);
}
}
import flash.events.*;
import flash.utils.*;
import flash.text.*;
import flash.ui.Keyboard;
class InputArea {
public function InputArea( x:int, y:int, str:String, num:String, func:Function ){
var tx:TextField = new TextField();
tx.text = str;
tx.x = x;
tx.y = y;
Main.addChild(tx);
var textArea:InputTextArea = new InputTextArea(func);
textArea.x = 1 + x + str.length * 10;
textArea.y = y;
textArea.text = num;
Main.addChild(textArea);
}
}
class InputTextArea extends TextField {
public var Func:Function;
public var myTimer:Timer = new Timer(2, 1);
public function InputTextArea( func:Function ) {
border = true;
borderColor = 0xCCCCCC;
width = 24;
height = 16;
type = TextFieldType.INPUT;
restrict = "0-9";
Func = func;
var format:TextFormat = new TextFormat( "AXIS Std R", 12, 0, true );
format.align = "right";
defaultTextFormat = format;
addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
addEventListener(Event.CHANGE, function(e:Event):void{Func(text);});
myTimer.addEventListener(TimerEvent.TIMER, timerHandler);
addEventListener(FocusEvent.FOCUS_IN, function(e:Event):void{ myTimer.start(); });
}
private function timerHandler(e:Event):void {
setSelection(0, length);
}
private function keyDownHandler(event:KeyboardEvent):void {
if ( event.keyCode == Keyboard.ENTER ) {
var inputText:String = text;
Func(text);
dispatchEvent( new InputEvent( InputEvent.INPUT_ENTER, inputText ) );
}
}
}
flash.events.Event;
class InputEvent extends Event {
public static const INPUT_ENTER:String = "InputEvent.inputEnter";
private var _text:String = "";
public function InputEvent(type:String, text:String, bubbles:Boolean=false, cancelable:Boolean=false) {
super(type, bubbles, cancelable);
_text = text;
}
public override function clone():Event {
return new InputEvent(type, _text, bubbles, cancelable);
}
public override function toString():String {
return formatToString("InputEvent", "text", "type", "bubbles", "cancelable", "eventPhase");
}
public function get text():String { return _text; }
}
import flash.display.Sprite;
import flash.events.Event;
import flash.text.TextField;
import flash.geom.Matrix;
import flash.filters.ColorMatrixFilter;
import flash.filters.GlowFilter;
class Button extends Sprite{
private static const mono:ColorMatrixFilter = new ColorMatrixFilter([
1 / 3, 1 / 3, 1 / 3, 0, 10,
1 / 3, 1 / 3, 1 / 3, 0, 10,
1 / 3, 1 / 3, 1 / 3, 0, 10,
0, 0, 0, 1, 0
]);
private var _textField:TextField = new TextField();
private var _size:int;
private var _hover:Boolean = false;
public function get hover():Boolean{
return _hover;
}
public function set hover(value:Boolean):void{
if(_hover != value){
_hover = value;
filters = (_hover ? null : [mono]);
}
}
public function Button(W:Number, H:Number, R:Number, label:String = "", size:int = 11){
var matrix:Matrix = new Matrix();
matrix.createGradientBox(W, H, Math.PI / 2);
var bg:Sprite = new Sprite();
bg.graphics.beginGradientFill("linear", [0x8c99a4, 0xc5d4e1, 0xBAD2E8], [1, 1, 1],
[0, 120, 136], matrix);
bg.graphics.drawRoundRect(0, 0, W, H, R, R);
bg.graphics.endFill();
bg.filters = [new GlowFilter(0xFFFFBE, .5, 10, 10, 2, 1, true)];
addChild(bg);
var line:Sprite = new Sprite();
line.graphics.lineStyle(3, 0xBAD2E8);
line.graphics.drawRoundRect(0, 0, W, H, R, R);
addChild(line);
filters = [mono];
buttonMode = true;
mouseChildren = false;
if (label != ""){
_size = size;
_textField.selectable = false;
_textField.autoSize = "left";
_textField.htmlText = <font size={size} color="#4B4349">{label}</font>.toXMLString();
_textField.x = (W - _textField.width) / 2;
_textField.y = (H - _textField.height) / 2;
addChild(_textField);
}
addEventListener("rollOver", buttonRollOver);
addEventListener("rollOut", buttonRollOut);
addEventListener("removed", function(event:Event):void{
removeEventListener("rollOver", buttonRollOver);
removeEventListener("rollOut", buttonRollOut);
removeEventListener("removed", arguments.callee);
});
}
public function setLabel( label:String ):void{
_textField.htmlText = <font size={_size} color="#4B4349">{label}</font>.toXMLString();
}
protected function buttonRollOver(event:Event):void{
hover = true;
}
protected function buttonRollOut(event:Event):void{
hover = false;
}
}
// エージェントを殺す
function killAgent(mx:int, my:int):void{
var nearDist:int = 99999999, dist:int;
var dx:int, dy:int;
var delAgent :Agent = null;
for each( var agent:Agent in AgentAry ){
if( agent.Status == 4 ) continue;
dx = agent.X - mx;
dy = agent.Y - my;
dist = dx*dx+dy*dy;
if( dist < 4*3 && nearDist > dist ){
nearDist = dist;
delAgent = agent;
}
}
if( delAgent != null ){
delAgent.Status = 4;
}
}
// 消毒剤クラス
class Disinfectant{
public var Px:int;
public var Py:int;
public var Radius:int;
public var Life:int;
public var Count:int;
public function Disinfectant( x:int, y:int, radius:int, life:Number ){
Px = x;
Py = y;
Radius = radius;
Life = life;
DisinfectantAry.push(this);
}
public function update():void{
Life--;
if( Life < 0 ){
for(var i:int = 0; i < DisinfectantAry.length; i++){
if(DisinfectantAry[i] == this){
DisinfectantAry.splice(i,1);
}
}
}
Tex.delPower( Px, Py, Radius );
}
public function draw():void{
var col:int = Life;
darwCircle( Px, Py, Radius, col + (col<<8)+(col<<16) );
}
}
// 牧場クラス
class Farm{
public var Px:int;
public var Py:int;
public var Width:int;
public var Height:int;
public function Farm( x:int, y:int, w:int, h:int, num:int, ratio:Number ){
Px = x;
Py = y;
Width = w;
Height = h;
var agent:Agent;
var ratioNow:Number = 0.001;
var ratioAdd:Number = 1/num;
var status:int = 0;
for( var i:int=0; i<num; i++,ratioNow+=ratioAdd ){
if( ratio < ratioNow ) status = 0;
else status = 1;
agent = new Agent( x+1,y+1,w-2,h-2, status );
}
FarmAry.push(this);
}
public function draw():void{
darwWall( Px, Py, Width, Height, WallColor );
}
}
// テクスチャ生成クラス
class ProcTex{
public var BmpData:BitmapData;
public var BmpDataCopy:BitmapData;
public var TmpBmpData:BitmapData;
public var Bmp:Bitmap;
public var Width:int;
public var Height:int;
public var HeightBuf:Array;
public var HeightIdxDst:int;
public var HeightIdxSrc0:int;
public var BufWidth:int;
public var BufHeight:int;
public var PixelBufSize:int = 256;
public var PixelBuf:Vector.<int>;
public function ProcTex( w:int, h:int, useBmpData:BitmapData ){
Width = w;
Height = h;
BmpDataCopy = useBmpData
BmpData = new BitmapData(Width, Height, false, 0xffffff);
Bmp = new Bitmap(BmpData);
// Bmp.scaleX = 2.0;
// Bmp.scaleY = 2.0;
Main.addChild(Bmp);
// 波高バッファの生成
HeightBuf = new Array;
BufWidth = Width+2;
BufHeight = Height+2;
clear();
}
public function clear():void{
HeightBuf[0] = new Vector.<Number>;
HeightBuf[1] = new Vector.<Number>;
HeightBuf[2] = new Vector.<Number>;
for( var x:int=-1; x<Width+1; x++ ){
for( var y:int=-1; y<Height+1; y++ ){
var idx:int = (x+1) + (y+1)*BufWidth;
HeightBuf[0].push( 0 );
HeightBuf[1].push( 0 );
HeightBuf[2].push( 0 );
}
}
HeightIdxSrc0=0;
HeightIdxDst=1;
}
public function draw():void{
HeightIdxSrc0++;
HeightIdxDst++;
if( HeightIdxSrc0 > 1 ) HeightIdxSrc0 = 0;
if( HeightIdxDst > 1 ) HeightIdxDst = 0;
calcWave();
createBmp( HeightIdxDst );
}
// 水面に力を加える
public function addPower( px:int, py:int, pow:Number ):void{
var r:int = 6;
var buf:Vector.<Number> = HeightBuf[HeightIdxDst];
for( var lx:int=-r; lx<=r; lx++ ){
for( var ly:int=-r; ly<=r; ly++ ){
const d:Number = Math.sqrt(lx*lx+ly*ly);
if (d < r) {
var p:Number = Math.cos(Math.PI/2 * d/r);
var x:int = px + lx;
var y:int = py + ly;
if( x < 0 || x >= Width || y < 0 || y >= Height ) break;
var idx:int = (x+1) + (y+1)*BufWidth;
buf[idx] += pow * p;
if( buf[idx] < 0 ) buf[idx] = 0;
}
}
}
}
// 水面に力を加える
public function delPower( px:int, py:int, r:int ):void{
var rr:int = r*r;
var buf:Vector.<Number> = HeightBuf[HeightIdxDst];
for( var lx:int=-r; lx<=r; lx++ ){
for( var ly:int=-r; ly<=r; ly++ ){
const d:Number = lx*lx+ly*ly;
if (d < rr) {
var x:int = px + lx;
var y:int = py + ly;
if( x < 0 || x >= Width || y < 0 || y >= Height ) break;
var idx:int = (x+1) + (y+1)*BufWidth;
buf[idx] = 0;
}
}
}
}
public function getPower( x:int, y:int ):Number{
if( x < 0 || x >= Width || y < 0 || y >= Height ) return 0;
var idx:int = (x+1) + (y+1)*BufWidth;
var buf:Vector.<Number> = HeightBuf[HeightIdxDst];
return buf[idx];
}
// 水面画像の生成
public function createBmp( idx:int ):void{
var buf:Vector.<Number> = HeightBuf[HeightIdxDst];
var col:Number, colU:Number, colL:Number, vecX:Number, vecY:Number;
var idx:int, ix:int, iy:int;
var r:int, g:int, b:int, pixCol:int, add:int;
BmpData.lock();
for( var x:int=0; x<Width; x++ ){
for( var y:int=0; y<Height; y++ ){
idx = (x+1) + (y+1)*BufWidth;
col = buf[idx];
pixCol = BmpDataCopy.getPixel(x, y);
r = (pixCol&0x0000ff);
g = (pixCol&0x00ff00)>>8;
b = (pixCol&0xff0000)>>16;
add = col * 64;
if( add > 128 ) add = 128;
b += add;
if( b > 255 ) b = 255;
if( b < 0 ) b = 0;
pixCol = r + (g<<8) + (b<<16);
BmpData.setPixel(x, y, pixCol);//col);
}
}
BmpData.unlock();
}
// 波計算
public function calcWave():void{
var srcBuf0:Vector.<Number> = HeightBuf[HeightIdxSrc0];
var dstBuf:Vector.<Number> = HeightBuf[HeightIdxDst];
var idx:int, idxU:int, idxD:int, idxL:int, idxR:int;
for( var x:int=1; x<Width-6-1; x++ ){
for( var y:int=1; y<Height-6-1; y++ ){
idx = (x+2) + (y+2)*BufWidth;
idxU = (x+2) + (y )*BufWidth;
idxD = (x+2) + (y+4)*BufWidth;
idxL = (x ) + (y+2)*BufWidth;
idxR = (x+4) + (y+2)*BufWidth;
dstBuf[idx] = 0.20 * (srcBuf0[idx] + srcBuf0[idxU] + srcBuf0[idxD] + srcBuf0[idxL] + srcBuf0[idxR]);
dstBuf[idx] *= 0.999;
}
}
}
}
var KEY_UP:int = 0x01;
var KEY_DOWN:int = 0x02;
var KEY_LEFT:int = 0x04;
var KEY_RIGHT:int = 0x08;
var KEY_SHIFT:int = 0x08;
var KeyData:int;
function keyCheckDown(event:KeyboardEvent):void {
switch (event.keyCode){
case Keyboard.UP: KeyData |= KEY_UP; break;
case Keyboard.DOWN: KeyData |= KEY_DOWN; break;
case Keyboard.LEFT: KeyData |= KEY_LEFT; break;
case Keyboard.SHIFT: KeyData |= KEY_SHIFT; break;
}
}
function keyCheckUp(event:KeyboardEvent):void {
switch (event.keyCode){
case Keyboard.UP: KeyData &= ~KEY_UP; break;
case Keyboard.DOWN: KeyData &= ~KEY_DOWN; break;
case Keyboard.LEFT: KeyData &= ~KEY_LEFT; break;
case Keyboard.RIGHT: KeyData &= ~KEY_RIGHT; break;
case Keyboard.SHIFT: KeyData &= ~KEY_SHIFT; break;
}
}