Beautifl - Flash Gallery

Thumbnail : 伝染病のシミュレーション
伝染病のシミュレーション
Nao_u 2009-09-18 All rights reserved

再生するにはFlash Playerが必要です。デスクトップのブラウザでご覧ください。

//
// 伝染病のシミュレーション
//
// 緑:健康
// 黄:潜伏期間
// 赤:発症
// 青:免疫獲得
// 灰:死亡
//
//
// 感染率:接触時の感染率(0~100%)
// 毒性の強さ:発症時のHP減少の大きさ(0-999)
// 潜伏期間:感染から発症までの期間
// 発症時間:周りに感染を広めながらHPが減少していく期間
// 免疫期間:発症終了後に抗体ができて再感染しない期間
//
// 移動:人の移動量の設定(4段階)
// 国境:国境移動の制限(検疫:発症している人のみ通行不可 封鎖:完全封鎖)
// 隔離:「ON」にすると発症している人を画面右下方向に隔離
//
// 左クリックでワクチンを適用(30%の確率で免疫を獲得)
//
//
// 解説など:http://game.g.hatena.ne.jp/Nao_u/20090430#p1
//
package {      
    import flash.display.Sprite;      
    import flash.events.*;      
    [SWF(width="465", height="465", backgroundColor="0xFFFFFF", frameRate="20")]       
         
    public class FlashTest extends Sprite {      
        public function FlashTest() {      
            Main = this;      
            initialize();      
            stage.addEventListener(Event.ENTER_FRAME,update);       
            stage.addEventListener(MouseEvent.MOUSE_DOWN,  viewClickEvent);    
        }      
    }      
}  

var kansen:int  = 80;       // 感染率(%)
var dokusei:int = 5;       // 毒性の強さ
var senpuku:int = 10;       // 潜伏期間
var hassyou:int = 7;        // 発症時間
var meneki:int  = 50;       // 免疫期間

var moveRate:Number = 0.55; // 移動の自由度
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 = 384; 
var BITMAP_H:int = 384; 

var AgentAry:Vector.<Agent> = new Vector.<Agent>;
var Text0:TextField = new TextField();
var Text1: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 = 2;
var KokkyouType:int = 2;

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

    clearBmp();    
    createAgent();

    Text0.x = 10;
    Text0.y = 386;
    Text0.defaultTextFormat = new TextFormat( "AXIS Std R", 13, 0, false );
    Main.addChild(Text0); 
    
    Text1.x = 59;
    Text1.y = 388;
    Text1.width = 384;
    Text1.defaultTextFormat = new TextFormat( "AXIS Std R", 10, 0, false );
    Main.addChild(Text1); 

    createResetButton();
    createKakuriButton();
    createIdouButton();
    createKokkyouButton();

    new InputArea(10,410, "感染率   ", kansen.toString(), function(str:String):void{kansen=parseInt(str)} );
    new InputArea(10,426, "毒性の強さ ", dokusei.toString(), function(str:String):void{dokusei=parseInt(str)} );

    new InputArea(118,410, "潜伏期間 ", senpuku.toString(), function(str:String):void{senpuku=parseInt(str)} );
    new InputArea(118,426, "発症時間 ", hassyou.toString(), function(str:String):void{hassyou=parseInt(str)} );
    new InputArea(118,442, "免疫期間 ", meneki.toString(), function(str:String):void{meneki=parseInt(str)} );

    var t:TextField;
    t = new TextField();
    t.text = "%";
    t.x = 95;
    t.y = 410;
    t.width = 16;
    t.height = 16;
    Main.addChild(t); 

    t = new TextField();
    t.text = "日";
    t.x = 193;
    t.y = 410;
    t.width = 16;
    t.height = 19;
    Main.addChild(t); 

    t = new TextField();
    t.text = "日";
    t.x = 193;
    t.y = 426;
    t.width = 16;
    t.height = 19;
    Main.addChild(t); 

    t = new TextField();
    t.text = "日";
    t.x = 193;
    t.y = 442;
    t.width = 16;
    t.height = 19;
    Main.addChild(t); 
} 

function viewClickEvent(event:MouseEvent):void{
    var mx:Number = Main.stage.mouseX;    
    var my:Number = Main.stage.mouseY;    
    
    for each( var agent:Agent in AgentAry ){
        if( agent.Status == 0 && Math.random() < 0.3 ){
            var dx:Number = mx-agent.X;
            var dy:Number = my-agent.Y;
            var dist:Number = Math.sqrt( dx*dx + dy*dy );
            if( dist < 35 ){
                agent.Status = 3;
                agent.CountDown = meneki * 10;
            }
        }
    }
}

function createAgent():void{
    AgentAry = new Vector.<Agent>;

    var i:int;
    var agent:Agent;
    for( i=0; i<4096; i++ ){
        agent = new Agent( 0,0,BITMAP_W,BITMAP_H );
    }
    for( i=0; i<1500; i++ ){
        agent = new Agent( 0,60,128, BITMAP_H-128);
    }
    for( i=0; i<1024; i++ ){
        agent = new Agent( 128,0,BITMAP_W,80 );
    }
    for( i=0; i<2048; i++ ){
        agent = new Agent( 128,0,BITMAP_W,80 );
    }
    for( i=0; i<4096; i++ ){
        agent = new Agent( 0,200,BITMAP_W,180 );
    }
}

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{createAgent();Time=0;}
    ); 
    Main.addChild(ResetButton);
}

function createKakuriButton():void{
    KakuriButton = new Button(64, 18, 8, "隔離 OFF", 10);
    KakuriButton.x = 468-120
    KakuriButton.y = 468-52
    KakuriButton.addEventListener(MouseEvent.CLICK, 
        function(event:MouseEvent):void{
            if( kakuri == 0.0 ) {
                KakuriButton.setLabel("隔離 ON");
                kakuri = 0.45;
            }else{
                KakuriButton.setLabel("隔離 OFF");
                kakuri = 0.0;
            }
        }
    ); 
    Main.addChild(KakuriButton);
}

function createIdouButton():void{

    Idou.border = true;
    Idou.borderColor = 0xCCCCCC;
    Idou.x = 234;
    Idou.y = 415;
    Idou.width = 79;
    Idou.height = 17;
    Idou.defaultTextFormat = new TextFormat( "AXIS Std R", 10, 0, false );
    Idou.text = "移動:通常"
    Main.addChild(Idou); 

    var up:Button   = new Button(14,9, 1, "▲", 9);
    var down:Button = new Button(14,9, 1, "▼", 9);
    up.x = 317;
    up.y = 409;
    down.x = 317;
    down.y = 424;
    Main.addChild(up);
    Main.addChild(down);

    up.addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void{ IdouType--; updateIdouType(); } ); 
    down.addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void{ IdouType++; updateIdouType(); } ); 
}

function updateIdouType():void{
    if( IdouType < 0 ) IdouType = 3;
    if( IdouType > 3 ) IdouType = 0;
    switch( IdouType ){
    case 0: Idou.text = "移動:厳戒態勢   "; moveRate = MoveRateAry[IdouType]; break;
    case 1: Idou.text = "移動:外出制限   "; moveRate = MoveRateAry[IdouType]; break;
    case 2: Idou.text = "移動:通常   "; moveRate = MoveRateAry[IdouType]; break;
    case 3: Idou.text = "移動:活発   "; moveRate = MoveRateAry[IdouType]; break;
    }
}


function createKokkyouButton():void{

    Kokkyou.border = true;
    Kokkyou.borderColor = 0xCCCCCC;
    Kokkyou.x = 234;
    Kokkyou.y = 443;
    Kokkyou.width = 79;
    Kokkyou.height = 17;
    Kokkyou.defaultTextFormat = new TextFormat( "AXIS Std R", 10, 0, false );
    Kokkyou.text = "国境:自由"
    Main.addChild(Kokkyou); 

    var up:Button   = new Button(14,9, 2, "▲", 9);
    var down:Button = new Button(14,9, 2, "▼", 9);
    up.x = 317;
    up.y = 440;
    down.x = 317;
    down.y = 454;
    Main.addChild(up);
    Main.addChild(down);

    up.addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void{ KokkyouType--; updateKokkyouType(); } ); 
    down.addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void{ KokkyouType++; updateKokkyouType(); } ); 
}

function updateKokkyouType():void{
    if( KokkyouType < 0 ) KokkyouType = 2;
    if( KokkyouType > 2 ) KokkyouType = 0;
    switch( KokkyouType ){
    case 0: Kokkyou.text = "国境:封鎖"; break;
    case 1: Kokkyou.text = "国境:検疫"; break;
    case 2: Kokkyou.text = "国境:通常"; break;
    }
}


function update(e :Event):void{      

    var num:int = 0;
    for( var i:int=0; i<5; i++ ) StateAry[i] = 0;

    var agent:Agent;
    for each( agent in AgentAry )  { agent.update(); num++; }
    clearBmp();    
    
    for each( agent  in AgentAry ) agent.draw();

    Time++;
    var date:int = Time/10;
    var n0:String = (StateAry[0]/num*100).toFixed(2);
    var n1:String = (StateAry[1]/num*100).toFixed(2);
    var n2:String = (StateAry[2]/num*100).toFixed(2);
    var n3:String = (StateAry[3]/num*100).toFixed(2);
    var n4:String = (StateAry[4]/num*100).toFixed(2);
    Text0.text = ""+ date +"日目";
    Text1.htmlText = 
        "<font color='#006000'>健康</font>: "+n0+"%   " +
        "<font color='#b0b000'>潜伏</font>: "+n1+"%   " +
        "<font color='#b00000'>発症</font>: "+n2+"%   " +
        "<font color='#003090'>免疫</font>: "+n3+"%   " +
        "<font color='#303030'>死亡</font>: "+n4+"%   " ;
            
}


function clearBmp():void{
    var col:int = 0xc0c0c0;
    for( var x:int=0; x<BITMAP_W; x++){
        for( var y:int=0; y<BITMAP_H; y++){
            BmpData.setPixel(x, y, BgColor);  
        }
    }

    if( KokkyouType <= 1 ){
        col = WallColor;
        if( KokkyouType == 1 ) col = WallColor2;
        for( x=0; x<BITMAP_W; x++){
            BmpData.setPixel(x, 86, col);  
            BmpData.setPixel(x, 87, col);  
            BmpData.setPixel(x, 88, col);  
            BmpData.setPixel(128, x, col);  
            BmpData.setPixel(129, x, col);  
            BmpData.setPixel(130, x, col);  
            BmpData.setPixel(x,201, col);  
            BmpData.setPixel(x,202, col);  
            BmpData.setPixel(x,203, col);  
        }
    }

    for( x=0; x<BITMAP_W; x++){
        BmpData.setPixel(x, 0, WallColor);  
        BmpData.setPixel(x, BITMAP_W-1, WallColor);  
        BmpData.setPixel(0, x, WallColor);  
        BmpData.setPixel(BITMAP_W-1, x, WallColor);  
        if( x<25 || (x>55 && x<170) || (x>178 && x<297) || (x>300) ){
            BmpData.setPixel(x, 85, WallColor);  
            BmpData.setPixel(x, 86, WallColor);  
            BmpData.setPixel(x, 87, WallColor);  
            BmpData.setPixel(x, 88, WallColor);  
            BmpData.setPixel(x, 89, WallColor);  
            BmpData.setPixel(127, x, WallColor);  
            BmpData.setPixel(128, x, WallColor);  
            BmpData.setPixel(129, x, WallColor);  
            BmpData.setPixel(130, x, WallColor);  
            BmpData.setPixel(131, x, WallColor);  
            BmpData.setPixel(x,200, WallColor);  
            BmpData.setPixel(x,201, WallColor);  
            BmpData.setPixel(x,202, WallColor);  
            BmpData.setPixel(x,203, WallColor);  
            BmpData.setPixel(x,204, WallColor);  
        }
    }

}


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 function Agent( x:Number, y:Number, px:Number, py:Number ){  
        do{
            X = x + px*Math.random();
            Y = y + py*Math.random();
        } while( BmpData.getPixel(X, Y) != BgColor );

        Hp = 5000 + Math.random() * 5000;
        AgentAry.push(this);
        if( Math.random() < 0.001 ) Status = 1;
    }

    public function update():void{
        StateAry[Status]++;

        if( Status != 4 ){
            var add:Number = 0;
            if( Status == 2 ) add = kakuri;    // 隔離パラメータ

            var sx:Number = moveRate * (Math.random()*5 - 2.5) + add;
            var sy:Number = moveRate * (Math.random()*5 - 2.5) + add;
            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;
            }
            if( BmpData.getPixel(X+sx, Y+sy) == ColRed0 ){
                if( Math.random()*100 < kansen ) {    // 感染力
                    Status = 1;
                    CountDown = senpuku * 10;    // 潜伏期間
                }
            }  
        }
        if( Status == 1 ){
            CountDown--;
            if( CountDown <= 0 ) {
                CountDown = hassyou * 10;    // 発症時間
                Status = 2;
            }
        }
        if( Status == 2 ){
            Hp-= dokusei * 10;              // 毒性の強さ
            CountDown--;
            if( CountDown <= 0 ) {
                CountDown = meneki * 10;    // 免疫期間
                Status = 3;
            }
            if( Hp <= 0 ) {
                Status = 4;
            }
        }
        if( Status == 3 ){
            CountDown--;
            if( CountDown <= 0 ) {
                CountDown = 0;    // 
                Status = 0;
            }
        }

    }

    public function draw():void{
        var col0:int, col1:int;
        switch( Status ){
        case 0: col0 = col1 = ColGreen;   break;
        case 1: col0 = col1 = ColYellow;  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;
    }
}