ソースコード
import 'dart:html';
import 'dart:html' as html;
import 'dart:math';
import 'package:stagexl/stagexl.dart';
import 'package:stagexl/stagexl.dart' as xl;
import 'type_circle.dart';
void main() {
new FjTyping();
}
/** シーン(enumの代わり) */
class SEEN {
/** スタート画面 */
static final SEEN START = new SEEN(1);
/** プレイ画面 */
static final SEEN PLAY = new SEEN(2);
/** 結果画面 */
static final SEEN END = new SEEN(3);
/** 識別用 */
int _value;
/** コンストラクタ */
SEEN(int val) {
_value = val;
}
}
/** FJ タイピング */
class FjTyping {
/** 基準点数 */
static const int _BASE_SCORE = 10;
/** キャンパス */
CanvasElement canvas;
/** ステージ */
Stage stage;
/** レンダー */
RenderLoop renderLoop;
/** タイプリスト */
List ballList;
/** 乱数 */
Random rnd;
/** シーン */
SEEN seen;
/** 丸J */
Sprite typeJ;
/** 丸F */
Sprite typeF;
/** 丸J */
TextField textJ;
/** 丸F */
TextField textF;
/** 開始時刻 */
DateTime _startDate;
/** 点数 */
num _score;
/** 連続コンボ数 */
int _combo;
/** ミスタイプ数 */
int _miss;
/** クリックイベント時、ENDシーンからSTARTシーンへ移るかどうか */
bool isGoStartSeen;
/** オンストラクタ */
FjTyping() {
this.rnd = new Random();
this.isGoStartSeen = true;
this.seen = SEEN.START;
// キャンパス作成
Element parson = querySelector("#fj_typing");
this.canvas = new CanvasElement(width: 500, height: 500);
this.canvas.id = "fj_canvas";
parson.append(this.canvas);
// ステージ作成
this.stage = new Stage(this.canvas);
this.renderLoop = new RenderLoop();
this.renderLoop.addStage(this.stage);
// イベント追加
this.stage.onMouseDown.listen(this.stageMouseDown);
this.stage.onMouseUp.listen(this.stageMouseUp);
window.onKeyDown.listen(this.keyDown);
window.onKeyUp.listen(this.keyUp);
// Fキーを押すと色が付く
this.typeF = new Sprite();
this.typeF.onMouseDown.listen(this.typeFMouseDown);
this.textF = new TextField("F");
TextFormat format = new TextFormat(textF.defaultTextFormat.font, 30, Color.Black);
this.textF.defaultTextFormat = format;
this.textF.autoSize = TextFieldAutoSize.CENTER;
this.textF.x = 500 * (1 / 3) - (this.textF.width / 2);
this.textF.y = 500 * (2 / 3) - (this.textF.height / 2);
this.textF.onMouseDown.listen(this.typeFMouseDown);
// Jキーを押すと色が付く
this.typeJ = new Sprite();
this.typeJ.onMouseDown.listen(this.typeJMouseDown);
this.textJ = new TextField("J");
this.textJ.defaultTextFormat = format;
this.textJ.autoSize = TextFieldAutoSize.CENTER;
this.textJ.x = 500 * (2 / 3) - (this.textJ.width / 2);
this.textJ.y = 500 * (2 / 3) - (this.textJ.height / 2);
this.textJ.onMouseDown.listen(this.typeJMouseDown);
// 開始シーン表示
drawStartSeen();
this.stage.onEnterFrame.listen(this._onEnterFrame);
}
num _fpsAverage = null;
/** FPS表示 */
_onEnterFrame(EnterFrameEvent e) {
if (_fpsAverage == null) {
_fpsAverage = 1.00 / e.passedTime;
} else {
_fpsAverage = 0.05 / e.passedTime + 0.95 * _fpsAverage;
}
html.querySelector('#fpsMeter').innerHtml = 'fps: ${_fpsAverage.round()}';
}
/** ゲーム開始 */
_playStart() {
this.stage.removeChildren();
this.renderLoop.juggler.clear();
this.seen = SEEN.PLAY;
this._startDate = new DateTime.now();
this._score = 0;
this._miss = 0;
this._combo = 0;
this.ballList = new List();
for (int ii = 0; ii < 50; ii++) {
this.ballList.add(new TypeCircle());
this.ballList[ii].draw(ii);
this.stage.addChild(this.ballList[ii]);
}
this.ballList[0].drawRect();
this.stage.addChild(this.typeF);
this.stage.addChild(this.typeJ);
this.drawTypeF(false);
this.drawTypeJ(false);
this.stage.addChild(this.textF);
this.stage.addChild(this.textJ);
}
/** ゲーム終了 */
void playEnd() {
this.stage.removeChildren();
this.seen = SEEN.END;
this.drawEndSeen();
}
/** プレイ中キーダウンイベント */
_playDownKey(KEY key) {
TypeCircle cur = this.ballList[0];
// キーが一致するか判定
if (cur.key == key) {
// コンボ数インクリメント
this._combo++;
// スコア加算
this._score = this._score + (_BASE_SCORE * (this._combo / 10));
// 一致した円をどっかへ動かす
var tween = new Tween(cur, 1.0, TransitionFunction.easeOutInBack);
tween.animate.x.by(this.rnd.nextInt(1000) - 500);
tween.animate.y.by(this.rnd.nextInt(1000) - 500);
tween.animate.alpha.to(0.0);
tween.animate.skewX;
tween.onComplete = () {
cur.removeFromParent();
this.renderLoop.juggler.removeTweens(cur);
this.renderLoop.juggler.remove(tween);
};
this.renderLoop.juggler.add(tween);
// 四角の枠を取る
this.ballList[0].draw();
// リストから先頭を削除
this.ballList.removeAt(0);
// 残りの列を左にずらす
for (int ii = 0; ii < this.ballList.length; ii++) {
var twe = new Tween(this.ballList[ii], 0.1, TransitionFunction.easeOutQuadratic);
twe.animate.x.by(-40);
this.renderLoop.juggler.add(twe);
if (ii == 0) {
// 先頭は四角を描画
this.ballList[0].drawRect();
}
}
} else {
// ミスタイプの場合
// コンボ数初期化
this._combo = 0;
// ミスタイプ数インクリメント
this._miss++;
// スコア減算
this._score = this._score - _BASE_SCORE;
}
}
/** キー押下イベント */
void keyDown(html.KeyboardEvent ev) {
if (this.seen == SEEN.START) {
// スペースキー
if (ev.keyCode == 32) {
this._playStart();
}
} else if (this.seen == SEEN.PLAY) {
// F
if (ev.keyCode == 70) {
this._playDownKey(KEY.F);
this.drawTypeF(true);
this.drawTypeJ(false);
} // J
else if (ev.keyCode == 74) {
this._playDownKey(KEY.J);
this.drawTypeF(false);
this.drawTypeJ(true);
}
// リストがなくなったら終了
if (this.ballList.length <= 0) {
this.playEnd();
}
} else if (this.seen == SEEN.END) {
// スペースキー
if (ev.keyCode == 32) {
this.seen = SEEN.START;
this.drawStartSeen();
}
}
}
/** キーアップリスナー */
void keyUp(html.KeyboardEvent ev) {
if (this.seen == SEEN.START) {
return;
} else if (this.seen == SEEN.PLAY) {
// F
if (ev.keyCode == 70) {
this.drawTypeF(false);
} // J
else if (ev.keyCode == 74) {
this.drawTypeJ(false);
}
} else if (this.seen == SEEN.END) {
return;
}
}
/** ステージマウスダウン */
void stageMouseDown(xl.MouseEvent ev) {
if (this.seen == SEEN.START) {
this._playStart();
} else if (this.seen == SEEN.END) {
if (isGoStartSeen) {
this.seen = SEEN.START;
this.drawStartSeen();
} else {
this.isGoStartSeen = true;
}
}
}
/** ステージマウスアップ */
void stageMouseUp(xl.MouseEvent ev) {
if (this.seen == SEEN.PLAY) {
this.drawTypeF(false);
this.drawTypeJ(false);
}
}
/** タイプFマウスダウン */
void typeFMouseDown(xl.MouseEvent ev) {
if (this.seen == SEEN.PLAY) {
// F
this._playDownKey(KEY.F);
this.drawTypeF(true);
this.drawTypeJ(false);
if (this.ballList.length <= 0) {
this.isGoStartSeen = false;
this.playEnd();
}
}
}
/** タイプJマウスダウン */
void typeJMouseDown(xl.MouseEvent ev) {
if (this.seen == SEEN.PLAY) {
this._playDownKey(KEY.J);
this.drawTypeF(false);
this.drawTypeJ(true);
if (this.ballList.length <= 0) {
this.isGoStartSeen = false;
this.playEnd();
}
}
}
/** 開始画面 */
void drawStartSeen() {
this.stage.removeChildren();
TextField typeInfo = new TextField("赤は「F」、青は「J」キーを押すんだよ");
TextFormat format = new TextFormat(typeInfo.defaultTextFormat.font, 25, Color.Black);
typeInfo.defaultTextFormat = format;
typeInfo.width = 500;
typeInfo.y = 500 * (1 / 3);
typeInfo.autoSize = TextFieldAutoSize.CENTER;
this.stage.addChild(typeInfo);
TextField startInfo = new TextField("スペースキーを押すか、どこかをクリックでゲームが始まるよ");
startInfo.width = 500;
startInfo.y = 500 * (1 / 2);
startInfo.autoSize = TextFieldAutoSize.CENTER;
this.stage.addChild(startInfo);
}
/** 終了画面 */
void drawEndSeen() {
// 経過時間計算
DateTime now = new DateTime.now();
num time = now.difference(this._startDate).inMilliseconds;
String text = "タイム:" + now.difference(this._startDate).inSeconds.toString() + "秒 ";
text = text + " ミス:" + this._miss.toString() + "回";
// タイム表示
TextField timeInfo = new TextField();
timeInfo.width = 500;
timeInfo.y = 500 * (1 / 3);
timeInfo.autoSize = TextFieldAutoSize.CENTER;
timeInfo.text = text;
this.stage.addChild(timeInfo);
// スコア表示
TextField scoreInfo = new TextField();
TextFormat format = new TextFormat(scoreInfo.defaultTextFormat.font, 40, Color.Black);
format.align = TextFormatAlign.CENTER;
scoreInfo.defaultTextFormat = format;
text = "スコア " + ((this._score / time) * 1000000).round().toString() + " pts";
scoreInfo.width = 500;
scoreInfo.y = 500 * (1 / 2) - (scoreInfo.height / 2);
scoreInfo.autoSize = TextFieldAutoSize.CENTER;
scoreInfo.text = text;
this.stage.addChild(scoreInfo);
TextField startInfo = new TextField("スペースキーを押すか、クリックしてくださいな");
startInfo.width = 500;
startInfo.y = 500 * (2 / 3);
startInfo.autoSize = TextFieldAutoSize.CENTER;
this.stage.addChild(startInfo);
}
/** タイプJ描画 */
void drawTypeJ(bool isDown) {
this.typeJ.graphics.clear();
num y = 500 * (2 / 3);
num x = 500 * (2 / 3);
this.typeJ.graphics.circle(x, y, 30);
if (isDown) {
this.typeJ.graphics.fillColor(Color.Blue);
} else {
this.typeJ.graphics.fillColor(Color.White);
}
this.typeJ.graphics.strokeColor(Color.Black);
}
/** タイプF描画 */
void drawTypeF(bool isDown) {
this.typeF.graphics.clear();
num y = 500 * (2 / 3);
num x = 500 * (1 / 3);
this.typeF.graphics.circle(x, y, 30);
if (isDown) {
this.typeF.graphics.fillColor(Color.Red);
} else {
this.typeF.graphics.fillColor(Color.White);
}
this.typeF.graphics.strokeColor(Color.Black);
}
}
type_circle.dart
library TypeCircle;
import 'dart:math';
import 'package:stagexl/stagexl.dart';
/** キー情報(enumの代わり) */
class KEY {
static final KEY F = new KEY(1);
static final KEY J = new KEY(2);
int _value;
KEY(int val) {
_value = val;
}
}
/** タイプ円 */
class TypeCircle extends Shape {
/** キー */
KEY key;
/** 乱数 */
Random rnd;
/** 開始位置 */
num startX;
/** コンストラクタ */
TypeCircle() : super() {
this.rnd = new Random();
this.startX = 0;
if (this.rnd.nextBool()) {
this.key = KEY.F;
} else {
this.key = KEY.J;
}
}
/** 円描画 */
draw([int index = -1]) {
this.graphics.clear();
if (index == -1) {
this.graphics.circle(this.startX, 250, 20);
} else {
this.startX = 250 + (40 * index);
this.graphics.circle(250 + (40 * index), 250, 20);
}
if (this.key == KEY.F) {
this.graphics.fillColor(Color.Red);
} else {
this.graphics.fillColor(Color.Blue);
}
}
/** 四角で囲む */
drawRect() {
this.graphics.beginPath();
this.graphics.rect(this.startX - 20, 250 - 20, 40, 40);
this.graphics.strokeColor(Color.Black, 2);
this.graphics.closePath();
}
}