動体視力テストの名を借りたストレス解消ゲーム
動体視力テストの名を借りたストレス解消ゲーム
@author Hiiragi
敵にしたい画像を読み込むと、ゲームが開始します。
ストレスを解消したい相手の画像だとなおよろしいです。
ゲーム開始すると、画像の上に的が出てくるんで、
そこをクリックすると打撃を与えられます。
一応、的の真ん中に近いほど高得点です。
制限時間は1分。
とにかく打撃を与えまくると面白いことになるかも。
・・・ちょっとエフェクト不足ですけど。
本当は北斗の拳的な「ピリリリリッ」っていう音を出したかったのですが、
SiONだと・・・というか、僕の腕だと上手く行きませんでした。
本当は、全部の音をSiONで構築したかったのですが、
MMLが奥が深すぎるのと、とても面倒だったので、
戦闘曲のみmp3のデータをお借りしました。
いつも以上にぐちゃぐちゃになってしまった・・・。全然だめですね。
もっとたくさん作って、作り方を研究しないと。
戦闘曲:
Return To The Royal Road/ユーフルカ(Wingless Seraph)
http://wingless-seraph.com/
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);
}
}