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); } } 動体視力テストの名を借りたストレス解消ゲーム