Beautifl - Flash Gallery

Thumbnail : 動体視力テストの名を借りたストレス解消ゲーム
動体視力テストの名を借りたストレス解消ゲーム
Hiiragi 2010-03-16 All rights reserved

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

package 
{
	/**
	 * 動体視力テストの名を借りたストレス解消ゲーム
	 * @author Hiiragi
	 * 
	 * 敵にしたい画像を読み込むと、ゲームが開始します。
	 * ストレスを解消したい相手の画像だとなおよろしいです。
	 * 
	 * ゲーム開始すると、画像の上に的が出てくるんで、
	 * そこをクリックすると打撃を与えられます。
	 * 一応、的の真ん中に近いほど高得点です。
	 * 
	 * 制限時間は1分。
	 * とにかく打撃を与えまくると面白いことになるかも。
	 * ・・・ちょっとエフェクト不足ですけど。
	 * 
	 * 本当は北斗の拳的な「ピリリリリッ」っていう音を出したかったのですが、
	 * SiONだと・・・というか、僕の腕だと上手く行きませんでした。
	 * 
	 * 本当は、全部の音をSiONで構築したかったのですが、
	 * MMLが奥が深すぎるのと、とても面倒だったので、
	 * 戦闘曲のみmp3のデータをお借りしました。
	 * 
	 * いつも以上にぐちゃぐちゃになってしまった・・・。全然だめですね。
	 * もっとたくさん作って、作り方を研究しないと。
	 * 
	 * 戦闘曲:
	 * Return To The Royal Road/ユーフルカ(Wingless Seraph)
	 * http://wingless-seraph.com/
	 */
	
	import flash.display.*;
	import flash.events.*;
	import flash.media.Sound;
	import flash.net.URLRequest;
	import flash.text.*;
	
	[SWF(width = 465, height = 465, frameRate = 60, backgroundColor = 0x333333)]
	public class Main extends Sprite 
	{
		private var _enemyImageMaxWidth:int = 400;
		private var _enemyImageMaxHeight:int = 400;
		
		private var _view:View;
		private var _model:Model;
		private var _controller:Controller;
		
		private var _statusText:TextField;
		
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			
			_statusText = new TextField();
			_statusText.autoSize = TextFieldAutoSize.LEFT;
			_statusText.defaultTextFormat = new TextFormat(null, 18, 0xFFFFFF);
			_statusText.text = "asset Data Loading now...";
			this.addChild(_statusText);
			
			var bgm1:Sound = new Sound();
			bgm1.addEventListener(Event.COMPLETE, assetsLoadComplete);
			bgm1.load(new URLRequest("http://melancholy.raindrop.jp/flash/wonderfl_3/RRR.mp3"));
		}
		
		private function assetsLoadComplete(e:Event):void 
		{
			
			this.removeChild(_statusText);
			_statusText = null;
			
			_model = new Model(_enemyImageMaxWidth, _enemyImageMaxHeight, this);
			_controller = new Controller(_model);
			_view = new View(_controller, _model, this);
			
			_model.battleBGM = e.target as Sound;
			this.addChild(_view);
		}
	}
}



import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.media.*;
import flash.net.*;
import com.bit101.components.*;
import flash.text.*;
import flash.utils.getTimer;
import flash.utils.Timer;

import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.easing.*;

import org.si.sion.SiONDriver;
import org.si.sion.SiONData;

class View extends Sprite
{
	private var _gameFlag:String;
	private const READY:String = "ready";
	private const PLAYING:String = "playing";
	private const GAME_END:String = "gameEnd";
	private const GAMEOVER:String = "gameover";
	
	private var _controller:Controller;
	private var _model:Model;
	private var _doc:DisplayObjectContainer;
	
	private var _vertices:Vector.<Number>;
	private var _indices:Vector.<int>;
	private var _uvtData:Vector.<Number>;
	
	private var _enemyImage:BitmapData;
	private var _enemySpriteForDraw:Sprite;
	private var _enemySprite:Sprite;
	private var _enemySpriteWidth:Number;
	private var _enemySpriteHeight:Number;
	private var _statusBar:StatusBar;
	private var _limitBar:LimitBar;
	
	private var _buttonField:Sprite;
	private var _loadBtn:PushButton;
	
	private var _startTextSp:Sprite;
	private var _hitAreaSp:Sprite;
	private var _gameEndTextSp:Sprite;
	private var _kimeSerifTextSp:Sprite;
	private var _resultSp:GameResultSprite;
	
	private var _enemyLastWords:Array = ["死にたわっ",
										 "ひっ!! ひでぶっ!!",
										 "ひゃぶ ぶっ!!",
										 "ぶげごげ!!ふ…ふげ…",
										 "たたずげべ ば!!",
										 "ばっう か…が…!!",
										 "どぉえへぷ!!",
										 "はっ…いっ!!、ゲッ!!",
										 "ぶあが であ!! ぐぶっ びっ! ぶあっ!!",
										 "げふ!! あがあ!! おえあ…"];
										 
	private var _enemyLastWordsSpArray:Array = []; 									 
	
	private var _sionDriver:SiONDriver;
	private var _attackSiONData:SiONData;
	private var _break1SiONData:SiONData;
	private var _break2SiONData:SiONData;
	private var _burstSiONData:SiONData;
	
	private var _battleBGM_sc:SoundChannel;
	
	public function View(controller:Controller, model:Model, doc:DisplayObjectContainer)
	{
		_battleBGM_sc = new SoundChannel();
		
		_gameFlag = READY;
		
		_controller = controller;
		_model = model;
		_doc = doc;
		
		_model.addEventListener(GameEvent.IMAGE_LOAD_COMPLETE, imageLoadComplete);
		_model.addEventListener(GameEvent.ATTACK_POINT_CHANGE, attackPointChange);
		_model.addEventListener(GameEvent.TIME_UPDATE, timeUpdate);
		_model.addEventListener(GameEvent.TIME_UP, timeUpHandler);
		_model.addEventListener(GameEvent.GAME_OVER, gameOverHandler);
		
		_enemySpriteForDraw = new Sprite();
		_enemySprite = new Sprite();
		_enemySprite.addEventListener(MouseEvent.CLICK, missClickHandler);
		this.addChild(_enemySpriteForDraw);
		_enemySpriteForDraw.addChild(_enemySprite);
		
		_statusBar = new StatusBar(_doc.stage.stageWidth, 50);
		_statusBar.visible = false;
		this.addChild(_statusBar);
		
		_limitBar = new LimitBar(_doc.stage.stageWidth, 30);
		_limitBar.visible = false;
		this.addChild(_limitBar);
		
		_buttonField = new Sprite();
		_loadBtn = new PushButton(_buttonField, 0, 0, "load Image", _controller.loadImage);
		_loadBtn.x = _doc.stage.stageWidth / 2 - _loadBtn.width / 2;
		_loadBtn.y = _doc.stage.stageHeight / 2 - _loadBtn.height / 2;
		
		this.addChild(_buttonField);
		
		//開始テキスト
		var textForBitmap:TextField = new TextField();
		textForBitmap.autoSize = TextFieldAutoSize.LEFT;
		textForBitmap.defaultTextFormat = new TextFormat("_明朝", 40, 0xFFFFFF, FontStyle.BOLD)
		textForBitmap.text = "開始!";
		
		var startTextBmpd:BitmapData = new BitmapData(textForBitmap.width * 4, textForBitmap.height * 4, true, 0);
		startTextBmpd.draw(textForBitmap, new Matrix(4, 0, 0, 4));
		var startTextBmp:Bitmap = new Bitmap(startTextBmpd, "auto", true);
		
		startTextBmp.x = -startTextBmp.width / 2;
		startTextBmp.y = -startTextBmp.height / 2;
		
		_startTextSp = new Sprite();
		_startTextSp.addChild(startTextBmp);
		_startTextSp.alpha = 0;
		_startTextSp.visible = false;
		_startTextSp.x = _doc.stage.stageWidth / 2;
		_startTextSp.y = _doc.stage.stageHeight / 2;
		_startTextSp.graphics.beginFill(0x0, .3);
		_startTextSp.graphics.drawRect( -_doc.stage.stageWidth / 2, -startTextBmp.height / 2, _doc.stage.stageWidth, startTextBmp.height);
		_startTextSp.graphics.endFill();
		
		this.addChild(_startTextSp);
		
		//ゲーム終了テキスト
		textForBitmap.text = "終了!";
		
		var gameEndTextBmpd:BitmapData = new BitmapData(textForBitmap.width * 4, textForBitmap.height * 4, true, 0);
		gameEndTextBmpd.draw(textForBitmap, new Matrix(4, 0, 0, 4));
		var gameEndTextBmp:Bitmap = new Bitmap(gameEndTextBmpd, "auto", true);
		
		gameEndTextBmp.x = -gameEndTextBmp.width / 2;
		gameEndTextBmp.y = -gameEndTextBmp.height / 2;
		
		_gameEndTextSp = new Sprite();
		_gameEndTextSp.addChild(gameEndTextBmp);
		_gameEndTextSp.visible = false;
		_gameEndTextSp.x = _doc.stage.stageWidth / 2;
		_gameEndTextSp.y = _doc.stage.stageHeight / 2;
		_gameEndTextSp.graphics.beginFill(0x0, .3);
		_gameEndTextSp.graphics.drawRect( -_doc.stage.stageWidth / 2, -gameEndTextBmp.height / 2, _doc.stage.stageWidth, gameEndTextBmp.height);
		_gameEndTextSp.graphics.endFill();
		this.addChild(_gameEndTextSp);
		
		//決め台詞テキスト
		textForBitmap.text = "おまえはもう死んでいる";
		
		var kimeSerifTextBmpd:BitmapData = new BitmapData(textForBitmap.width, textForBitmap.height, true, 0);
		kimeSerifTextBmpd.draw(textForBitmap, new Matrix(1, 0, 0, 1));
		var kimeSerifTextBmp:Bitmap = new Bitmap(kimeSerifTextBmpd, "auto", true);
		
		kimeSerifTextBmp.x = -kimeSerifTextBmp.width / 2;
		kimeSerifTextBmp.y = -kimeSerifTextBmp.height / 2;
		
		_kimeSerifTextSp = new Sprite();
		_kimeSerifTextSp.addChild(kimeSerifTextBmp);
		_kimeSerifTextSp.visible = false;
		_kimeSerifTextSp.x = _doc.stage.stageWidth / 2;
		_kimeSerifTextSp.y = _doc.stage.stageHeight / 2;
		_kimeSerifTextSp.graphics.beginFill(0x0, .3);
		_kimeSerifTextSp.graphics.drawRect( -_doc.stage.stageWidth / 2, -kimeSerifTextBmp.height / 2, _doc.stage.stageWidth, kimeSerifTextBmp.height);
		_kimeSerifTextSp.graphics.endFill();
		this.addChild(_kimeSerifTextSp);
		
		
		//ヒットエリア描画
		_hitAreaSp = new Sprite();
		_hitAreaSp.graphics.lineStyle(1,0xFFFFFF);
		_hitAreaSp.graphics.beginFill(0x000000, .7);
		_hitAreaSp.graphics.drawCircle(0, 0, 21);
		_hitAreaSp.graphics.endFill();
		_hitAreaSp.graphics.drawCircle(0, 0, 14);
		_hitAreaSp.graphics.drawCircle(0, 0, 7);
		_hitAreaSp.graphics.moveTo(0, -30);
		_hitAreaSp.graphics.lineTo(0, 30);
		_hitAreaSp.graphics.moveTo(-30, 0);
		_hitAreaSp.graphics.lineTo(30, 0);
		
		_hitAreaSp.visible = false;
		_hitAreaSp.addEventListener(MouseEvent.CLICK, hitAttackArea);
		this.addChild(_hitAreaSp);
		
		//断末魔の叫び
		for (var i:int = 0; i < _enemyLastWords.length; i++) 
		{
			var sp:Sprite = new Sprite();
			var bmp:Bitmap
			var bmpd:BitmapData;
			
			textForBitmap.text = _enemyLastWords[i];
			bmpd = new BitmapData(textForBitmap.width, textForBitmap.height, true, 0);
			bmpd.draw(textForBitmap, new Matrix(1, 0, 0, 1));
			bmp = new Bitmap(bmpd, "auto", true);
			bmp.x = -bmp.width / 2;
			bmp.y = -bmp.height / 2;
			sp.addChild(bmp);
			sp.graphics.beginFill(0x0, .3);
			sp.graphics.drawRect( -_doc.stage.stageWidth / 2, -50, _doc.stage.stageWidth, 100);
			sp.x = _doc.stage.stageWidth / 2;
			sp.y = _doc.stage.stageHeight / 2;
			_enemyLastWordsSpArray[i] = sp;
		}
		
		//結果表示
		_resultSp = new GameResultSprite(_doc.stage);
		_resultSp.visible = false;
		this.addChild(_resultSp);
		
		_sionDriver = new SiONDriver();
		_attackSiONData = _sionDriver.compile("%2@4 o4 l64 q8 v16c<v16c");
		_burstSiONData = _sionDriver.compile("%2@4 o7 l1 q8 c * o2c");
		_break1SiONData = _sionDriver.compile("#TABLE0{|0,2}; %1@1 l16 o8 nt0 c;");
		_break2SiONData = _sionDriver.compile("#TABLE0{|0,2}; %1@1 l16 o7 nt0 g;");
		_sionDriver.play();
	}
	
	private function imageLoadComplete(e:GameEvent):void 
	{
		_enemyImage = _model.enemyImage;
		createImage();
		
		_enemySprite.x = _doc.stage.stageWidth / 2 - _enemySprite.width / 2;
		_enemySprite.y = _doc.stage.stageHeight / 2 - _enemySprite.height / 2;
		
		_loadBtn.visible = false;
		
		_statusBar.y = -_statusBar.height;
		_limitBar.y = _doc.stage.stageHeight + _limitBar.height;
		
		_statusBar.visible = true;
		_limitBar.visible = true;
		_startTextSp.visible = true;
		
		BetweenAS3.serial	(
								BetweenAS3.parallel	(
													BetweenAS3.tween(_statusBar, { y:0 }, null, .5),
													BetweenAS3.tween(_limitBar, { y:435 }, null, .5)
													),
								BetweenAS3.tween(_startTextSp, { scaleX:1, scaleY:1, alpha:1 }, { scaleX:3, scaleY:3, alpha:1 }, .2),
								BetweenAS3.func(battleBgmStart),
								BetweenAS3.func(shakeStartText)
							).play();
	}
	
	private var _sceneChangeTimer:Timer;
	
	private function battleBgmStart():void 
	{
		_battleBGM_sc = _model.battleBGM.play(0,0,new SoundTransform(.1));
	}
	
	private function timeUpHandler(e:GameEvent):void 
	{
		trace("timeUp");
		_sceneChangeTimer = new Timer(2000);
			
		_hitAreaSp.visible = false;
		_gameFlag = GAME_END;
		_gameEndTextSp.visible = true;
		
		bgmFadeInOutTimer.addEventListener(TimerEvent.TIMER, bgmFadeout);
		bgmFadeInOutTimer.start();
		
		if (_model.attackPoints.length > 0)
		{
			this.removeEventListener(Event.ENTER_FRAME, shakeDisplayObject);
			_sceneChangeTimer.addEventListener(TimerEvent.TIMER, kimeSerifHandler);
			_sceneChangeTimer.start();
		}
		else
		{
			//ゲームオーバー
			_sceneChangeTimer.addEventListener(TimerEvent.TIMER, youLose);
			_sceneChangeTimer.start();
		}

	}
	
	//BGM FadeIn Out
	private var bgmFadeInOutTimer:Timer = new Timer(200);
	private function bgmFadeout(e:TimerEvent):void 
	{
		var vol:Number = _battleBGM_sc.soundTransform.volume;
		if (vol > 0)
		{
			_battleBGM_sc.soundTransform = new SoundTransform(vol - .01);
		}
		else
		{
			bgmFadeInOutTimer.stop();
			_battleBGM_sc.stop();
		}
	}
	
	private function youLose(e:Event):void 
	{
		_resultSp.textUpdate("まだまだ修行が足らん!");
		_resultSp.visible = true;
	}
	
	
	private function kimeSerifHandler(e:TimerEvent):void 
	{
		_sceneChangeTimer.stop();
		_gameEndTextSp.visible = false;
		_kimeSerifTextSp.visible = true;
		_sceneChangeTimer.removeEventListener(TimerEvent.TIMER, kimeSerifHandler);
		_sceneChangeTimer.addEventListener(TimerEvent.TIMER, breakStart);
		_sceneChangeTimer.start();


	}
	
	private var attackCount:int;
	private function breakStart(e:TimerEvent):void 
	{
		attackCount = _model.attackPoints.length;
		_firstAttackFlag = false;
		//_kimeSerifTextSp.visible = false;
		_sceneChangeTimer.stop();
		_diffScore = _model.score / _model.attackPoints.length;
		_sceneChangeTimer.delay = 10;	//即実行させるため
		_sceneChangeTimer.removeEventListener(TimerEvent.TIMER, breakStart);
		_sceneChangeTimer.addEventListener(TimerEvent.TIMER, enemyBreak);
		_sceneChangeTimer.start();
	}
	
	private var _nowScore:int;
	private var _diffScore:int;
	private var _firstAttackFlag:Boolean = false;
	private function enemyBreak(e:TimerEvent = null):void 
	{
		_sceneChangeTimer.stop();
		
		if (!_firstAttackFlag)
		{
			_sceneChangeTimer.delay = 1000;
			_firstAttackFlag = true;
		}
		else
		{
			_sceneChangeTimer.delay = 20;
		}
		
		var attackPoint:Point = _model.attackPoints.shift();
		
		//打撃ポイントを_verticesに反映させる
		var len:int = _vertices.length / 2;
		var pt:Point;
		var power:Number;
		var rad:Number;
		var radius:Number = 50;	//打撃の有効範囲
		
		var vx:Number;
		var vy:Number;
		
		//頂点移動の処理
		for (var i:int = 0; i < len; i++)
		{
			pt = new Point(_vertices[i * 2], _vertices[i * 2 + 1]);
			
			power = radius - Point.distance(pt, attackPoint);
			if (power <= 0)
			{
				//打撃の有効範囲外なので、スルー
				continue;
			}
			else
			{
				//打撃の有効範囲なので、powerと角度に従って頂点座標を移動
				rad = Math.atan2(attackPoint.y - pt.y, attackPoint.x - pt.x);
				vx = Math.cos(rad) * power;
				vy = Math.sin(rad) * power;
				_vertices[i * 2] -= vx * .5;
				_vertices[i * 2 + 1] -= vy * .5;
			}
		}
		
		//_sionDriver.sequenceOn([_break1SiONData, _break2SiONData][Math.round(Math.random())]);
		_controller.attackPointsAdjust(attackPoint);
		_nowScore += _diffScore;
		//_statusBar.scoreUpdate(_nowScore);
		drawImage();
		
		if (_model.attackPoints.length == 0)
		{
			trace("breakComplete");
			_kimeSerifTextSp.visible = false;
			_statusBar.scoreUpdate(_model.score);
			_sceneChangeTimer.removeEventListener(TimerEvent.TIMER, enemyBreak);
			_shakeCnt = 0;
			
			this.addEventListener(Event.ENTER_FRAME, shakeDisplayObject);
		}
		else
		{
			_sceneChangeTimer.start();
		}
	}
	
	

	
	private function timeUpdate(e:GameEvent):void 
	{
		_limitBar.scaleUpdate(_model.gameTimerLeft / _model.gameTimerLimit);
	}
	
	private var _spriteTextArray:Array = [];
	private function hitAttackArea(e:MouseEvent):void 
	{
		var sp:Sprite = new HitTextSprite();
		sp.x = mouseX;
		sp.y = mouseY;
		this.addChild(sp);
		_spriteTextArray.push(sp);
		_shakeCnt = 0;
		
		this.addEventListener(Event.ENTER_FRAME, shakeDisplayObject);
		_sionDriver.sequenceOn(_attackSiONData);
		_controller.hitAttackArea(100 - Point.distance(new Point(), new Point(e.localX, e.localY)) / (_hitAreaSp.width / 2) * 100);
	}
	
	private function missClickHandler(e:MouseEvent):void 
	{
		if (_gameFlag == PLAYING)
		{
			var sp:Sprite = new MissTextSprite();
			sp.x = mouseX;
			sp.y = mouseY;
			this.addChild(sp);
			_spriteTextArray.push(sp);
			_controller.missAttack();
		}
	}
	
	private function spriteTextManager(e:Event):void 
	{
		var len:int = _spriteTextArray.length;
		for (var i:int = len - 1; i >= 0; i--)
		{
			_spriteTextArray[i].y -= 1;
			_spriteTextArray[i].alpha -= .05;
			if (_spriteTextArray[i].alpha <= 0)
			{
				this.removeChild(_spriteTextArray[i]);
				_spriteTextArray.splice(i, 1);
			}
		}
	}
	
	private function attackPointChange(e:GameEvent):void 
	{
		_statusBar.scoreUpdate(_model.score);
		_statusBar.comboCntUpdate(_model.combo);
		_hitAreaSp.x = _model.attackPoint.x + _enemySprite.x;
		_hitAreaSp.y = _model.attackPoint.y + _enemySprite.y;
	}
	
	private var _shakeCnt:int = 0;
	private function shakeStartText():void 
	{
		this.addEventListener(Event.ENTER_FRAME, shakeDisplayObject);
	}
	
	private function shakeDisplayObject(e:Event):void 
	{
		if (_gameFlag == PLAYING || _gameFlag == GAME_END)
		{
			shakeFunction(_enemySprite, _doc.stage.stageWidth / 2 - _enemyImage.width / 2, _doc.stage.stageHeight / 2 - _enemyImage.height / 2);
		}
		else if (_gameFlag == READY)
		{
			shakeFunction(_startTextSp, _doc.stage.stageWidth / 2, _doc.stage.stageHeight / 2);
		}
		
		_shakeCnt++;
		
		if (_gameFlag == PLAYING && _shakeCnt > 4)
		{
			_enemySprite.x = _doc.stage.stageWidth / 2 - _enemySprite.width / 2;
			_enemySprite.y = _doc.stage.stageHeight / 2 - _enemySprite.height / 2;
			
			this.removeEventListener(Event.ENTER_FRAME, shakeDisplayObject);
		}
		else if (_gameFlag == READY && _shakeCnt >= 50)
		{
			//GameStart
			_gameFlag = PLAYING;
			_controller.gameStart();
			this.removeEventListener(Event.ENTER_FRAME, shakeDisplayObject);
			_startTextSp.visible = false;
			_hitAreaSp.visible = true;
			this.addEventListener(Event.ENTER_FRAME, spriteTextManager);
		}
		else if (_gameFlag == GAME_END && _shakeCnt >= 15)
		{
			this.removeEventListener(Event.ENTER_FRAME, shakeDisplayObject);
			enemyBurstInitialize();
			_sionDriver.sequenceOn(_burstSiONData);
			this.addEventListener(Event.ENTER_FRAME, enemyBurst);
		}
	}
	
	private var _canvas:BitmapData;
	private var _canvasDisplay:Bitmap;
	private var _canvasCtf:ColorTransform = new ColorTransform(.9,.9,.9,.9);
	private var _particles:Array = [];
	private function enemyBurstInitialize():void
	{
		_canvas = new BitmapData(_doc.stage.stageWidth, _doc.stage.stageHeight, true, 0);
		
		_canvas.lock();
		
		_canvasDisplay = new Bitmap(_canvas);
		_canvas.draw(_enemySpriteForDraw);
		_enemySpriteForDraw.visible = false;
		this.addChild(_canvasDisplay);
		var lenX:int = _doc.stage.stageWidth;
		var lenY:int = _doc.stage.stageHeight;
		
		var color:uint;
		var rad:Number;
		var power:Number;
		
		for (var y:int = 0; y < lenY; y++) 
		{
			for (var x:int = 0; x < lenX; x++) 
			{
				power = 20 * Math.random() + 10;
				color = _canvas.getPixel32(x, y);
				if ((color >> 24) & 0xFF > 0 && Math.random() > .9)
				{
					rad = Math.atan2(y - _doc.stage.stageHeight / 2, x - _doc.stage.stageWidth / 2);
					_particles.push(new Particle(x, y, color, Math.cos(rad) * power, Math.sin(rad) * power));
				}
			}
		}
		
		_canvas.fillRect(_canvas.rect, 0);
		_canvas.unlock();
		this.addChild(_enemyLastWordsSpArray[int(_model.score.toString().substr( -1, 1))]);
	}
	
	private function enemyBurst(e:Event):void
	{
		_canvas.lock();
		
		_canvas.colorTransform(_canvas.rect, _canvasCtf);
		var p:Particle;
		for (var i:int = _particles.length - 1; i >=0; i--) 
		{
			p = _particles[i];
			p.x += p.vx;
			p.y += p.vy;
			
			if (p.x < 0 || p.x > _doc.stage.stageWidth || p.y < 0 || p.y > _doc.stage.stageHeight)
			{
				_particles.splice(i, 1);
			}
			else
			{
				_canvas.setPixel32(p.x, p.y, p.color);
			}
		}
		
		_canvas.unlock();
		
		if (_particles.length == 0)
		{
			trace("burstComplete");
			this.removeEventListener(Event.ENTER_FRAME, enemyBurst);
			_sceneChangeTimer.delay = 3000;
			_sceneChangeTimer.addEventListener(TimerEvent.TIMER, gameOverSceneStart);
			_sceneChangeTimer.reset();
			_sceneChangeTimer.start();
		}
	}
	
	private function gameOverSceneStart(e:TimerEvent):void 
	{
		trace("gameOverSceneStart");
		_sceneChangeTimer.stop();
		_sceneChangeTimer.removeEventListener(TimerEvent.TIMER, gameOverSceneStart);
		
		_gameFlag = GAMEOVER;
		_controller.gameOver();
	}
	
	private function gameOverHandler(e:GameEvent):void 
	{
		trace("start gameOverHandler");
		var str:String = "Result\n\tattackCount : " + attackCount;
		_resultSp.textUpdate(str);
		this.addChild(_resultSp);
		_resultSp.visible = true;
		
		
		
	}
	
	private function shakeFunction(target:DisplayObject, cx:Number, cy:Number):void
	{
		target.x = cx + int(Math.random() * 10 - 5);
		target.y = cy + int(Math.random() * 10 - 5);
	}
	
	private function createImage():void
	{
		_vertices = new Vector.<Number>;
		_indices = new Vector.<int>;
		_uvtData = new Vector.<Number>;
		
		var w:int = _enemyImage.width;
		var h:int = _enemyImage.height;
		
		var xNum:int = 20;
		var yNum:int = 20;
		
		var xDiff:Number = w / (xNum - 1);
		var yDiff:Number = h / (yNum - 1);
		
		for (var y:int = 0; y < yNum; y++)
		{
			for (var x:int = 0; x < xNum; x++)
			{
				_vertices.push(xDiff * x, yDiff * y);
				_uvtData.push(x / (xNum - 1), y / (yNum - 1));
				
				if (x < xNum - 1)
				{
					var pos:int = x + y * xNum;
					_indices.push(pos, pos + 1, pos + xNum, pos + xNum, pos + 1, pos + xNum + 1);
				}
			}
		}
		
		drawImage();
	}
	
	private function drawImage():void 
	{
		var g:Graphics = _enemySprite.graphics;
		g.clear();
		//g.lineStyle(1, 0xFFFFFF);
		g.beginBitmapFill(_enemyImage, null, false, true);
		g.drawTriangles(_vertices, _indices, _uvtData);
		g.endFill();
	}
	
}

class Particle 
{
	public var x:int;
	public var y:int;
	public var color:uint;
	public var vx:Number;
	public var vy:Number;
	
	public function Particle(x:int, y:int, color:uint, vx:Number, vy:Number):void 
	{
		this.x = x;
		this.y = y;
		this.color = color;
		this.vx = vx;
		this.vy = vy;
	}
}

class HitTextSprite extends Sprite
{
	public function HitTextSprite() 
	{
		var tf:TextField = new TextField();
		tf.selectable = false;
		tf.autoSize = TextFieldAutoSize.LEFT;
		tf.text = "Hit!";
		tf.setTextFormat(new TextFormat(null, 35, 0xFF0000, FontStyle.BOLD));
		tf.x = -tf.width / 2;
		tf.y = -tf.height / 2;
		this.addChild(tf);
	}
}

class MissTextSprite extends Sprite
{
	public function MissTextSprite() 
	{
		var tf:TextField = new TextField();
		tf.selectable = false;
		tf.autoSize = TextFieldAutoSize.LEFT;
		tf.text = "Miss!";
		tf.setTextFormat(new TextFormat(null, 35, 0xFF0000, FontStyle.BOLD));
		tf.x = -tf.width / 2;
		tf.y = -tf.height / 2;
		this.addChild(tf);
	}
}

class GameResultSprite extends Sprite
{
	private var _sw:int;
	private var _sh:int;
	
	private var _tf:TextField;
	
	public function GameResultSprite(s:Stage) 
	{
		_sw = s.stageWidth;
		_sh = s.stageHeight;
		
		var filmHeight:int = 300;
		this.graphics.beginFill(0, .7);
		this.graphics.drawRect(0, _sh / 2 - filmHeight / 2, _sw, filmHeight);
		this.graphics.endFill();
		
		_tf = new TextField();
		_tf.defaultTextFormat = new TextFormat("_明朝", 30, 0xFFFFFF, FontStyle.BOLD);
		_tf.selectable = false;
		_tf.autoSize = TextFieldAutoSize.LEFT;
		this.addChild(_tf);
		

	}
	
	public function textUpdate(text:String):void 
	{
		_tf.text = text;
		_tf.x = _sw / 2 - _tf.width / 2;
		_tf.y = _sh / 2 - _tf.height / 2;
	}
}

class StatusBar extends Sprite
{
	private var _scoreLabelTxt:TextField;
	private var _scoreTxt:TextField;
	private var _comboLabelTxt:TextField;
	private var _comboTxt:TextField;
	
	public function StatusBar(w:int ,h:int) 
	{
		var tFormat:TextFormat = new TextFormat(null, 30, 0xFFFFFF, FontStyle.BOLD);
		
		this.graphics.beginFill(0x0, .3);
		this.graphics.drawRect(0, 0, w, h);
		this.graphics.endFill();
		
		_scoreLabelTxt = new TextField();
		_scoreLabelTxt.autoSize = TextFieldAutoSize.LEFT;
		_scoreLabelTxt.text = "Score : ";
		_scoreLabelTxt.x = 10;
		_scoreLabelTxt.y = 10;
		_scoreLabelTxt.setTextFormat(tFormat);
		this.addChild(_scoreLabelTxt);
		
		_scoreTxt = new TextField();
		_scoreTxt.autoSize = TextFieldAutoSize.LEFT;
		_scoreTxt.x = _scoreLabelTxt.x + _scoreLabelTxt.width;
		_scoreTxt.y = 10;
		_scoreTxt.defaultTextFormat = tFormat;
		_scoreTxt.text = "00000000";
		this.addChild(_scoreTxt);
		
		_comboLabelTxt = new TextField();
		_comboLabelTxt.autoSize = TextFieldAutoSize.LEFT;
		_comboLabelTxt.text = "Combo : ";
		_comboLabelTxt.x = w - 180;
		_comboLabelTxt.y = 10;
		_comboLabelTxt.setTextFormat(tFormat);
		this.addChild(_comboLabelTxt);
		
		_comboTxt = new TextField();
		_comboTxt.autoSize = TextFieldAutoSize.LEFT;
		_comboTxt.x = _comboLabelTxt.x + _comboLabelTxt.width;
		_comboTxt.y = 10;
		_comboTxt.defaultTextFormat = tFormat;
		_comboTxt.text = "0";
		this.addChild(_comboTxt);
	}
	
	public function scoreUpdate(value:int):void 
	{
		_scoreTxt.text = fillZero(value, 8);
	}
	
	private function fillZero(value:int, degit:int):String
	{
		var returnStr:String = "";
		for (var i:int = 0; i < degit; i++) returnStr += "0";
		returnStr += value.toString();
		
		return returnStr.substr( -degit, degit);
	}
	
	public function comboCntUpdate(value:int):void 
	{
		_comboTxt.text = value.toString();
	}
}


class LimitBar extends Sprite
{
	private var _frame:Sprite;
	private var _bar:Sprite;
	
	public function LimitBar(w:int, h:int) 
	{
		var g:Graphics;
		g = this.graphics;
		g.beginFill(0x000000);
		g.drawRect(0, 0, w, h);
		g.endFill();
		
		_frame = new Sprite();
		g = _frame.graphics;
		g.lineStyle(3, 0x222222);
		g.drawRect(0, 0, w, h);
		
		_bar = new Sprite();
		g = _bar.graphics;
		var mtx:Matrix = new Matrix();
		mtx.createGradientBox(w, h, Math.PI / 2);
		g.beginGradientFill(GradientType.LINEAR, [0x555555, 0x999999, 0x555555], [1, 1, 1], [0, 127, 255], mtx);
		g.drawRect(0, 0, w, h);
		g.endFill();
		
		this.addChild(_bar);
		this.addChild(_frame);
	}
	
	public function scaleUpdate(scale:Number):void
	{
		_bar.scaleX = scale;
		
		_bar.transform.colorTransform = new ColorTransform(1, scale, scale);
	}
}


class Controller
{
	private var _model:Model;
	
	public function Controller(model:Model) 
	{
		_model = model;
	}
	
	public function loadImage(e:MouseEvent = null):void 
	{
		_model.loadImage();
	}
	
	public function gameStart():void
	{
		_model.gameStart();
	}
	
	public function hitAttackArea(score:Number):void 
	{
		_model.hitAttackPoint(score);
	}
	
	public function missAttack():void 
	{
		_model.missAttack();
	}
	
	public function attackPointsAdjust(pt:Point):void 
	{
		_model.attackPointsAdjust(pt);
	}
	public function gameOver():void 
	{
		_model.gameOver();
	}
	//getter / setter
	public function get model():Model { return _model; }
	
	public function set model(value:Model):void 
	{
		_model = value;
	}
}

class Model extends EventDispatcher
{
	private var _fr:FileReference;
	private var _loader:Loader;
	private var _stage:Stage;
	
	private var _enemyImage:BitmapData;
	private var _enemyImageMaxWidth:int;
	private var _enemyImageMaxHeight:int;
	
	private var _attackPoint:Point;
	private var _attackPoints:Array;
	
	private var _attackCnt:int;
	private var _attackCntMax:int = 100;
	private var _combo:int;
	private var _maxCombo:int;
	private var _score:int;
	
	private var _gameTimer:Timer;
	private var _gameTimerLimit:int = 60000;
	private var _gameTimerStart:int;
	private var _gameTimerLeft:int;
	
	private var _battleBGM:Sound;
	
	public function Model(enemyImageMaxWidth:int, enemyImageMaxHeight:int, parent:DisplayObjectContainer) 
	{
		_enemyImageMaxWidth = enemyImageMaxWidth;
		_enemyImageMaxHeight = enemyImageMaxHeight;
		
		_stage = parent.stage;
		
		_attackPoints = [];
		
		_fr = new FileReference();
		_loader = new Loader();
		_fr.addEventListener(Event.SELECT, fileSelectedHandler);
		
		_gameTimer = new Timer(33);
	}
	
	//image Load ------------------------------------------------------------------------------------------
	public function loadImage():void
	{
		_fr.browse();
	}
	
	private function fileSelectedHandler(e:Event):void 
	{
		_fr.addEventListener(ProgressEvent.PROGRESS,onProgress);
		_fr.addEventListener(Event.COMPLETE,onComplete);
		// _fr.addEventListener(Event.OPEN, onOpen);
		// _fr.addEventListener(IOErrorEvent.IO_ERROR, onIoError);
		_fr.load(); // 読み込み処理を開始
	}
	
	private function onProgress(e:ProgressEvent):void
	{
		trace("読み込んだバイト数:" + e.bytesLoaded + "、 全体のバイト数:" + e.bytesTotal);
	}
	
	private function onComplete(e:Event):void
	{
		_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imgLoadComplete);
		_loader.loadBytes(_fr.data);
		
		// fr.type を参考にオブジェクト変換する等の処理を記述
		// fr.removeEventListener(...)
	}
	
	private function imgLoadComplete(e:Event):void 
	{
		trace("enemyImage Load Completed");
		
		_enemyImage = imageSizeCompressor(Bitmap(_loader.content).bitmapData, _enemyImageMaxWidth, _enemyImageMaxHeight);
		
		this.dispatchEvent(new GameEvent(GameEvent.IMAGE_LOAD_COMPLETE));
	}
	
	/**
	 * 指定のBitmapDataを、幅と高さの比率をそのままに、閾値に合わせて拡大縮小します。
	 * 
	 * @param	inputBitmapData	拡大・縮小したいBitmapData
	 * @param	maxWidth		幅の閾値
	 * @param	maxHeight		高さの閾値
	 * @return	閾値に合わせて拡大・縮小したBitmapData
	 */
	private function imageSizeCompressor(inputBitmapData:BitmapData, maxWidth:int, maxHeight:int):BitmapData
	{
		var ratio:Number;	//どれくらい拡大・縮小するか
		var fixWidth:int;	//拡大・縮小したときの幅
		var fixHeight:int;	//拡大・縮小したときの高さ
		
		var returnBitmapData:BitmapData;
		
		//maxWidth * maxHeightの範囲内に最大限に収める
		//横長の場合
		if (inputBitmapData.width / inputBitmapData.height >=  maxWidth / maxHeight)
		{
			//横長なので、横の大きさを閾値に合わせ、その比率分、高さを拡大縮小して、縦横の比率をそのままにサイズ変更する。
			ratio = _enemyImageMaxWidth / inputBitmapData.width;
			fixWidth = _enemyImageMaxWidth;
			fixHeight = inputBitmapData.height * ratio;
		}
		//縦長の場合
		else if (inputBitmapData.width / inputBitmapData.height <  maxWidth / maxHeight)
		{
			ratio = _enemyImageMaxHeight / inputBitmapData.height;
			fixWidth = inputBitmapData.width * ratio;
			fixHeight = _enemyImageMaxHeight;
		}
		
		returnBitmapData = new BitmapData(fixWidth, fixHeight, true, 0x0);
		returnBitmapData.draw(inputBitmapData, new Matrix(ratio, 0, 0, ratio));
		
		return returnBitmapData;
	}
	
	
	
	//Game Start ---------------------------------------------------------------------------------
	public function gameStart():void 
	{
		this.dispatchEvent(new GameEvent(GameEvent.GAME_START));
		attackPointChange();
		
		_gameTimerStart = getTimer();
		_gameTimerLeft = _gameTimerLimit;
		_gameTimer.delay = 33;
		_gameTimer.addEventListener(TimerEvent.TIMER, gameTimerEventHandler);
		_gameTimer.start();
		
	}
	
	//AttackPointにヒットしたとき
	public function hitAttackPoint(score:Number):void
	{
		_combo++;
		_score += score * 10 * _combo;
		if (_combo > _maxCombo) _maxCombo = _combo;
		_attackPoints.push(_attackPoint);
		attackPointChange();
	}
	
	//ミスしたとき
	public function missAttack():void 
	{
		_combo = 0;
		attackPointChange();
		this.dispatchEvent(new GameEvent(GameEvent.ATTACK_MISS));
	}
	
	private function attackPointChange():void
	{
		_attackPoint = new Point(Math.random() * _enemyImage.width, Math.random() * _enemyImage.height);
		this.dispatchEvent(new GameEvent(GameEvent.ATTACK_POINT_CHANGE));
	}
	
	private function gameTimerEventHandler(e:TimerEvent):void
	{
		_gameTimerLeft = _gameTimerLimit - (getTimer() - _gameTimerStart);
		
		if (_gameTimerLeft > 0)
		{
			this.dispatchEvent(new GameEvent(GameEvent.TIME_UPDATE));
		}
		else
		{
			this.dispatchEvent(new GameEvent(GameEvent.TIME_UP));
			_gameTimer.stop();
		}
	}
	
	public function attackPointsAdjust(pt:Point):void 
	{
		var len:int = _attackPoints.length;
		var power:Number;
		var attackFieldRadius:Number = 50;
		var rad:Number;
		var vx:Number;
		var vy:Number;
		
		for (var i:int = 0; i < len; i++)
		{
			power = attackFieldRadius - Point.distance(_attackPoints[i], pt);
			if (power <= 0)
			{
				continue;
			}
			else
			{
				rad = Math.atan2(_attackPoints[i].y - pt.y, _attackPoints[i].x - pt.x);
				vx = Math.cos(rad) * power;
				vy = Math.sin(rad) * power;
				_attackPoints[i].x -= vx;
				_attackPoints[i].y -= vy;
			}
		}
	}
	
	//EnemyBreaked
	public function gameOver():void 
	{
		this.dispatchEvent(new GameEvent(GameEvent.GAME_OVER));
	}
	
	//public function breakStart():void 
	//{
		//_gameTimer.delay = 500;
		//_gameTimer.reset();
		//_gameTimer.removeEventListener(TimerEvent.TIMER, gameTimerEventHandler);
		//_gameTimer.addEventListener(TimerEvent.TIMER, ememyBreak);
		//if (_attackPoints.length == 0)
		//{
			//this.dispatchEvent(new GameEvent(GameEvent.ENEMY_BREAK_COMPLETE));
		//}
		//else
		//{
			//this.dispatchEvent(new GameEvent(GameEvent.ENEMY_BREAK, _attackPoints.shift()));
			//_gameTimer.repeatCount = _attackPoints.length;
			//trace("timerStart : repeatCount = " + _gameTimer.repeatCount + " , currentCount = " + _gameTimer.currentCount);
			//_gameTimer.start();
		//}
//
	//}
	//
	//private function ememyBreak(e:TimerEvent):void 
	//{
		//_gameTimer.delay = 20;
		//trace("_gameTimer.currentCount = " + _gameTimer.currentCount);
		//
		//this.dispatchEvent(new GameEvent(GameEvent.ENEMY_BREAK, _attackPoints.shift()));
		//
		//if (_gameTimer.currentCount == _gameTimer.repeatCount)
		//{
			//_gameTimer.stop();
			//_gameTimer.removeEventListener(TimerEvent.TIMER, ememyBreak);
			//this.dispatchEvent(new GameEvent(GameEvent.ENEMY_BREAK_COMPLETE));
		//}
	//}
	
	// getter / setter ----------------------------------------------------------------------------
	public function get enemyImage():BitmapData { return _enemyImage; }
	
	public function set enemyImage(value:BitmapData):void 
	{
		_enemyImage = value;
	}
	
	public function get attackCnt():int { return _attackCnt; }
	
	public function set attackCnt(value:int):void 
	{
		_attackCnt = value;
	}
	
	public function get attackCntMax():int { return _attackCntMax; }
	
	public function set attackCntMax(value:int):void 
	{
		_attackCntMax = value;
	}
	
	public function get maxCombo():int { return _maxCombo; }
	
	public function set maxCombo(value:int):void 
	{
		_maxCombo = value;
	}
	
	public function get score():int { return _score; }
	
	public function set score(value:int):void 
	{
		_score = value;
	}
	
	public function get gameTimerLeft():int { return _gameTimerLeft; }
	public function get gameTimerLimit():int { return _gameTimerLimit; }
	public function get attackPoint():Point { return _attackPoint; }
	public function get combo():int { return _combo; }
	
	public function get attackPoints():Array { return _attackPoints; }
	
	public function get battleBGM():Sound { return _battleBGM; }
	
	public function set battleBGM(value:Sound):void 
	{
		_battleBGM = value;
	}
	
}

class GameEvent extends Event
{
	public static const IMAGE_LOAD_COMPLETE:String = "imageLoadComplete";
	public static const ATTACK_POINT_CHANGE:String = "attackPointChange";
	public static const ATTACK_MISS:String = "attackMiss";
	public static const GAME_START:String = "gameStart";
	public static const GAME_OVER:String = "gameOver";
	public static const TIME_UPDATE:String = "timeUpdate";
	public static const TIME_UP:String = "timeUp";
	public static const ENEMY_BREAK:String = "enemyBreak";
	public static const ENEMY_BREAK_COMPLETE:String = "enemyBreakComplete";
	
	public function GameEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false) 
	{
		super(type, bubbles, cancelable);
	}

}