Canvasの描画機能で、ゲーム中の台詞や説明を表示するためのメッセージ表示ウインドウを作ってみます。とりあえず、今回は設定された文字列をウインドウの横幅に合わせて折り返し(改行し)ながら一画面で表示し、改ページは考えないことにしましょう。

メッセージ表示ウインドウは、白枠をつけた黒い長方形として描画し、その中に文字列を描いていきます。ゲームのスクリプトからも呼び出しやすいようJavaScriptのクラスとしてまとめてみました。

ウインドウの描画は、クラスの変数(パラメータ)x/yの位置に行います。描画用メソッドdraw()に描画用のCanvasコンテキストを渡すと、そのコンテキストのx/yの座標位置を基準に描画するようにしてみました。

draw()では、まずウインドウ全体をfillRect()で白く塗りつぶし、その後枠の部分を除いて黒く塗りつぶします。こうすることで「白枠を持つ黒い長方形」を描画し、その内部に表示するメッセージ文字列を格納する文字列配列linesの各行(各要素)をfillText()で描いていく形にしました。

ウインドウに描画する文字列は、ウインドウクラスのsetText()で設定します。setText()は、渡された文字列をウインドウの横幅にあわせて行に分割し、配列linesに格納する関数です。

文字列を行に分割する際には、文字列を一文字ずつ取り出しては行文字列に追加し、描画時の大きさを取得するmeasureText()で横幅を調べています。measureText()で指定コンテキストに文字列が描画された時の横幅を取得して、それがテキストを描画する領域の横幅を超えたらその直前の文字までを一つの行とするわけです。

また、メッセージ中に改行を入れたくなることもあるでしょうから「<:br>」という文字列があれば無条件に改行するようにもしてみました。

では、実際にメッセージ表示ウインドウをテストしてみましょう。青い背景にウインドウが表示されていますが、「テキスト設定」ボタンをクリックすると下のテキスト欄の文字列が表示メッセージとして設定されます。



JavaScriptコードとHTMLは、以下のとおりです。

<div style="text-align: center;">
<canvas id="testCanvas" width="300" height="180" style="background: #0000cc;"></canvas><br>
<textarea id="testText" rows="6" style="width: 290px;"></textarea><br>
<button id="testButton" onClick="setText()" disabled>テキスト設定</button>
</div>

<script>

// メッセージ表示ウインドウクラス
var MessageWindow = function() {

	// 表示位置
	var x, y;

	// 表示サイズ
	var width, height;

	// 枠の太さ
	var borderWidth;

	// テキスト領域の幅
	var drawWidth;

	// テキスト領域左上端座標
	var drawX, drawY;

	// テキスト領域余白
	var textPadding;

	// テキスト
	var lines = null;

	// フォント
	var font;

	// 行の高さ
	var lineHeight;

	// 初期化
	this.init = function() {

		// フォントに等幅14ピクセルを指定
		this.font = "14px monospace";

		// 行高さ設定
		this.lineHeight = 16;

		// ウインドウ枠幅設定
		this.borderWidth = 1;

		// テキスト領域余白設定
		this.textPadding = 2;

	}

	// Canvas上表示位置設定
	this.setPosition = function(x, y) {

		// ウインドウ描画位置設定
		this.x = x;
		this.y = y;

		// テキスト描画位置設定
		this.drawX = x + this.borderWidth + this.textPadding;
		this.drawY = y + this.borderWidth + this.textPadding;

	}

	// ウインドウサイズ設定
	this.setSize = function(w, h) {

		this.width = w;
		this.height = h;

		// テキスト領域描画幅算出
		this.drawWidth = w - (this.borderWidth + this.textPadding) * 2;

	}

	// 表示テキスト設定
	this.setText = function(text, context) {

		context.font = this.font;

		this.lines = new Array();

		var line = '';
		var pos = 0;

		// テキスト描画領域の横幅に合わせて各行のテキスト作成
		while (pos < text.length) {

			// 改行指定が入るか横幅がテキスト領域を超えるまで文字追加
			while (pos < text.length && context.measureText(line + text.charAt(pos)).width < this.drawWidth) {

				if (text.indexOf('<:br>', pos) == pos) {

					pos += 5;

					break;

				} else {
					line = line + text.charAt(pos++);
				}

			}

			// 文字列を追加
			this.lines.push(line);

			line = '';

		}

	}

	this.draw = function(context) {

		// ウインドウ領域全体を白でクリア
		context.fillStyle = '#ffffff';
		context.fillRect(this.x, this.y, this.width, this.height);

		// 枠を残して黒でクリア
		context.fillStyle = '#000000';
		context.fillRect(this.x + this.borderWidth, this.y + this.borderWidth, this.width - this.borderWidth * 2, this.height - this.borderWidth * 2);

		// テキスト描画設定
		context.font = this.font;
		context.fillStyle = '#ffffff';
		context.textBaseline = 'top';

		if (this.lines == null || this.lines.length < 1) {
			return;
		}

		var i;

		// 各行のテキストを描画
		for (i = 0;i < this.lines.length;i++) {
			context.fillText(this.lines[i], this.drawX, this.drawY + i * this.lineHeight);
		}

	}

}

var testCanvas = document.getElementById('testCanvas');
var testContext;

var mesWin;

var testText = document.getElementById('testText');

testText.value = 'テストテキスト1行目。<:br>2行目。brタグ以外の改行は入れないでください。連続改行テスト<:br><:br>四行目。フォントは、スタイルシート形式で等幅を指定しています。';

if (testCanvas.getContext) {

	testContext = testCanvas.getContext('2d');

	// ウインドウオブジェクト作成
	mesWin = new MessageWindow();

	mesWin.init();

	// 表示領域設定
	mesWin.setPosition(20, 20);
	mesWin.setSize(260, 140);

	mesWin.draw(testContext);

	// テキスト設定ボタン有効化
	document.getElementById("testButton").disabled = false;

}

// テキスト設定ボタンクリック時
function setText() {

	// テキストエリアの文字列をメッセージとして設定
	mesWin.setText(testText.value, testContext);

	// ウインドウ再描画
	mesWin.draw(testContext);

}

</script>

創作プログラミングの街 > ゲーム開発室 > Webゲーム開発室