<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>仮ぶろぐ &#187; ゲーム作成</title>
	<atom:link href="http://plusb.jp/blog/?cat=19&#038;feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://plusb.jp/blog</link>
	<description>今更なことをそれでもつらづらと書くブログ</description>
	<lastBuildDate>Tue, 07 May 2013 09:06:48 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>JavaScriptでBINGO -ざっくり設計</title>
		<link>http://plusb.jp/blog/?p=806</link>
		<comments>http://plusb.jp/blog/?p=806#comments</comments>
		<pubDate>Mon, 23 Apr 2012 03:24:24 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[ゲーム作成]]></category>
		<category><![CDATA[プログラミング]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=806</guid>
		<description><![CDATA[ビンゴをJavaScriptで作ってみました。 1.概要 ビンゴゲームWebアプリケーションを作成する。 ただし、作成するのは抽選機能のみ。Webブラウザー上で、グラフィカルに抽選する機能を提供する。 （ビンゴカードをオ &#8230; <a href="http://plusb.jp/blog/?p=806">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>ビンゴをJavaScriptで作ってみました。<br />
<a href="http://plusb.jp/blog/wp-content/uploads/2012/04/bingo.png"><img src="http://plusb.jp/blog/wp-content/uploads/2012/04/bingo-300x224.png" alt="BINGO 画面" title="bingo" width="300" height="224" class="alignnone size-medium wp-image-816" /></a></p>
<p><span id="more-806"></span></p>
<h2>1.概要</h2>
<p>ビンゴゲームWebアプリケーションを作成する。<br />
ただし、作成するのは抽選機能のみ。Webブラウザー上で、グラフィカルに抽選する機能を提供する。<br />
（ビンゴカードをオンラインから取得してもおもしろいかも、全員がスマートフォン時代ならいけるかも）</p>
<h2>2.用件</h2>
<h3>2.1 機能用件</h3>
<p>数字は1～75<br />
抽選中のアイコンは大きく表示する<br />
全ての数字のアイコンを画面上に表示しておく<br />
抽選済みの数字は強調表示される<br />
抽選中の演出を用意する。<br />
抽選の乱数は、基底値を固定すると同じ値が選択される<br />
レイアウトは独立して変更可能とする</p>
<h3>2.2 非機能用件</h3>
<p>言語は、JavaScript+CSS3(for HTML5)</p>
<h2>3.設計</h2>
<h3>3.1概念抽出</h3>
<ul>
<li>　数字アイコン
</li>
<li>　点灯する、消灯する
</li>
<li>　カレントのアイコン
</li>
<li>　レイアウト
</li>
<li>　抽選する
</li>
<li>　クリアする（初期化する）
</li>
</ul>
<h2>3.2 シナリオ</h2>
<h3>　3.2.1 クリア<br />
<h3>
　　数字アイコン1～75を消灯状態で表示する<br />
　　カレントアイコンを消灯状態で表示する<br />
　　乱数、抽選情報を初期化する</p>
<h3>　3.2.2 抽選する</h3>
<dl>
　　
<dt>抽選用演出を開始する</dt>
<dd>演出は、ランダムに未抽選の数字の選択（選択されると数字アイコンを点灯し、次の数字が選ばれたら消灯する）を繰り返す。
</dd>
<p>　　
<dt>演出を終了する</dt>
<dd>最終的な抽選を実施して、選択された数字アイコンを点灯させる。<br />
最終的に選ばれた数字アイコンは数回点滅下のちに点灯する。<br />
さらにカレントのアイコンに数字を表示する。
</dd>
</dl>
<p>考えがまとまったので後はとっとと実装しまして、<br />
<a href="/dqfw/bingo/bingo.html">出来上がり</a>。<br />
ソース:<a href="/dqfw/bingo/js/bingo.js">bingo.js</a>,<a href="/dqfw/bingo/js/bingo_ctl.js">bingo_ctl.js</a><br />
<a href="/blog/?p=810">補足</a>も確認して下さい。</p>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=806</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaScriptでバトルシティー</title>
		<link>http://plusb.jp/blog/?p=772</link>
		<comments>http://plusb.jp/blog/?p=772#comments</comments>
		<pubDate>Sun, 14 Aug 2011 02:12:27 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[ゲーム作成]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[battlecity]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=772</guid>
		<description><![CDATA[例によってライブラリを作り込むための参考にバトルシティー的なものを作ってみました。 今回はゲームとして成立するところまでは作るつもりはないのですが、敵のアルゴリズムをどうしたら良いのかがわかりませんorz しかもiPho &#8230; <a href="http://plusb.jp/blog/?p=772">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>例によってライブラリを作り込むための参考にバトルシティー的なものを作ってみました。<br />
今回はゲームとして成立するところまでは作るつもりはないのですが、敵のアルゴリズムをどうしたら良いのかがわかりませんorz<br />
しかもiPhoneでは処理が重すぎるようで、本末転倒。<br />
<span id="more-772"></span><br />
ライブラリ:<a href="dq-canvas.js">dq-canvas.js</a><br />
<a href="http://plusb.jp/dqfw/samples/battlecity.html">battlecity.html</a><br />
フレーム内を一度クリックするとキーが効くようになります。十字キーに対応しています。<br />
Aボタンは&#8217;V'キー<br />
Bボタンは&#8217;C'キー<br />
です。<br />
<iframe src="http://plusb.jp/dqfw/samples/battlecity.html" width="320" height="426" style="overflow: hidden;"></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=772</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>テトリスをJavascriptで作る 実装編(3)</title>
		<link>http://plusb.jp/blog/?p=760</link>
		<comments>http://plusb.jp/blog/?p=760#comments</comments>
		<pubDate>Mon, 08 Aug 2011 08:26:52 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[ゲーム作成]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Tetris]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=760</guid>
		<description><![CDATA[実装編　その３です。 ステージやラインについて解説します。 その１ その２ ソース:tetris.js ライブラリー:dq-rtg.js,dq-cancas.js(実際に動かすにはライブラリのコアコンポーネントとjQue &#8230; <a href="http://plusb.jp/blog/?p=760">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>実装編　その３です。<br />
ステージやラインについて解説します。<br />
<a href="http://plusb.jp/blog/?p=699">その１</a><br />
<a href="http://plusb.jp/blog/?p=709">その２</a><br />
ソース:<a href="http://plusb.jp/dq/samples/js/tetris.js">tetris.js</a><br />
ライブラリー:<a href="http://plusb.jp/dq/js/rtg/dq-rtg.js">dq-rtg.js</a>,<a href="http://plusb.jp/dq/js/dq-canvas.js">dq-cancas.js</a>(実際に動かすにはライブラリのコアコンポーネントとjQueryも必要です）。<br />
<a href="http://plusb.jp/blog/?p=694">できあがり</a><br />
<span id="more-760"></span></p>
<h3>TETRIS.Stageクラス</h3>
<p>ステージは22本(*1)のラインがあり、ラインは10個の粒（ブロック）で構成されています。<br />
簡単に言えば縦22x横10個の粒で構成されていることになります。<br />
*1 ゲームとして有効なのは20ラインですが、テトリミノが落下する位置として2ライン分追加しています。</p>
<p>ステージの役割は粒の管理で、ラインの削除判定や削除中のラインの状態を管理します。</p>
<h4>初期化</h4>
<p>ラインを作成します。</p>
<pre>
DQ.TETRIS.Stage = function (engine) {
    this._engine = engine;
    this.lines = [];
    for (var i = 0; i &lt; 22; i++) {
        this.lines.push(new DQ.TETRIS.Line(i));
    }
}
</pre>
<p>ゲーム開始時にライン上のチップを削除することで初期化します。</p>
<pre>
DQ.TETRIS.Stage.prototype = {
    left: DQ.TETRIS.STAGE_LEFT,
    top: -14,
    lines: [],
    clear: function () {
        for (var ln = 0; ln < this.lines.length; ln++) {
            for (var i = 0; i &lt; 10; i++) {
                if (this.lines[ln].chips[i]) {
                    this.lines[ln].chips[i].remove();
                    this.lines[ln].chips[i] = null;
                }
            }
        }
    }
}
</pre>
<h4>当たり判定</h4>
<p>Stageクラスが落下中のテトリミノがステージの壁やステージ上の粒にぶつかるかどうかの当たり判定を担当します。</p>
<pre>
    hitTest: function (mino, dx, dy) {
        ///&lt;summary&gt;
        ///指定のテトリミノの当たり判定をします。
        ///&lt;/summary&gt;
        ///&lt;param name="mino" type="Tetrimino"&gt;
        ///対象となるテトリミノを指定
        ///&lt;/param&gt;
        ///&lt;param name="dx", type="number"&gt;
        ///x方向の移動予定幅を指定
        ///&lt;/param&gt;
        ///&lt;param name="dy", type="number"&gt;
        ///y方向の移動予定幅を指定
        ///&lt;/param&gt;

        for (var i = 0; i &lt; 4; i++) {
            var chip = mino.chip(i);
            var cx = Math.floor((chip.x + dx - this.left) / DQ.TETRIS.CHIP_SIZE);
            var cy = Math.floor((chip.y + dy - this.top) / DQ.TETRIS.CHIP_SIZE);
            //wall
            if (cx < 0
                || 10 &lt;= cx
                || 22 &lt;= cy) {
                return true;
            }
            //chip
            if (this.lines[cy].chips[cx]) {
                return true;
            }
        }

        return false;
    }
}
</pre>
<p>落下中のテトリミノを構成する４つの粒に対して壁とステージ上の粒との当たり判定を実施します。<br />
ステージ上の粒の有無は、対象となる座標に粒のインスタンスがあるかどうかで判定しています。<br />
横移動の場合、<code>hitTest()</code>で<code>false</code>が返ると移動できません。<br />
落下処理の場合は、「遊び」状態へ遷移します。「遊び」状態が放置されると落下中のテトリミノはただの粒へと変化します。</p>
<h4>粒への移行</h4>
<p>落下が完了したテトリミノをラインへ粒として登録します。</p>
<pre>
{
    transChip: function (mino) {
        ///&lt;summary&gt;
        ///落下中だったテトリミノをチップへ変換します。
        ///&lt;/summary&gt;
        ///&lt;param name="mino" type="Tetrimino"&gt;
        ///変換するテトリミノを指定
        ///&lt;/param&gt;

        for (var i = 0; i &lt; 4; i++) {
            var chip = mino.chip(i);
            var cx = Math.floor((chip.x - this.left) / DQ.TETRIS.CHIP_SIZE);
            var ln = Math.floor((chip.y - this.top) / DQ.TETRIS.CHIP_SIZE);
            this.lines[ln].chips[cx] = new DQ.Screen.Canvas.Sprite({
                image: chipImg.client[0],
                x: cx * DQ.TETRIS.CHIP_SIZE + this.left,
                y: ln * DQ.TETRIS.CHIP_SIZE + this.top,
                width: DQ.TETRIS.CHIP_SIZE,
                height: DQ.TETRIS.CHIP_SIZE,
                dir: mino.type,
                animation: false,
                numberOfPause: 0
            });
            this._engine._canvas.push(this.lines[ln].chips[cx]);
        }
    }
}
</pre>
<p>テトリミノを構成する４つの粒を該当する座標の粒として登録します。<br />
粒のインスタンスは描画用の<code>Sprite</code>です。スプライトを作成する際には、座標系を粒から画面のpixel単位へ変換しています。<br />
作成したSpriteは、キャンバスへ登録します（これによって、粒の描画はキャンバス(*2)が適宜実行してくれます)。<br />
*2 念のためですが、このキャンバスは拙作のライブラリのキャンバスクラスの事です。</p>
<h4>削除判定</h4>
<p>ライン上に新しい粒が登録された後は、ラインの削除判定を実施します。</p>
<pre>
{
    eraseLine: function () {
        this._lineFlash = [];
        for (var i = 21; 2 <= i; i--) {
            if (this.lines[i].canErase()) {
                //削除可能なラインがあったのでフラッシュ状態へ移行
                this.mode = DQ.TETRIS.StageMode.Flash;
                this._elapse = 0;
                var line = new DQ.Screen.Canvas.Sprite({
                    y: i * DQ.TETRIS.CHIP_SIZE + this.top,
                    x: this.left,
                    width: DQ.TETRIS.CHIP_SIZE * 10,
                    height: DQ.TETRIS.CHIP_SIZE,
                    animation: false,
                    numberOfPause: 0,
                    image: flashImg.client[0]
                });
                this._lineFlash.push(line);
                engine._canvas.push(line);
            }
        }
        return this._lineFlash.length;
    },
</pre>
<p>全てのラインについて削除判定を行います。判定自体はラインクラスに任せていますが、ようはライン内の全ての領域に粒があれば削除可能です。<br />
削除可能なら画面効果用のスプライトを登録しています。<br />
この時点で、ゲーム全体の状態はゲーム中(Play)状態から削除中(Erase)状態へ遷移します。<br />
また、画面効果として削除可能なラインがフラッシュして、しばらくしてからラインが消え、またしばらくしてから全体が落下するようになっています。<br />
ちなみに、メソッドの名前が微妙だったりしますが、そこは目をつぶります。</p>
<h4>状態管理</h4>
<p>Stageクラスではラインが削除中の場合だけ状態を管理します。状態はUpdate()の呼び出しによる一定の時間経過後に遷移します。</p>
<pre>
{
    update: function () {
        if (this.mode == DQ.TETRIS.StageMode.None) {
            return;
        }
        this._elapse += 60 / TETRIS.fps;
        if (this.wait <= this._elapse) {
            //時間経過を超えた
            switch (this.mode) {
                case DQ.TETRIS.StageMode.Flash:
                    //フラッシュ中から削除中へ移行
                    this.mode = DQ.TETRIS.StageMode.Erase;
                    this._elapse = 0;
                    for (var i = 21; 2 <= i; i--) {
                        if (this.lines[i].canErase()) {
                            this.lines[i].clear();
                        }
                    }
                    for (var i = 0; i &lt; this._lineFlash.length; i++) {
                        this._lineFlash[i].remove();
                    }
                    this._lineFlash = [];
                    break;
                case DQ.TETRIS.StageMode.Erase:
                    //削除中から通常へ移行
                    this.mode = DQ.TETRIS.StageMode.None;
                    this._elapse = 0;
                    var count = 0;
                    for (var i = 21; 2 <= i; i--) {
                        if (this.lines[i].canDown()) {
                            this.lines.splice(i, 1);
                            count++;
                        }
                    }
                    //削除した分だけラインを追加
                    for (i = 0; i &lt; count; i++) {
                        this.lines.unshift(new DQ.TETRIS.Line(0));
                    }
                    //ライン番号を振り直す
                    for (i = 0; i &lt; 22; i++) {
                        this.lines[i].line(i);
                    }
                    break;
            }
        }
    }
}
</pre>
<p>ステージの状態は<code>None</code>→<code>Flash</code>→<code>Erase</code>→<code>None</code>へと遷移します。<br />
状態遷移後に経過時間を示す<code>_elapse</code>がクリアされ、一定時間経過後にイベント処理が実施されます。<br />
まず、Flash状態にある場合は削除可能なラインをクリアします。それからフラッシュ効果用のスプライトを削除(remove)します。<br />
（スプライトをremove()するとキャンバスクラスからも削除され、描画の対象から外れます。）<br />
次に削除状態にある場合は、ラインを落下させます。<br />
落下処理については、削除可能なラインを配列から削除して、削除した分のラインを配列の先頭に追加することで落下したように見せています。<br />
余談ですが、ぷよぷよなど粒自体が落ちていく場合にはこの手法は使えないですね。</p>
<h4>全体の状態遷移</h4>
<p><a href="http://plusb.jp/blog/?p=709">その２</a>では、割愛していた全体の状態遷移の管理です。<br />
updateメソッド中で、状態毎のチェックを実施しています。</p>
<pre>
    update: function () {
        var mode = DQ.TETRIS.Mode;
        switch (this.game) {
            case mode.Start:
            case mode.GameOver:
                return;
            case mode.Erase:
                //ラインの削除演出中
                this.stage.update();
                if (this.stage.mode == DQ.TETRIS.StageMode.None) {
                    //演出完了
                    this.game = DQ.TETRIS.Mode.Play;
                    //落下したラインに合わせてゴーストを移動
                    this.moveGhost();
                }
                break;
            case mode.Delay:
                //「遊び」中
                this._elapse += 60 / this.fps;
                if (this.wait <= this._elapse) {
                    this.game = DQ.TETRIS.Mode.Play;
                    this.stage.transChip(this.current);
                    this.current.remove();
                    this.shiftCurrent();
                    soundBox.play(1);

                    var n_line = this.stage.eraseLine();
                    if (n_line > 0) {
                        this.score.score += DQ.TETRIS.Game.ScoreTable[n_line];
                        this.score.line += n_line;
                        var pre = this.score.level;
                        this.score.level = Math.floor(this.score.line / 10) + 1;
                        if (pre != this.score.level) {
                            this.levelUp();
                        }
                        this.updateScore();

                        this.game = DQ.TETRIS.Mode.Erase;
                        return;
                    }
                }
                break;
            case mode.Play:
                //「落下中」
                if (this.isAccelerate()) {
                    if (this.current.y - this._startPos > DQ.TETRIS.CHIP_SIZE) {
                        this.score.score++;
                        this.updateScore();
                        this._startPos += DQ.TETRIS.CHIP_SIZE;
                    }
                }
                var dy = this.gdy;
                if (this.hitTest(0, dy + DQ.TETRIS.CHIP_SIZE)) {
                    //「遊び」に移行
                    this.game = DQ.TETRIS.Mode.Delay;
                    this._elapse = 0;
                    this.stopAccelerate();
                    this.current.move(0, dy);
                    this.current.fit();
                } else {
                    this.current.move(0, dy);

                }
                break;
        }

    }
}
</pre>
<p>ゲーム全体の状態はゲーム開始直後(StartGame)、ゲームオーバー(GameOver)、ゲーム中(Play)、遊び中(Delay)および削除中(Erase)です。<br />
ゲーム開始直後およびゲームオーバー状態はキー操作があるまでやることも状態遷移もありません。<br />
次に基本となるゲーム状態ですが、ここについては前回説明しているので割愛します。<br />
遊び状態は一定時間が経過するとステージへ定着(transChip)します。それからラインの削除判定を実施し、削除可能なラインがなければゲーム中状態へ遷移し、削除可能なラインがあれば削除中へ遷移します。<br />
また、削除可能なラインがあった場合はスコアーの計算やレベルアップの判定も実施していますが、説明は割愛します。<br />
削除中状態ではステージに状態管理を委譲しています。これは、削除中の演出の管理をStageクラスへ局所化する意図があります。</p>
<p>次回は、ゴーストやハードドロップについてです。</p>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=760</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>dq(rpg) 2011-08-02</title>
		<link>http://plusb.jp/blog/?p=745</link>
		<comments>http://plusb.jp/blog/?p=745#comments</comments>
		<pubDate>Tue, 02 Aug 2011 14:13:52 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[dq]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[ゲーム作成]]></category>
		<category><![CDATA[JavaScript MapEditor]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=745</guid>
		<description><![CDATA[ナイトリービルドを更新。 マップエディターを更新しました。汎用的なマップエディターのための最低限の機能は実装した気がします。 プロジェクトを導入 マップの新規追加対応 マップのプロパティー編集に対応 コマンドを追加（マッ &#8230; <a href="http://plusb.jp/blog/?p=745">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>ナイトリービルドを更新。<br />
マップエディターを更新しました。汎用的なマップエディターのための最低限の機能は実装した気がします。<br />
<span id="more-745"></span></p>
<ol>
<li>プロジェクトを導入</li>
<li>マップの新規追加対応</li>
<li>マップのプロパティー編集に対応</li>
<li>コマンドを追加（マップの移動、リサイズ)</li>
<li>スプライトのアップロード対応</li>
</ol>
<p><a href="http://plusb.jp/blog/wp-content/uploads/2011/08/map_editor.png"><img src="http://plusb.jp/blog/wp-content/uploads/2011/08/map_editor-300x208.png" alt="マップエディター" title="マップエディター" width="300" height="208" class="alignnone size-medium wp-image-746" /></a><br />
<a href="http://plusb.jp/dqfw/">ナイトリービルド</a>を更新。<br />
<a href="http://plusb.jp/dqfw/samples/map_editor.html">マップエディター</a><br />
後の問題はオフラインでも使えなければ公開している意味が無いことかorz</p>
<p>補足ですが、キャッシュが効いている場合に<code>CTRL+R</code>などでページを再読み込みする必要があります。</p>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=745</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>dq(rpg) 2011-07-25</title>
		<link>http://plusb.jp/blog/?p=731</link>
		<comments>http://plusb.jp/blog/?p=731#comments</comments>
		<pubDate>Mon, 25 Jul 2011 15:53:30 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[dq]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[ゲーム作成]]></category>
		<category><![CDATA[Tiled Map Editor]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=731</guid>
		<description><![CDATA[ナイトリービルドを更新。 マップエディターを更新しました。 canvasで実装したことで、描画に余裕ができたので今までの固定長のマップ領域をブラウザーに併せてサイズ変更できるようにしました。 マップエディターを汎用化する &#8230; <a href="http://plusb.jp/blog/?p=731">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>ナイトリービルドを更新。<br />
マップエディターを更新しました。<br />
<span id="more-731"></span><br />
canvasで実装したことで、描画に余裕ができたので今までの固定長のマップ領域をブラウザーに併せてサイズ変更できるようにしました。<br />
<div id="attachment_732" class="wp-caption alignnone" style="width: 310px"><a href="http://plusb.jp/blog/wp-content/uploads/2011/07/map_editor.jpg"><img src="http://plusb.jp/blog/wp-content/uploads/2011/07/map_editor-300x240.jpg" alt="マップエディター" title="map_editor" width="300" height="240" class="size-medium wp-image-732" /></a><p class="wp-caption-text">マップエディター</p></div></p>
<p>マップエディターを汎用化するために、しばらく改変を続けたいと思います。</p>
<p><a href="http://plusb.jp/dqfw/">ナイトリービルド</a>を更新。<br />
<a href="http://plusb.jp/dqfw/samples/map_editor.html">マップエディター</a></p>
<p>補足ですが、キャッシュが効いている場合に<code>CTRL+R</code>などでページを再読み込みする必要があります。</p>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=731</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>テトリスをJavaScriptで作る 実装編(2)</title>
		<link>http://plusb.jp/blog/?p=709</link>
		<comments>http://plusb.jp/blog/?p=709#comments</comments>
		<pubDate>Sat, 23 Jul 2011 03:25:59 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[ゲーム作成]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Tetris]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=709</guid>
		<description><![CDATA[実装編　その２です。 描画周りやTETRISクラスの説明です。 その１ ソース:tetris.js ライブラリー:dq-rtg.js,dq-cancas.js(実際に動かすにはライブラリのコアコンポーネントとjQuery &#8230; <a href="http://plusb.jp/blog/?p=709">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>実装編　その２です。<br />
描画周りやTETRISクラスの説明です。<br />
<a href="http://plusb.jp/blog/?p=699">その１</a><br />
ソース:<a href="http://plusb.jp/dq/samples/js/tetris.js">tetris.js</a><br />
ライブラリー:<a href="http://plusb.jp/dq/js/rtg/dq-rtg.js">dq-rtg.js</a>,<a href="http://plusb.jp/dq/js/dq-canvas.js">dq-cancas.js</a>(実際に動かすにはライブラリのコアコンポーネントとjQueryも必要です）。<br />
<a href="http://plusb.jp/blog/?p=694">できあがり</a><br />
<span id="more-709"></span></p>
<h3>描画</h3>
<h4>イメージの読み込み</h4>
<p>canvasのdrawImageに引き渡すimgオブジェクトですが、描画する前に読み込みが完了している必要があります。<br />
そのため、ゲームエンジンを起動する前に全ての画像の読み込みの完了(loadイベントを使用）をチェックします。</p>
<pre>
var count = 0;
function image_loaded(sender) {
   count++;
   if(count == 4) {
       TETRIS = new DQ.TETRIS(engine);
       TETRIS.initialize();

       //engineはタイマーやキーイベントを管理
       engine.start();
   }
}

stageImg = new <a href="http://plusb.jp/blog/?p=480">DQ.Image</a>(DQ.page(), {
   width: 320,
   height: 320,
   src: "default/images/stage.png",
   onLoaded: image_loaded
});

...
</pre>
<h4>canvasへの描画</h4>
<p>前回も少し触れていますがcanvasへの描画はキャンバスクラスが担当していますので、その仕組みを説明しておきます。<br />
キャンバス内では、指定されたFPSになるようにインターバルタイマーが発生して<code>update</code>メソッドを呼び出されます。<br />
<code>update</code>メソッド内では、背景から順番にイメージを都度描画しています。</p>
<pre>
update: function () {
    if (this.drawing) {
        return;
    }
    this.drawing = true;
    var ctx = this.obj0.getContext("2d"),
        sort_compare = function (o1, o2) {
             return o1.zIndex - o2.zInde;
    }

    //準備
    this._sprites.sort(sort_compare);

    //描画
    !this._bg &#038;&#038; ctx.clearRect(0, 0, this._size.width, this._size.height);

    //背景描画
    this._bg &#038;&#038; this._bg.draw(ctx, this._size);

    //スプライト描画
    for (var i = 0; i < this._sprites.length; i++) {
        this._sprites[i].draw(ctx, this._size);
    }

    //前景描画
    this._fg &#038;&#038; this._fg.draw(ctx, this._size);

    //情報レイヤー描画
    this._ig &#038;&#038; this._ig.draw(ctx, this._size);

    this.drawing = false;
},
</pre>
<h3>TETRISクラス</h3>
<p>TETRISクラスは、分析・設計では[<<場>>ゲーム]として抽出されたクラスです。<br />
ゲームの進行を管理して、ステージやテトリミノなどのインスタンスを保持します。</p>
<h4>初期化</h4>
<p>インスタンスの作成時に背景やステージなどの設定を行います。</p>
<pre>
DQ.TETRIS = function (engine) {
    this._engine = engine;
    this.next = [];
    this._next7 = [];
    //ステージを作成
    this.stage = new DQ.TETRIS.Stage(engine);
}
DQ.TETRIS.prototype = {
  initialize: function () {
    //ステージをスプライトとして追加
    var stage = new DQ.Screen.Canvas.Sprite({
        y: 0,
        x: 0,
        width: 320,
        height: 320,
        animation: false,
        numberOfPause: 0,
        image: stageImg.client[0]
    });
    //背景を設定
    var bg = new DQ.Screen.Canvas.BG({
        width: bgImg.width(),
        height: bgImg._height,
        image: bgImg.client[0]
    });
    this._engine._canvas.push(stage);
    this._engine._canvas.bg(bg);
    ...
  }
}
</pre>
<h4>テトリミノの作成</h4>
<p>次のテトリミノの作成はwikiによれば、おおよそ以下の通りです。<br />
<BLOCKQUOTE>あらかじめ重複しないように７つのテトリミノを決定します。そして、その７つのテトリミノを使い切ると次の７つのテトリミノを決定します。</BLOCKQUOTE><br />
このルールを元に次のテトリミノ決定ルーチンを作成します。<br />
画面に表示する３つのテトリミノを取得するようになっています。</p>
<pre>
{
    _next7: [],
    _genNextTetrimino7: function () {
        var used = [false, false, false, false, false, false, false];
        this._next7 = [];
        for (var i = 0; i < 7; i++) {
            while (true) {
    var candidate = Math.floor(Math.random() * 7);
    if (i &lt; 2 &#038;&#038; (candidate == DQ.TETRIS.TetriminoFactory.DIR.S || 
                  candidate == DQ.TETRIS.TetriminoFactory.DIR.Z)) {
        continue;
    }
    if (used[candidate]) {
        continue;
    }
    used[candidate] = true;
    this._next7.push(candidate);
    break;
            }
        }
    },
    genNextTetrimino: function () {
        //上限 MAX_NEXT分(3つ)だけ、次のテトリミノを作成する
        for (var i = this.next.length; i &lt; DQ.TETRIS.MAX_NEXT; i++) {
            //7つのテトリミノがなければ作成
            this._next7.length == 0 &#038;&#038; this._genNextTetrimino7();

            //テトリミノのインスタンスを作成
            var mino = DQ.TETRIS.TetriminoFactory.create(this._next7.shift());
            mino.setCanvas(this._engine._canvas);

            this.next.push(mino);
        }

        //待機位置へ移動
        for (var i = 0; i &lt; DQ.TETRIS.MAX_NEXT; i++) {
            this.next[i].to(DQ.TETRIS.NextPos[i].x, DQ.TETRIS.NextPos[i].y);
        }
    }
}
</pre>
<h4>落下テトリミノの作成</h4>
<p>ゲームを開始すると、待機しているテトリミノが落下するテトリミノへと移行します。</p>
<pre>
{
    shiftCurrent: function () {
        //待機中のテトリミノの先頭を落下中のテトリミノに移行
        this.current = this.next.shift();

        //ステージの最上部へ移動
        this.current.to(DQ.TETRIS.STAGE_LEFT + DQ.TETRIS.CHIP_SIZE * 3, this.stage.top);
        if (this.hitTest(0, 0)) {
            //開始位置で衝突するなら終了
            this.gameOver();
            return;
        }

        //減った分だけ次のテトリミノを作成します。
        this.genNextTetrimino();

        //ゴーストを作成
        this.ghost &#038;&#038; this.ghost.remove();
        this.ghost = DQ.TETRIS.TetriminoFactory.createGhost(this.current);
        this.ghost.setCanvas(this._engine._canvas);
        //落下中のテトリミノと位置合わせ
        this.ghost.to(DQ.TETRIS.STAGE_LEFT + DQ.TETRIS.CHIP_SIZE * 3, this.stage.top);

        this.moveGhost();
    }
}
</pre>
<h4>落下処理</h4>
<p>無操作の状態で、テトリミノはレベルに応じて落下していきます。<br />
落下する量の計算は次の様になります。</p>
<pre>
{
    calcGDY: function () {
        this.gdy = this.g * DQ.TETRIS.CHIP_SIZE / this.fps;
        //1chip分/framを最大値とする(hitTest()が対応していないので）
        this.gdy = this.gdy &gt; DQ.TETRIS.CHIP_SIZE ? DQ.TETRIS.CHIP_SIZE - .1 : this.gdy;
    }
}
</pre>
<p>TETRISクラスの<code>update()</code>もFPSに従って定期的に呼び出されます。</p>
<pre>
{
    update: function() {
        var dy = this.gdy;
        //当たり判定
        if (this.hitTest(0, dy + DQ.TETRIS.CHIP_SIZE)) {
            //「遊び」に移行
            this.game = DQ.TETRIS.Mode.Delay;
            this._elapse = 0;
            this.stopAccelerate();
            //下に移動
            this.current.move(0, dy);
            //描画上のずれを補正
            this.current.fit();
        } else {
            this.current.move(0, dy);
        }
}
</pre>
<p><a href="http://plusb.jp/blog/?p=760">次はStageクラス他</a></p>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=709</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>dq(rpg) 2011-07-21</title>
		<link>http://plusb.jp/blog/?p=710</link>
		<comments>http://plusb.jp/blog/?p=710#comments</comments>
		<pubDate>Thu, 21 Jul 2011 16:37:05 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[dq]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[ゲーム作成]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[rpg]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=710</guid>
		<description><![CDATA[ナイトリービルドを更新。 ロトの鎧を実装しました。 これまでロトの鎧を実装しようとして、手が止まっていました。ロトの鎧を装備すると沼のダメージが無くなり、魔法系のダメージが半減されます。 使い捨てのコードならダメージ処理 &#8230; <a href="http://plusb.jp/blog/?p=710">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>ナイトリービルドを更新。<br />
ロトの鎧を実装しました。<br />
<span id="more-710"></span><br />
これまでロトの鎧を実装しようとして、手が止まっていました。ロトの鎧を装備すると沼のダメージが無くなり、魔法系のダメージが半減されます。<br />
使い捨てのコードならダメージ処理でハードコーディングすれば良いのですが、フレームワークとして出来れば汎用的に実装したい。<br />
たぶん、ダメージ判定後に装備に対して補正を要求すれば良いのかな。</p>
<pre>
DQ.RPG.DamageType = { Unknown: 0, Pysical: 1, Magic: 2, Fire: 3, Water: 4, Erth: 5, Wind: 6, Sander: 7, Light: 8, Dark: 9, Swamp: 10, Baria:11 }
Player.prototype.gainDamage = function(damage, type) {
   for(var i = 0 ; i &lt; this._equipmentIDs.length ; i++ ) {
       var equip = world.items[this._equipmentIDs[i].uid];
       damage = equip.gainDamage(damage, type);
   }
   return damage;
}

storategys['roro'] = roro_storategy;

roro_storategy.prototype.gainDamage = function(damage, type) {
   var dm = DQ.RPG.DamageType;
   swich(type) {
       dm.Magic:
       dm.Fire:
           dm /= 2;
           break;
       dm.Swamp:
       dm.Baria:
           dm = 0;
           break;
   }
   return dm;
}
</pre>
<p>沼なら</p>
<p>・・・それから３日後</p>
<p>装備することで一時状態を追加すれば、良いのではないでしょうか。<br />
呪われた装備なら、カースを追加。カース状態中は装備を外せないが、カースを解除されると装備も外せると。</p>
<p>「浮いている」なら、スパイクや沼やバリア無効。</p>
<p>ロトを装備している「状態」なら魔法や火を半減、ダメージを受けるチップ（沼、バリア）無効。</p>
<p>装備に equipメソッドとremoveメソッドを追加します。</p>
<pre>
DQ.RPG.Item.prototype = {
  equip: functon(type, to) {
    to.temporary.push(
        new DQ.RPG.State(world.statuses.find("uid", 10009)));
  },
  remove: function() {
  }
}
</pre>
<p>特殊な装備は装備したときに状態を追加します。</p>
<p>DQ1では、呪われていると王様の台詞が変化します。呪われたらフラグを立てる方法が単純ですが、<br />
プレイヤーが呪われた状態かを調べる方法もありです。</p>
<pre>
Player.hasStatus = function(uid) {
}
</pre>
<p>チップによるイベントでは、状態によるisAvoid()判定とgainDamage()判定を実施します。<br />
スパイクでのダメージの場合、luckにより回避が発生する仕組みも実装できます。</p>
<pre>
Player.prototype.isAvoid(type) {
}
Player.prototype.gainDamage(dmg, type) {
}

Status.prototype.isAvoid(type) {
}
Status.prototype.gainDamage(dmg, type0 {
}
</pre>
<p>標準で提供されていない状態や装備は後から追加可能にします。<br />
今でも、種類毎にストラテジーを選択する仕組みが実装されていますが、いっそのことUID別の<br />
テーブルがあれば、そこからストラテジーを選択出来るようにして拡張毎のストラテジーを後から<br />
追加出来るようにすればよいのではないでしょうか。</p>
<pre>
DQ.RPG.State.Roro = function() {
}
DQ.RPG.State.table.push({uid: 10009, strategy: DQ.RPG.State.Roro});
</pre>
<p><a href="http://plusb.jp/dqfw/">ナイトリービルド</a>を更新。<br />
<a href="http://plusb.jp/dqfw/samples/rpg_learning.html">RPG 習作</a>(<a href="http://plusb.jp/dqfw/samples/rpg_learning.html?debug=true">debug</a>)<br />
<a href="http://plusb.jp/dqfw/samples/bt_test.html">戦闘テスト</a><br />
<a href="http://plusb.jp/dqfw/samples/message_editor.html">メッセージエディター</a></p>
<p>補足ですが、キャッシュが効いている場合に<code>CTRL+R</code>などでページを再読み込みする必要があります。</p>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=710</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>テトリスをJavaScriptで作る 実装編(1)</title>
		<link>http://plusb.jp/blog/?p=699</link>
		<comments>http://plusb.jp/blog/?p=699#comments</comments>
		<pubDate>Mon, 18 Jul 2011 08:43:23 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[ゲーム作成]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Tetris]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=699</guid>
		<description><![CDATA[設計を元に実装していきます。 ソース:tetris.js ライブラリー:dq-rtg.js,dq-cancas.js(実際に動かすにはライブラリのコアコンポーネントとjQueryも必要です）。 できあがり 状態管理 常に &#8230; <a href="http://plusb.jp/blog/?p=699">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p><a href="http://plusb.jp/blog/?p=682">設計</a>を元に実装していきます。<br />
ソース:<a href="http://plusb.jp/dq/samples/js/tetris.js">tetris.js</a><br />
ライブラリー:<a href="http://plusb.jp/dq/js/rtg/dq-rtg.js">dq-rtg.js</a>,<a href="http://plusb.jp/dq/js/dq-canvas.js">dq-cancas.js</a>(実際に動かすにはライブラリのコアコンポーネントとjQueryも必要です）。<br />
<a href="http://plusb.jp/blog/?p=694">できあがり</a><br />
<span id="more-699"></span></p>
<h3>状態管理</h3>
<p>常にタイマーからの更新要求が飛んでくるので、ゲームの状態を用意して描画を少し管理することにします。</p>
<h4>ゲーム状態</h4>
<p>Start:<br />
 &#8220;Push A Button&#8221; を表示して、ゲームの開始を待っている状態</p>
<p>Play:<br />
 ゲーム進行中、落下中のテトリミノを落としたり、キー操作を画面に反映します。</p>
<p>Pause:<br />
 ゲーム進行中ですが、落下などの進行を中断します。</p>
<p>Erase:<br />
 ラインの削除演出を表示中です。<br />
 テトリミノの落下が抑止されます。</p>
<p>GameOver:<br />
 &#8220;Game Over&#8221; が表示されます。</p>
<h4>ライン削除</h4>
<p>演出の状態を管理します。<br />
ライン削除演出の状態を管理します。</p>
<p>None:<br />
 落下中ではない</p>
<p>Flash:<br />
 落下対象のラインを光らせます。</p>
<p>Erase:<br />
 落下対象のラインが消えます。</p>
<p>Down:<br />
 落下対象のラインを落とします。</p>
<h3>実装モデル</h3>
<p>設計を元に、クラスを作成します。</p>
<p>実装用に作成したクラスは以下の通りです。</p>
<ol>
<li>TETRIS:ゲーム全体を管理</li>
<li>Stage: ステージ上のイベントを処理</li>
<li>Line: 各ラインの状態を管理</li>
<li>Tetrimino: 落下中やNextなどのテトリミノを管理</li>
<li>TetriminoFactory: Tetriminoの作成を管理</li>
</ol>
<p>[TETRIS]+-ステージ[Stage]<br />
[TETRIS]-進行管理[Engine]<br />
[TETRIS]+-current[Tetrimino]<br />
[TETRIS]+-next[Tetrimino]</p>
<p>[Stage]+-[Line]<br />
[Line]+chip[Sprite]</p>
<h4>画像</h4>
<p>下準備として、ステージやチップ（粒）の画像を用意します。<br />
背景<br />
<a href="http://plusb.jp/blog/wp-content/uploads/2011/07/tetris_bg.jpg"><img src="http://plusb.jp/blog/wp-content/uploads/2011/07/tetris_bg.jpg" alt="テトリス背景" title="tetris_bg" width="320" height="320" class="alignnone size-full wp-image-700" /></a><br />
粒<br />
<a href="http://plusb.jp/blog/wp-content/uploads/2011/07/block.png"><img src="http://plusb.jp/blog/wp-content/uploads/2011/07/block.png" alt="粒" title="block" width="14" height="112" class="alignnone size-full wp-image-701" /></a><br />
ステージ<br />
<a href="http://plusb.jp/blog/wp-content/uploads/2011/07/stage.png"><img src="http://plusb.jp/blog/wp-content/uploads/2011/07/stage.png" alt="ステージ" title="stage" width="320" height="320" class="alignnone size-full wp-image-704" /></a><br />
フラッシュ<br />
<a href="http://plusb.jp/blog/wp-content/uploads/2011/07/flash.png"><img src="http://plusb.jp/blog/wp-content/uploads/2011/07/flash.png" alt="削除前のフラッシュ" title="flash" width="140" height="14" class="alignnone size-full wp-image-702" /></a></p>
<h4>テトリミノの作成</h4>
<p>テトリミノは全て4つの粒で構成されています。<br />
それぞれのテトリミノの粒の位置を配列で準備します。<br />
単純なI型は、次の様になります。９０度づつ回転するので種別ごとに４つのデータを持ちます。</p>
<pre>
        [ //I
            [[0, 1], [1, 1], [2, 1], [3, 1]],
            [[1, 0], [1, 1], [1, 2], [1, 3]],
            [[0, 2], [1, 2], [2, 2], [3, 2]],
            [[2, 0], [2, 1], [2, 2], [2, 3]]
        ],
</pre>
<p>この情報を元にスプライトを作成します。</p>
<pre>
    create: function (type) {
        var chips = types[type][0]; //指定された型の先頭の粒リストを取得
        var sprites = [];
        for (var i = 0; i &lt; chips.length; i++) {
            sprites.push(
                new DQ.Screen.Canvas.Sprite({
                    image: chipImg.client[0],
                    x: chips[i][0] * DQ.TETRIS.CHIP_SIZE,
                    y: chips[i][1] * DQ.TETRIS.CHIP_SIZE,
                    width: DQ.TETRIS.CHIP_SIZE,
                    height: DQ.TETRIS.CHIP_SIZE,
                    dir: type
                })
            );
        }
        //４つのスプライトを元にグループを作成
        var group = new DQ.Screen.Canvas.SpriteGroup(sprites);
        return new DQ.Tetrimino(type, group);
    }
</pre>
<p>Spriteは座標とイメージを保持していてCanvasクラスから渡されたコンテキストを元に以下の様な感じで描画しています。</p>
<pre>
  Sprite.prototype = {
        draw: function (ctx) {
            var x = this.x;
            var y = this.y;
            var w = this.width, h = this.height;
            ctx.drawImage(this.image, 0, this.dir * h, w, h, Math.floor(x), Math.floor(y), w, h);
        }
    }
</pre>
<p>テトリミノの作成は専用のクラスを用意しておいて、テトリミノ自身からは分離しておきます。<code>createGhost()</code>や<code>rotate()</code>は必要に応じて後で説明します。</p>
<pre>
DQ.TETRIS.TetriminoFactory = {
    DIR: { I: 0, O: 1, S: 2, Z: 3, J: 4, L: 5, T: 6, G: 7 },
    types: [
        [ //I
            [[0, 1], [1, 1], [2, 1], [3, 1]],
            [[1, 0], [1, 1], [1, 2], [1, 3]],
            [[0, 2], [1, 2], [2, 2], [3, 2]],
            [[2, 0], [2, 1], [2, 2], [2, 3]]
        ],
        [ //O
            [[1, 0], [1, 1], [2, 0], [2, 1]],
            [[1, 0], [1, 1], [2, 0], [2, 1]],
            [[1, 0], [1, 1], [2, 0], [2, 1]],
            [[1, 0], [1, 1], [2, 0], [2, 1]]
        ],
        [ //S
            [[0, 1], [1, 1], [1, 0], [2, 0]],
            [[1, 0], [1, 1], [2, 1], [2, 2]],
            [[2, 1], [1, 1], [1, 2], [0, 2]],
            [[0, 0], [0, 1], [1, 1], [1, 2]],
        ],
        [ //Z
            [[0, 0], [1, 0], [1, 1], [2, 1]],
            [[2, 0], [2, 1], [1, 1], [1, 2]],
            [[0, 1], [1, 1], [1, 2], [2, 2]],
            [[1, 0], [1, 1], [0, 1], [0, 2]]
        ],
        [ //J
            [[0, 0], [0, 1], [1, 1], [2, 1]],
            [[1, 0], [1, 1], [1, 2], [2, 0]],
            [[0, 1], [1, 1], [2, 1], [2, 2]],
            [[1, 0], [1, 1], [1, 2], [0, 2]]
        ],
        [ //L
            [[0, 1], [1, 1], [2, 1], [2, 0]],
            [[1, 0], [1, 1], [1, 2], [2, 2]],
            [[0, 1], [1, 1], [2, 1], [0, 2]],
            [[1, 0], [1, 1], [1, 2], [0, 0]],
        ],
        [ //T
            [[0, 1], [1, 1], [2, 1], [1, 0]],
            [[1, 0], [1, 1], [1, 2], [2, 1]],
            [[0, 1], [1, 1], [2, 1], [1, 2]],
            [[1, 0], [1, 1], [1, 2], [0, 1]]
        ]],
    create: function (type) {
        var chips = DQ.TETRIS.TetriminoFactory.types[type][0];
        var sprites = [];
        for (var i = 0; i &lt; chips.length; i++) {
            sprites.push(
                new DQ.Screen.Canvas.Sprite({
                    image: chipImg.client[0],
                    x: chips[i][0] * DQ.TETRIS.CHIP_SIZE,
                    y: chips[i][1] * DQ.TETRIS.CHIP_SIZE,
                    width: DQ.TETRIS.CHIP_SIZE,
                    height: DQ.TETRIS.CHIP_SIZE,
                    dir: type,
                    animation: false,
                    numberOfPause: 0
                })
            );
        }
        var group = new DQ.Screen.Canvas.SpriteGroup(sprites);
        return new DQ.Tetrimino(type, group);
    },
    createGhost: function (mino) {
        var chips = DQ.TETRIS.TetriminoFactory.types[mino.type][0];
        var sprites = [];
        for (var i = 0; i &lt; chips.length; i++) {
            sprites.push(
                new DQ.Screen.Canvas.Sprite({
                    image: chipImg.client[0],
                    x: chips[i][0] * DQ.TETRIS.CHIP_SIZE,
                    y: chips[i][1] * DQ.TETRIS.CHIP_SIZE,
                    width: DQ.TETRIS.CHIP_SIZE,
                    height: DQ.TETRIS.CHIP_SIZE,
                    dir: DQ.TETRIS.TetriminoFactory.DIR.G,
                    animation: false,
                    numberOfPause: 0
                })
            );
        }
        var group = new DQ.Screen.Canvas.SpriteGroup(sprites);
        return new DQ.Tetrimino(mino.type, group);
    },
    rotate: function (mino, dir, ndir) {
        var pre = DQ.TETRIS.TetriminoFactory.types[mino.type][dir];
        var pos = DQ.TETRIS.TetriminoFactory.types[mino.type][ndir];
        for (var i = 0; i &lt; mino._group._member.length; i++) {
            var sp = mino._group._member[i];
            var cx = sp.x - pre[i][0] * DQ.TETRIS.CHIP_SIZE;
            var cy = sp.y - pre[i][1] * DQ.TETRIS.CHIP_SIZE;
            cx += pos[i][0] * DQ.TETRIS.CHIP_SIZE;
            cy += pos[i][1] * DQ.TETRIS.CHIP_SIZE;

            sp.x = cx;
            sp.y = cy;
        }
    }
}
</pre>
<p><a href="http://plusb.jp/blog/?p=709">続く</a></p>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=699</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>テトリスをJavaScriptで作る</title>
		<link>http://plusb.jp/blog/?p=694</link>
		<comments>http://plusb.jp/blog/?p=694#comments</comments>
		<pubDate>Mon, 18 Jul 2011 05:39:38 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[ゲーム作成]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Tetris]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=694</guid>
		<description><![CDATA[とりあえず、作りました。 wikiを見た事で、最低レベルのハードルをあげてしまったので時間がかかってしまいました。 実装の解説は後で書きます。 ルールがシンプルなだけあって1000ステップにも到達しなかったのはびっくりで &#8230; <a href="http://plusb.jp/blog/?p=694">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>とりあえず、作りました。<br />
wikiを見た事で、最低レベルのハードルをあげてしまったので時間がかかってしまいました。<br />
実装の解説は後で書きます。<br />
<span id="more-694"></span><br />
ルールがシンプルなだけあって1000ステップにも到達しなかったのはびっくりです。ただ、もう少しちゃんとした物にするためにはスーパーローテーションには対応する必要がありそうです。</p>
<p>ソース:<a href="http://plusb.jp/dq/samples/js/tetris.js">tetris.js</a></p>
<p><a href="http://plusb.jp/dq/samples/tetris.html">tetris.html</a><br />
フレーム内を一度クリックするとキーが効くようになります。十字キーに対応しています。<br />
Aボタンは&#8217;V'キー<br />
Bボタンは&#8217;C'キー<br />
です。<br />
<iframe src="http://plusb.jp/dq/samples/tetris.html" width="320" height="420" style="overflow: hidden;"></iframe><br />
<a href="http://plusb.jp/blog/?p=682" title="設計編">設計編</a><br />
<a href="http://plusb.jp/blog/?p=699" title="実装編">実装編(1)</a></p>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=694</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>テトリスをJavaScriptで作る 分析、設計編</title>
		<link>http://plusb.jp/blog/?p=682</link>
		<comments>http://plusb.jp/blog/?p=682#comments</comments>
		<pubDate>Thu, 14 Jul 2011 14:28:07 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[ゲーム作成]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[テトリス]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=682</guid>
		<description><![CDATA[テトリスをJavaScriptでまじめに作る。 連休に併せて、ちょいと作成したcanvasライブラリーの調整のためにテトリスを作ってみようと思います。 リアルタイムなゲームで簡単に作れる定番？といえばテトリスですよね。せ &#8230; <a href="http://plusb.jp/blog/?p=682">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>テトリスをJavaScriptでまじめに作る。<br />
連休に併せて、ちょいと作成したcanvasライブラリーの調整のためにテトリスを作ってみようと思います。<br />
リアルタイムなゲームで簡単に作れる定番？といえばテトリスですよね。せっかくなのでOOでまじめに設計してみたいと思います。<br />
<span id="more-682"></span><br />
<span style="color: Red">2011/7/18 <a href="http://ja.wikipedia.org/wiki/%E3%83%86%E3%83%88%E3%83%AA%E3%82%B9">Wiki</a>を元に記述を修正</span><br />
ちなみにいつもblog用のダイアグラムは<a href="http://www.yuml.me/diagram/scruffy;scale:75/class/draw">yUML</a>を活用していますが、今日は非常に重たいので後で変換します。<br />
<a href="http://plusb.jp/blog/?p=694">できあがり</a></p>
<h3>1.分析</h3>
<h4>1.1 シナリオ</h4>
<p>　ゲームの内容をシナリオとして簡単に記述します。</p>
<h4>1.1.1 ゲームを始める</h4>
<p>　ゲームの開始を促す表示がされていて、ボタンを押すとゲームが開始される。<br />
　最初は何も無いステージに様々な形状のブロックが上から落ちてくる。<br />
　ブロックは中央上部から落ちてくる。<br />
　ブロックが落下を始めると次のブロックが明示される<br />
  次のブロックは３つまで表示される。</p>
<h4>1.1.2 操作する</h4>
<p>　プレイヤーは落ちていくブロックを回転、あるいは左右に移動させながらステージの下に隙間無く埋めていく。<br />
　また、ブロックの落下速度をプレイヤーの操作によって落下させることが出来る。<br />
　（加速中はスコアが増加する）</p>
<h4>1.1.3 ラインを消す</h4>
<p>　ブロックが落ちた事で隙間無く埋まったラインは、消えてスコアーとなる。<br />
　同時に複数のラインを消すとスコアーは指数的に増加する。<br />
　ラインが消えると上のラインが下に落ちてくる<br />
（※ライン単位でしか下に落ちないので、ブロックの粒の下に空洞があっても粒単独で下に落ちたりはしない（つまり連鎖は無い））。</p>
<h4>1.1.4 レベルアップ</h4>
<p>　ゲームを進めてスコアーが一定以上になるとレベルが上がり、無操作状態でのブロックの落下速度が速くなる。<br />
　レベルアップと共に背景やＢＧＭに変化がある。</p>
<h4>1.1.5　ゲームオーバー</h4>
<p>　ブロックの落下口からブロックが落ちることが出来なければ、ゲームオーバーとなる。<br />
　ゲームオーバーになると、ゲームを終了するか、新しくゲームを始めるかの選択肢が表示される。</p>
<h4>1.1.6 その他と非機能要件</h4>
<ul>
<ol>
　ステージは縦20ライン、横10粒。
</ol>
<ol>
　落下表示は、一粒よりも細かい粒度で表現されること。
</ol>
<ol>
　横移動は粒単位で良い事とする。
</ol>
<ol>
　言語はJavaScript。</ol>
<ol>
　プラットフォームは Webブラウザー 及び HTML5 canvasとする。
</ol>
<ol>
　落下したブロックは見た目上ラインに接触していても回転や横滑り出来る猶予(遊び期間）を設ける。<br />
　「遊び中」に移動または回転すると、「遊び中」のカウントはクリアされる。
</ol>
<ol>
　操作はキーボード（もしくはバーチャルパッド）</ol>
</ul>
<h4>1.2 概念の抽出</h4>
<p>　前述のシナリオから名詞・動詞を拾う形で、思いつくままに概念を抽出してみます。<br />
　一つのテクニックとして、物、事、場の視点から抽出します。  </p>
<h4>1.2.1 物</h4>
<p>　プレイヤー<br />
<del datetime="2011-07-18T05:20:23+00:00">　ブロック</del>テトリミノ<br />
　　赤（縦棒）、青（凸型）、黄（四角）、緑（残りのやつ）<br />
　次の<del datetime="2011-07-18T05:20:23+00:00">ブロック</del>テトリミノ<br />
　粒（造語、ブロックを構成する一つ一つの四角を粒と呼ぶことにする）<br />
　ステージ<br />
　枠？<br />
　ライン<br />
  スコア<br />
　背景<br />
　BGM<br />
　ジングル<br />
　タイマー（暗黙の了解で追加）<br />
※ブロックはプレイヤーが操作しなくても「時々刻々」と落下していく。時々刻々、即ちインターバルタイマーの登場（これを重力と表現するかは人の好き好き）</p>
<h4>1.2.2 事</h4>
<p>　（ブロックが）落ちる<br />
　（ブロックが）加速する<br />
　（ブロックが）回転する<br />
　（ブロックが横に）移動する<br />
　（ブロックが）止まる（地面か、ラインにぶつかれば止まる）<br />
　（次のブロックを）決める<br />
　（レベルが）上がる<br />
　（スコアが）増える<br />
　（ラインが）消える<br />
　（ラインが）落ちる<br />
　（ゲームが）終わる<br />
　（ゲームが）始まる<br />
　（ステージを）クリアする<br />
　（BGMを）鳴らす</p>
<p>たまたまですが、どれもオブジェクトではなく振る舞いのようです。</p>
<h4>1.2.3 場</h4>
<p>　ゲーム</p>
<h4>1.3 概念モデル</h4>
<p> 抽出した概念から静的モデルを作成（知見を基にオブジェクトでは無く属性への落とし込みも行ってます）。<br />
[ゲーム|スコア;レベル|開始();終了();BGM再生();次ブロック決定()]<br />
[テトリミノ]+-[粒]<br />
[テトリミノ|タイプ(赤,青...)|落下();加速();回転();移動()]<br />
[ステージ]+-[ライン]<br />
[ ステージ||初期化()]<br />
[ライン]+-[粒]<br />
[ライン|行|消す();落とす()]</p>
<h4>1.4 シーケンス</h4>
<p>※下記のシーケンスの文法は独自なのでがんばって解釈してください。</p>
<h4>1.4.1 初期化</h4>
<p> ゲーム->背景.作成()<br />
 ゲーム->スコア.初期化()<br />
 ゲーム->レベル.初期化()<br />
 ゲーム->ステージ.作成()->ライン.作成()<br />
 ゲーム->&#8221;Push Start&#8221;.表示()<br />
 ゲーム->BGM.再生(オープニング)</p>
<h4>1.4.1 ゲーム開始</h4>
<p>  ゲーム->ステージ.クリア()->ライン.クリア()<br />
  ゲーム.次のテトリミノを決定()<br />
  ゲーム->テトリミノ:次.作成()<br />
  ゲーム.:次を落下するテトリミノへ移動()</p>
<h4>1.4.2 プレイヤーなどによる操作</h4>
<p>  プレイヤー->テトリミノ.加速()<br />
  プレイヤー->テトリミノ.移動()<br />
  プレイヤー->テトリミノ.回転()<br />
  タイマー->テトリミノ.落下()<br />
  タイマー->底から順番に|ライン.消す()※但し、消せるなら<br />
  タイマー->ライン.落とす()※但し、落ちるなら</p>
<p>思いつくままに書くとこうなるが、自明なので以下に修正</p>
<p>　タイマー->ゲーム.更新()->ブロック.落下(Level)　※落下出来なければ、ゲームオーバー<br />
　タイマー->ゲーム.更新()->スコア.更新(加速中?)<br />
　タイマー->ゲーム.更新()->底から順番に|ライン.消す()※但し、消せるなら<br />
　タイマー->ゲーム.更新()->スコア.更新(ライン数)<br />
　タイマー->ゲーム.更新()->底から順番に|ライン.落とす()※但し、落ちるなら<br />
　　　　　　　　　　　　　<br />
ここで気になるのがラインを消す演出です。ラインがそろうと、パッと光って、ポンと消えて、それからバスッと落ちます。<br />
これを表現するためにはラインには状態管理が必要です。</p>
<p>通常->消せる(光ってる)->消した ※ライン自体が消えるのか、ライン上の粒だけがいなくなるのかは実装のお話。</p>
<h4>1.4.3 ゲームオーバー</h4>
<p>  ゲーム->&#8221;Game Over&#8221;.表示()<br />
  ゲーム->選択肢.表示()</p>
<h3>2. 設計</h3>
<p>概念モデルでは当然、プラットフォームやアーキテクチャーには依存していないので、ここでモデルを少し具体化します。</p>
<h4>2.1 アーキテクチャー</h4>
<p>　設計モデルに入る前に、アーキテクチャーの考察をしておきます。<br />
　まず、画面表示にはHTML5 canvasを使用します。canvasへの描画については、自前のライブラリーを使用します。<br />
　この時点で「背景」、「前景」、「スプライト」のオブジェクトが登場します。<br />
　背景には背景を、前景にはステージを表示します。スプライトは一粒、1スプライトとします。</p>
<p>　描画は設定されたFPSに基づいて発生するインターバルタイマー毎に画面をクリア、更新します。<br />
　一粒は14px,14pxとします。<br />
　<br />
　テトリミノの「遊び」の表現は状態遷移モデルで管理します。<br />
  [落下中]->[遊び中]<br />
  [遊び中](移動または、タイムアウト)->[落下中]</p>
<h4>2.2 設計モデル</h4>
<p>　(ドメイン)モデルとビューの分離は難しく考え無い事にします。<br />
   全く分離しないなら、「自分のことは自分でする」という振る舞いの配置原則に従って、モデル自身が画面への描画責務を負います。まあ、それは現実解ではないでしょう（たぶん）。</p>
<p>（モデル）<br />
　[粒]->[スプライト]->[イメージ]　※このイメージはCSSスプライトとします。<br />
  [ステージ]->[イメージ]　※ステージのイメージ（枠）は一枚絵<br />
  [背景]->[イメージ]　　　※背景も一枚絵<br />
  [BGM]->[Audio]　　※このAudioはHTML Audio を想定</p>
<p>  プレイヤーは現実的にキー入力とします。<br />
(シーケンス)<br />
　キー入力->ブロック.回転()</p>
<p>  テトリミノは、回転や落下に伴い、スプライトの座標を更新します。<br />
　一般にモデルとビューは分離する物とされています。それを守るならコントローラーかスプライト側がモデルであるテトリミノを参照するべきです。<br />
　まあ、ここは適当に行きましょう（気になれば後で修正すればＯＫです）。</p>
<p>（モデル）<br />
　[キャンバス]->[スプライト]<br />
　[キャンバス]->[canvas]</p>
<p>  キャンバスには全てのスプライトへの参照を保有させます。<br />
　と言うことは、次テトリミノの作成や次テトリミノを落下テトリミノへ移行した場合にスプライトをキャンバスへ登録したり、<br />
　逆にラインが消えると該当するスプライトをキャンバスから削除する必要があります。</p>
<p>（モデル）<br />
  [キャンバス||登録(スプライト);削除(スプライト)]<br />
　[ゲーム]->[テトリミノ:次]<br />
　[ゲーム]->[テトリミノ:落下中]</p>
<p>（シーケンス）<br />
  ゲーム->ブロック:次.作成()<br />
  ゲーム->キャンバス.スプライト登録(:次.スプライト群)</p>
<p>  次のブロックから、落下ブロックへの昇格時はスプライトをそのまま引き継いで、座標だけを変更する事にします。<br />
（シーケンス）<br />
  ゲーム->:次.昇格()->スプライト.移動()<br />
　<br />
　描画は一連の更新作業が済んだ後に実施します。</p>
<p>（シーケンス）<br />
  タイマー->ゲーム.更新()<br />
  タイマー->キャンバス.更新()</p>
<p>  このゲームの実装上のトピックとしては、粒の当たり判定と回転によるブロックの表示切り替えでしょうか。<br />
  これは、実装時にはっきりさせることにします。</p>
<h3>3. イテレーション</h3>
<p>　最初のイテレーションでどこまで実装しましょうかね。<br />
　とりあえず、スコアとレベルの実装は無し。<br />
　ＢＧＭも無し。<br />
　ラインが消える際の演出も無し。<br />
　<br />
　ブロックが落下できるまでとかけちくさいことは言わず、ゲームとして成立するレベルまでは仕上げることにします。</p>
<p><a href=" http://plusb.jp/blog/?p=699 " title="実装編その１">実装編その１</a></p>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=682</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
