/* マウスで自由に壁をつくります. Shift + drag で消しゴムになります. 右クリックの 初期化 で初めの状態にもどります. 下に落ちたら上からまたふってきます. 砂の挙動は砂のような液体のような何か. 元ネタは名前を忘れてしまいましたが昔遊んだアプリからです. */ package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.events.ContextMenuEvent; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Rectangle; import flash.ui.ContextMenu; import flash.ui.ContextMenuItem; [SWF(width=465, height=465, backgroundColor=0x000000, frameRate=60)] public class SimSand extends Sprite { private var numSand:int; private var sand:Array; private var lineBmp:BitmapData; private var sandBmp:BitmapData; private var screenBmp:BitmapData; private var lineSprite:Sprite; private var printSprite:Sprite; private var screenSprite:Sprite; private var canvasWidth:int; private var canvasHeight:int; private var context:ContextMenu; private var menuInit:ContextMenuItem; public function SimSand() { canvasWidth = stage.stageWidth / 3; canvasHeight = stage.stageHeight / 3; context = new ContextMenu(); menuInit = new ContextMenuItem( "初期化", false ); contextMenu = context; context.customItems.push( menuInit ); numSand = 1500; init( null ); menuInit.addEventListener( ContextMenuEvent.MENU_ITEM_SELECT, init ); stage.addEventListener( Event.ENTER_FRAME, loop ); stage.addEventListener( MouseEvent.MOUSE_DOWN, startDrawCanvas ); } private function init( e:ContextMenuEvent ):void { //set on and off EventListeners stage.removeEventListener( MouseEvent.MOUSE_UP, stopDrawCanvas ); stage.removeEventListener( MouseEvent.MOUSE_MOVE, drawCanvas ); if( stage.hasEventListener( MouseEvent.MOUSE_DOWN ) == false ) { stage.addEventListener( MouseEvent.MOUSE_DOWN, startDrawCanvas ); } // create sand sand = new Array(); for( var i:int = 0; i < numSand; i++ ) { var ramX:int = Math.random() * canvasWidth / 4 + canvasWidth / 4 * 1.5; var ramY:int = Math.random() * canvasHeight / 2 - canvasHeight / 2; sand.push( new Sand( ramX, ramY, 0xFFFFFF00 ) ); } lineSprite = new Sprite(); printSprite = new Sprite(); screenSprite = new Sprite(); //make standard stage lineSprite.graphics.lineStyle( 3 , 0x0000FF , 1.0 ); lineSprite.graphics.moveTo( 0, 20 ); lineSprite.graphics.lineTo( canvasWidth / 2 - 2, 50); lineSprite.graphics.moveTo( canvasWidth, 20 ); lineSprite.graphics.lineTo( canvasWidth / 2 + 2, 50 ); lineSprite.graphics.moveTo( canvasWidth / 5 * 2, 100 ); lineSprite.graphics.lineTo( canvasWidth / 5 * 3, 100 ); //sandglass extra stage /* lineSprite.graphics.lineStyle( 3 , 0x0000FF , 1.0 ); for( i = -1; i <= 1; i+=2 ) { lineSprite.graphics.moveTo( -10 * 3 + canvasWidth / 2, i * 0.5 * 100 + 80 ); for( var j:int = -10; j <= 10; j+=1 ) { lineSprite.graphics.lineTo( j * 3 + canvasWidth / 2, i * 0.5 * j * j + 80 ); } if( i > 0 ) lineSprite.graphics.lineTo( -10 * 3 + canvasWidth / 2, i * 0.5 * 100 + 80 ); } lineSprite.graphics.lineStyle( 2 , 0x000000 , 1.0 ); lineSprite.graphics.moveTo( canvasWidth / 2, 79 ); lineSprite.graphics.lineTo( canvasWidth / 2, 81 ); */ lineBmp = new BitmapData( canvasWidth, canvasHeight, true, 0x0 ); screenBmp = new BitmapData( canvasWidth, canvasHeight, true, 0x0 ); sandBmp = new BitmapData( canvasWidth, canvasHeight, true, 0x0 ); printSprite.addChild( new Bitmap(lineBmp) ); screenSprite.addChild( printSprite ); screenSprite.addChild( lineSprite ); screenSprite.addChild( new Bitmap( sandBmp ) ); screenSprite.scaleX = stage.stageWidth / canvasWidth; screenSprite.scaleY = stage.stageHeight / canvasHeight; addChild(screenSprite); } private function loop( e:Event ):void { screenSprite.graphics.clear(); screenSprite.graphics.beginFill(0x0); screenSprite.graphics.drawRect(0, 0, canvasWidth, canvasHeight); screenSprite.graphics.endFill(); screenBmp.draw( screenSprite ); sandBmp.lock(); sandBmp.fillRect( new Rectangle(0,0,canvasWidth, canvasHeight), 0x00000000); for( var i:int = 0; i < numSand; i++ ) { //falling noise var noise:int = 0; var neighbor:uint = 0; for( var j:int = -1; j <= 1; j++ ) { neighbor += screenBmp.getPixel( sand[i].x + j, sand[i].y + 1 ); } if( neighbor == 0x0 ) { noise = 0; } else { noise = int( Math.random() * 3 - 1.5 ); if( sand[i].x + noise < 0 || sand[i].x + noise>= canvasWidth ) { noise = 0; } } //on falling down if( screenBmp.getPixel( sand[i].x + noise, sand[i].y + 1 ) == 0x000000 ) { sand[i].x += noise; sand[i].y += 1; } //staying on wall else { var deltaX:int = int( Math.random() * 3 - 1.5 ); var deltaY:int = 0;//int( Math.random() * 2 ); if( sand[i].x + deltaX > 0 && sand[i].x + deltaX < canvasWidth ) { if( screenBmp.getPixel( sand[i].x + deltaX, sand[i].y + deltaY ) == 0x000000 ) { sand[i].x += deltaX; sand[i].y += deltaY; } } } if( sand[i].y > canvasHeight ) sand[i].y = 0; sandBmp.setPixel32( sand[i].x, sand[i].y, sand[i].color ); } sandBmp.unlock(); } private function startDrawCanvas( e:MouseEvent ):void { if( e.shiftKey == false ) { lineSprite.graphics.lineStyle( 3 , 0x0000FF ); // make-wall mode } else { lineSprite.graphics.lineStyle( 5, 0x000000 ); // eraser mode } lineSprite.graphics.moveTo( stage.mouseX / screenSprite.scaleX, stage.mouseY / screenSprite.scaleY ); stage.removeEventListener( MouseEvent.MOUSE_DOWN, startDrawCanvas ); stage.addEventListener( MouseEvent.MOUSE_MOVE, drawCanvas ); stage.addEventListener( MouseEvent.MOUSE_UP, stopDrawCanvas ); } private function stopDrawCanvas( e:MouseEvent ):void { lineBmp.draw( lineSprite ); lineSprite.graphics.clear(); printSprite.graphics.clear(); stage.removeEventListener( MouseEvent.MOUSE_MOVE, drawCanvas ); stage.removeEventListener( MouseEvent.MOUSE_UP, stopDrawCanvas ); stage.addEventListener( MouseEvent.MOUSE_DOWN, startDrawCanvas ); } private function drawCanvas( e:MouseEvent ):void { lineSprite.graphics.lineTo( stage.mouseX / screenSprite.scaleX, stage.mouseY / screenSprite.scaleY) } } } import flash.geom.Point; class Sand { public var x:int; public var y:int; public var color:uint; public function Sand( px:int, py:int, pcolor:uint ) { x = px; y = py; color = pcolor; } } 砂で遊ぶ