こちらは、ドリコム Advent Calendar 2018 13日目の記事です。
前回は じぬ さんの みんな大好き目標設定の進め方 です。


初めまして、enza事業本部ゲーム開発部の青木です。
突然ですが、スマートフォンで遊ぶゲームといえば何を思い浮かべるでしょうか。
多くの方は、ストアに上がっているアプリをダウンロードしてから遊ぶものを
思い浮かべるのではないでしょうか。

それに対し、私たちはストアからダウンロードしなくてもスマートフォンで遊べる
HTML5とJavaScriptを使ったゲーム開発に挑戦しています。
今回は、もともとUnityエンジニアだった私がHTML5+JavaScriptによる
ゲーム開発に挑戦してみて感じたことをお伝えしたいと思います。
これを通じて少しでもHTML5+JavaScriptによる
スマートフォンゲーム開発に興味を持っていただけたら嬉しいです。

自己紹介

さて、HTML5+JavaScriptを紹介すると言っている筆者は何者かといいますと、
1年前まではUnityエンジニアとしてC#でプログラムを書いていました。
GUI上で画像を配置し、それを制御するプログラムを書き、そしてスマートフォンに
インストールしてデバッグをする…ごくごく普通のUnityエンジニアです。
そんな私が、今年の初めに突然「HTML5+JavaScriptに興味はないか?」とお誘いを受けて
今現在、スマートフォンのブラウザで遊べるゲーム開発に携わるようになりました。

初めてのHTML5ゲーム開発ということで、「やっぱりUnityより大変なのかな?」という
不安がありました。でも、その不安はすぐに杞憂だということを知りました。

すんなりとできたこと

不安なことで一番大きかったのが、「新しくたくさん覚えることがあるのではないか」
ということです。もちろん、HTML5もJavaScriptも初めてだったので覚えることは
少なからずありましたが、「ゲーム開発」という点においては必ずしも全てを一度に
習得する必要はなく、既に知っていることでもたくさんのことができました。

JavaScriptの文法

JavaScriptもC#も、C言語に似た文法であるため、特に言語仕様に混乱することなく
ゲームロジックの作成に集中することができました。
例えば、下記はよく例題として出されるFizzBuzz問題ですがJavaScriptを
知らない方でもすんなりと読めると思います。

const max = 30;
for (let i = 1; i <= max; i++) {
    if (i % 15 === 0) {
        console.log('Fizz Buzz');
    }
    else if (i % 3 === 0) {
        console.log('Fizz');
    }
    else if (i % 5 === 0) {
        console.log('Buzz');
    }
    else {
        console.log(i);
    }
}

また、最近ではECMAScript6(JavaScriptの標準規格)が導入されたことにより、
定数やクラスの定義、ラムダ式によりC#に近い形でかけるようになりました。

// クラス定義
class Penguin {
  // getter
  get isEating() {
    return this._isEating;
  }

  // setter
  set isEating(value) {
    this._isEating = value;
  }

  // コンストラクタ
  constructor() {
    this.isEating = false;
  }

  // メンバ関数定義
  Eat(somethingToEat, onFinish) {
    this.isEating = true;
    // eating...
    // finish!
    this.isEating = false;
    onFinish();
  }
}

// 定数定義
const taro = new Penguin();
// ラムダ式でコールバック指定
taro.Eat(fish, () => {
  console.log('ごちそうさまでした!');
});

データ

データの取り扱いに関してはJSONであれば、ほぼそのままJavaScriptのオブジェクトとして
使えるためむしろUnityよりも楽になりました。
そもそもJSONはJavaScriptのためのデータ構造なので、当然といえば当然ですね!

JSON

{
  "character": {
    "name": "taro"
  }
}

JavaScript

// これだけでJavaScriptのオブジェクトとして構成されるので、特別にクラス定義などは不要です
const data = JSON.parse(JSON文字列);
console.log(data.character.name); // taro

デバッグ

実は、私が最も不安だったのがデバッグです。
「明確な変数の型が無いJavaScript、どうやってデバッグすれば・・・?」
と思っていました。
しかし、Google ChromeやSafariであれば標準機能として開発用のツールが
用意されており、かつブレークポイントや変数書き換えなどアプリ開発とほぼ同じ感覚で
使うことができます。

Google Chromeの開発ツールスクリーンショット
Google Chromeのデバッグ機能

ゲーム開発全般の知識

私は現在PIXIJSを使っているのですが、「グローバル座標とローカル座標」や「テクスチャ」、
「シェーダ」といったゲームの基本概念はそのまま通じるため、「PIXIJSだから覚える」という項目は
あまりありませんでした。
また、内部でWebGL使っているので、OpenGLの知識が生きてきます。

HTML5ゲームで苦労したこと

ここまでは、普通のゲーム開発の知識さえあれば何とかなりそうということをご紹介しましたが、
ここからは苦労したことをご紹介します。

ブラウザ特有の事柄

例えば、Safariでは
ユーザーのアクションに関するコールバックを介さないとBGMやSEが鳴らせない
という制約があったりします。
そのため、初めて触った時には「何でBGMならないの?!」と驚いてしまいました。
他にも
・同時発音数(同時にいくつの音が鳴らせるか)
・ブラウザキャッシュが残り続けて表示が崩れる
ということがあったりします。
このあたりは現在私もまだ勉強中で、開発者側ではハンドリングしにくいことから
簡単だけど情報が少ないといったことがいくつかあります。
特にHTML5関連になるとまだまだ発展途上という感じでブラウザごとに挙動が微妙に違って
難しさを感じています。

JavaScriptは存在しないメンバへのアクセスをしてもエラーにならない

JavaScriptは存在しないメンバへアクセスした際は「undefined」という値になります。
この「undefined」は数値計算に利用したり文字列として結合したりしても
直ちにエラーになるわけではなく、特殊な値を結果として計算できてしまいます。
例えば、下記のようなコードを実行してもエラーにはなりません。

var test = { x: 1, y: 3 };
var added = test.z + test.y;      // xをzとタイプミス!
console.log('x + y is ' + added); // x + y is Nan

特に、複雑な計算をしている箇所では結果はおかしくなるけれど、エラーが出ないため
何が間違っているのか追うのが大変、ということが時々あります。

まとめ

簡単だったこと
・HTML5+JavaScriptでのゲーム開発であっても、Unityなど他のゲーム開発で
 得た知見がそのまま使用可能
・JavaScriptはC言語に似ているのでよくゲームで使われるプログラミング言語の
 文法を知っていればすんなり組める
・デバッグはブラウザに標準で搭載されている機能が優秀で不自由しない
苦労したこと
・ブラウザ特有の事柄が稀にあって知らないと対応できない
・エラーが発生しないが結果がおかしくなることがあるのでデバッグが大変

いかがでしょうか、こう見るとそこまで不安がらなくてもHTML5+JavaScriptで
ゲーム開発できる気がしてきたのではないでしょうか。
もし、少しでも興味がありましたらぜひ一緒に挑戦していきませんか?