HTML5のゲーム開発向けフレームワークの乱立
昨今、HTML5のCanvas, WebGL, WebAudioAPiなど、Webフロントエンド技術でのゲーム開発に向いた技術が増えて、Webブラウザ向けのゲーム開発界隈が盛り上がりを見せています。
それに合わせて、JavaScriptによるゲーム開発向けフレームワークも広がりを見せ、どれを選べばいいか迷ってしまうほど、多くのフレームワークが登場しています。
習熟の道
しかし、HTML5ゲームの開発をする際にそういったフレームワークを使用することを選択した場合、CanvasやWebGLなどの特性を学ぶ他、そのフレームワークの使用方法や設計理念も学ぶ必要があり、目の前に登場する大きな要塞に立ちくらみを覚える人も居るかと思います。
「フロー体験」という考え方があり、技術の習熟においては、自分の現在の習熟レベルに合わせて技術を学習する必要があります。
もし「HTML5ゲーム開発自体の習熟レベルが低い」という場合、ベースとなっているCanvasやWebGL、さらにはJavaScriptやDOMなどの基礎知識すら習熟レベルが低いという状態では、フレームワークの使用方法や設計理念の学習というのは、フロー体験を妨げるものとなります。
「ただ散歩がしたかっただけなのに、歩き方トレーナーや健康講座、休憩の仕方の話など、色んな知識を押し付けられて萎えた……」みたいな状態になります。ただ散歩がしたかっただけなのに……。
関連キーワード:YAGNI
フルスクラッチという選択
そこで、フルスクラッチです。
フルスクラッチとは 【 full scratch 】 - 意味/解説/説明/定義 : IT用語辞典
既存のものを一切流用せずにまったく新規に開発すること。
フレームワークレスでゲーム開発することにより、必要な知識を最小限に抑えながら、学習を進める、という攻め方です。
あくまで学習を進めるための有効な攻め方の1つと考えるものであり、実際のプロダクト開発においては、有効な手段とならない場合もあるので注意が必要です。
しかし、これを一度体験すると、フルスクラッチで開発することに魅了されることでしょう。
Webブラウザはすでにある種のゲームエンジンである
私個人は、Webブラウザはすでにある種のゲームエンジンであると考えています。
UnityやUnreal Engineのような高級なゲーム開発向けツール群がWebブラウザに揃えられているわけではありませんが、DOMという仕組みや、各種APIがすでに高級なものであり(ここで言う”高級”は、OSの低レベルAPIを直接触る必要が無い層という意味)、JavaScriptというプログラミング言語自体も、メモリについて深く考慮しなくても良い高級なもの、という意味で、すでにゲーム開発を楽にする仕組みが用意されている、とも捉えることができます。
このへんについて感動するためには、一度CやC++で、フレームワークを使わずに直接OSのAPIを叩いてゲーム開発をしてみる経験が必要かもしれません。
また、昨今のモダンなWebブラウザには、高機能なデバッグツールが標準で備えられており、ゲーム開発の助けになります。
余談になりますが、ゲーム開発向けツールはゲームを実行させるためのエンジンとは別物になるべきだという考えを私は持っており、ツールとエンジンが仕様で深く結びついたようなオールインワンタイプのツールは好きになれません。
ゲーム開発向けツールは、そこで作成したデータがポータブル(オープンな仕様の特定のエンジンに依存しないデータフォーマット)になるべきです。そこに政治的事情が絡めば話は別ですが。
ではさっそくフルスクラッチでのゲーム開発をしてみましょう。
htmlファイルとjsファイルを用意する
というわけで、さっそくフルスクラッチでゲーム開発していきましょう。
まずはhtmlファイルです。index.html
ファイルを作成します。
<!DOCTYPE>
<html>
<head>
<title>ゲーム</title>
</head>
<body>
</body>
</html>
JavaScriptを実行するため、<script>
タグを追加しておきます。
:
<head>
<title>
<script src="main.js"></script>
</head>
:
実行されるjsファイルを用意し、基本的なコードを書きます。
window.addEventListener('load', init);
/**
* 初期化
*/
function init() {
// ここに初期化処理を書く
}
HTMLページが読み込まれたときに初期化処理が実行されるように、window.addEventListener('load', init)
で、init
関数が呼ばれるようにしています。
Canvasを用意する
<canvas>
タグを追加します。
:
<body>
<canvas id="maincanvas"></canvas>
</body>
:
JavaScript側でCanvasとRenderingContextを取り出して扱えるようにしておきます。
var canvas;
var ctx;
function init() {
canvas = document.getElementById('maincanvas');
ctx = canvas.getContext('2d');
}
Canvasのサイズを定義しておき、
var SCREEN_WIDTH = 800;
var SCREEN_HEIGHT = 600;
:
Canvasにサイズを設定します。
function init() {
:
canvas.width = SCREEN_WIDTH;
canvas.height = SCREEN_HEIGHT;
}
毎フレーム更新処理を作成する
毎フレーム更新処理用にWeb標準APIとしてrequestAnimationFrame
というメソッドが用意されています。
こちらはwindow
オブジェクトのメソッドとして用意され、window
オブジェクトはJavaScriptコンテキストのグローバルオブジェクトでもあるので、window.requestAnimationFrame
というようにwindow
を付けなくても呼び出すことができます。
グローバルオブジェクトについての参考記事
[JavaScript] グローバル変数とグローバルオブジェクトを取得する方法 - Qiita
requestAnimationFrame
の仕様については、以下が参考になります。
window.requestAnimationFrame - Web API インターフェイス | MDN
第1引数に関数を与えることで、次回フレームの更新が必要なタイミングで関数を呼んでくれます。
function init() {
:
requestAnimationFrame(update);
}
function update() {
requestAnimationFrame(update);
}
注意点としては、あくまで「次回フレームの更新が必要なタイミング」なので、更新処理毎に、また次回フレームの更新が必要なタイミングで関数を呼んでもらう必要があるため、毎フレームrequestAnimationFrame
を呼ぶ必要がある、という点です。
描画
描画が必要になる処理はrender
関数で処理することにします。
function update() {
:
render();
}
function render() {
// ここで描画処理する
}
描画については、毎フレームでCanvas全体を描画し直していく必要があるため、RenderContextのclearRect
メソッドを使って全体のクリアから行います。
function render() {
// 全体をクリア
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
clearRect
メソッドの仕様は、こちらが参考になります。
CanvasRenderingContext2D.clearRect() - Web API インターフェイス | MDN
これで基本的な準備は整いました。
ファイル全体は以下のようになります。
<!DOCTYPE>
<html>
<head>
<title>ゲーム</title>
<script src="main.js"></script>
<body>
<canvas id="maincanvas"></canvas>
</body>
</html>
var SCREEN_WIDTH = 800;
var SCREEN_HEIGHT = 600;
window.addEventListener('load', init);
var canvas;
var ctx;
function init() {
canvas = document.getElementById('maincanvas');
ctx = canvas.getContext('2d');
canvas.width = SCREEN_WIDTH;
canvas.height = SCREEN_HEIGHT;
requestAnimationFrame(update);
}
function update() {
requestAnimationFrame(update);
render();
}
function render() {
// 全体をクリア
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
長くなるので、また次回から続きを進めます。