tanaka's Programming Memo

プログラミングについてのメモ。

Unity1週間ゲームジャム「Space」に参加しました!

前回の【フロー】の回は不参加でしたが、1年生の皆さんの初参加タイミングだったので、自分もやらねばということで今回は参加しました。以下から遊べます。

ロ-α版- | 無料ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう

目次

学生さん作品

Unity1週間ゲームジャム2回目から学生さんを焚きつけ始めて、6回目の今回は一年生も参加して、以下の作品が揃いました。まだ3本ほど開発中のものがあるので、もう少し増えそうです。

  • 範囲チェッカー
    • 動くバーをタイミングよくスペースキーを押して止めて、ステージに広がる箱をなるべく小さい体積で囲んでいくゲームです。
  • ぶつかるな!
    • 飛んでくる障害物を避けながら前方に進んでいく避けゲーです。
  • いい旅、夢ごこち
    • 左右移動とジャンプ、ショットを駆使して、奥にいるボスにたどり着いてやっつけるゲームです。
  • 鰯!鰯!鰯!

個人的な目的

個人的な目的は以下でした。

  • これまで勢いだけでクリアできて深みがなかったので、攻略や中毒性がありそうなネタにしたい
  • 写真で素材を作ってどうなるか実験したい
  • アセットでお気に入りのキャラクターを登場させたい

できたのは上2つ。3つ目は未だにゲームが完成していないぐらいなので、一週間では盛り込めず見送りましたf^^; そしてやはり地味なことに・・・。

一週間の進捗

ツイッターから一週間を振り返ります。

初日 11/13(月)

ここからスタート。

まずはシーン遷移やオンラインランキング、BGMや効果音制御などの共通部分を準備します。基本的なものは用意済みなのでそれをコピーして終わり。

この時点で地味になりそうなのは察知していて、キャラクターを登場させようと考えてアセットも探していたのですが・・・。

画面の解像度も事前に決めておくと楽です。今回はiPhone SEを想定して、640x1136ピクセルを基準にしました( iPhone SE - 仕様 - Apple(日本) )。Canvasやゲーム画面の素材を、このピクセル数で設計していきます。

Main Cameraのサイズは、640x1136ではなく、64x113.6にしました。モデルが大きくなると影に影響が出るためです。然るべき設定をすれば動くと思いますが、Unityは大きすぎたり小さすぎるとあちこちに不具合が起きることがあるのでこうしました。

午前中でここまでやって、日野に講義へ。夜帰ってから作業再開です。

この時点では動きやプログラムはつけず、スプライトやモデルなどをシーンに並べてレイアウトや必要な演出を検討していきます。今回はスケッチブックの紙面や、鉛筆で描いた素材をiPhoneで撮影して、Photoshopで加工。それをスプライトに貼り付けて画面を作って、画面の雰囲気がわかったところで初日終了。

2日目

スコアの実装からスタート。紙に鉛筆で数字を書いて、iPhoneで撮影して、Photoshopで加工して素材を作りました。それをTextMesh Proで絵文字として表示するようにしました。

以上で基本的な画面レイアウトが完了したので、ゲーム作りに取り掛かりました。まずは自分の操作から。ボタンを押したら全角スペースが発射されるようにします。

全く目立ちませんが、ロは発射時に少しずつ現れるようになっています。ロの1枚のテクスチャーから、アルファー値を設定して以下のようなテクスチャーを生成しています。

f:id:am1tanaka:20171122221058p:plain

シェーダーでやればリアルタイムでメモリーも消費せずにできるので、いずれやってみたいなということで宿題です。

画面レイアウトが整ったので、Unity CollabotateとUnity Cloudを仕込んで、WebGLの動作確認をして2日目終わり。

3日目

この日は朝から夕方まで専門学校。通勤電車の中で、ロが揃ったかの判定を考えたりしてました。

放課後、有志で集まって開発作業をしました。質問に答えたり、ちょっかい出したりしつつなので、ややこしいステージデータを考えるのは難しかったので、見た目の調整をしました。スコア部分が貧弱だったので、ロールを置くことにしました。これでかなり画面が締まりました。また、凸凹をつけてみようと紙の画像からNormalマップを作って設定したのも成功でした。

帰宅後は、降りてくるロの内部ロジック作り。ブロックは、5x10の2次元配列で管理しています。一番上の段がどこかを表す変数を用意して、1段分下がると、その変数を更新して、参照位置を変えるということをしています。更新時に、一番下にブロックがあればゲームオーバーです。

4日目

午前中は家事で、作業は午後からでした。

ステージデータをTiledで作成して読み込みまでやったところで、今回はステージを自動生成してエンドレスで遊べるようにするべきじゃないかと思い至って、ボツにしました。

UnityではNormalマップが使えるけど、Phaserではどうだっけ、とかあれこれ考えていました。自分でシェーダーを書ければ、ノーマルマップの機能がなくても大丈夫だなということで、シェーダーに手を出す理由が増えてきました。

はい。気にしない。

マップ+滑らかスクロールは、開始点を基準点にして絶対座標で管理するのがセオリーです。久々のループさせるマップ構造で、そこをすっかり舐めて進めてしまいました。これが後々のトラブルにつながりました。改めて、スクロールものは絶対座標を持たせること!この日は解決を諦めて寝ました。

5日目

午後から専門学校なので、午前中作業。

寝ている間に解決の方針がまとまって、無事に動かせました。夜が更けて混乱していたら寝るに限ります。

放課後に自主活動をして、帰宅してさらに少し作業をしました。ややこしい部分に差し掛かっていたし、形になってきたので早めの就寝。あとは週末勝負。

6日目

影がロに落ちなかったので、どうも見栄えがよくない。ということで、シェーダーに手を出しました。

と言っても、コピペしただけ...。改めて勉強します。細かいところですが、見栄えが変わりました。

そしてこれ。

最近はWebGLでもかなり速いので、Fantasticで良いと思います。

自動ブロックパターン生成、オーディオ関連、消える判定などを実装して、6日目終わり。

最終日

最終日は、タイトル画面作成から。

紙をひらひらさせようと思って、Clothコンポーネントに手を出しました。頂点ごとに、拘束させるかや、当たり判定のあるものにどれぐらいめり込むかの設定ができるのですね。Clothを適用するモデルは、Scaleを設定すると動きがおかしくなります。ということでPlaneは使えず。ProBuilder BasicのモデルはRendererがかち合うので非対応でした。仕方ないのでBlender3Dでモデルを作りました。前回に続き、Blender入門(2.7版)さんにお世話になりました。

時間がかかった割にはイマイチな出来になりましたが、まだ足りないものがあるので操作説明の作成へ。必要な状況のスクリーンショットを撮って、Screenpressoで矢印をつけたり、文字を追加して画像作成。それをペタペタシーンに貼り付けて完成。

タイトルと操作説明で時間を食い、こんな状況に。ひとまず、時間がかかりそうな部分や、クオリティーを上げる時間はなさそうなので、一旦公開する方向で調整に入りました。難易度はスクロール速度を上げるだけにして、画面幅を広げるとバグが出るので、アスペクト比はそのままに、などなど。

こんな一週間でした。

今回新しく挑戦したこと

  • カメラ2つを使って、ゲームのレイアウトの外側の描画
  • テクスチャを書き換えて、動的にテクスチャパターン作成
  • Animationで画像やテキストに動きをつける
  • 半透明に影を落とすためのシェーダーの利用(ブログのコピペですが)
  • Clothコンポーネントによる布シミュレーション
  • Blender3Dでクロス用のモデル作成
  • Unity Affiliateに登録

作ってみると何かしら新しいことに手を出して経験が増えます。宿題のテーマもできましたし。

1週間が終わって

これまでで最も未完成の状態での投稿でした^^; 他の皆さんが公開予約しました~とかいう報告に「うっ」となりつつ、学生さんに「締め切りすぎても大丈夫だから」と言っていた手間、そのまま突っ込みました。

今回も見てもらったり、遊んでもらうための仕込が足りなかったと反省が多いですが、自分的には楽しく遊べるものになりました。スマホアプリにするのが最終目標なので、これから画面レイアウトなどごっそり変えたりしながら継続して開発していくつもりです。

次回に向けて

自己満足はしていますが、これまで課題だった魅力的な画面作りは今回も失敗でした。敗因はいつも通りですが、魅力を伝えるコレ、というものを用意できなかったことだと思っています。

次回は三ヶ月後なので気分が変わって別のことをしそうですが、今の所、プリミティブな素材をフラットデザインかグラデーションで魅せるか、キャラクターに徹底的にフォーカスした作品を作ってみたいです。参加してない跳ねるフローのを作る手も。皆さんの作品を見ていると、サクッと遊べてすごく面白いものがあって、そういうのを2,3日で完成させてみるというのもやってみたいです。

利用アセット・参考URL

今回も沢山のアセットによって、楽しくゲーム作りができました。作者の皆様、ありがとうございました。

文字表示に使いました。グラデーションとかつけられるし、プリセットのフォントも良い感じのがあるので、とりあえず入れておくと吉です。

タイトルやゲーム中のBGMに利用しました。 イメージが近い曲が見つかるのでいつも助かってます。

【Unity、WebGL】なるべく簡単にオンラインランキング機能をつけるサンプル - naichi's lab

今回も利用させていただきました、オンラインランキングシステムです。パーツが綺麗になって更にいい感じになっていました。

Online converter - convert video, images, audio and documents for free

SoundEngine FreeはMP3が扱えないので、MP3からOGGに変換するのに使いました。 Webページで変換できるので手軽で便利です。

SoundEngine・RadioLine公式サイト!【ダウンロード・ヘルプ・豆知識・関連情報など】

OGGなどの音素材のトリミングやエフェクトをかけられるフリーウェアです。効果音の一部を切り出したり、冒頭の無音部分を削除したりするのに利用しました。 とても使いやすいです。

UnityのWebGL出力に簡単に無料でグローバルランキングを実装できる仕組みを考えてみた - Qiita

オンラインランキングのバックエンドをGoogleワークシートで構築するdivideby_zero氏の記事です。今回もありがたく利用いたしました。

効果音ラボ - フリー、商用無料、報告不用の効果音素材をダウンロード

生活音などのさりげない音が揃っていて、好みの音を見つけやすくて重宝しています。

Unity5で半透明オブジェクトに影を投影する方法 - プログラムの素

ハムエッグ氏のブログです。 半透明のオブジェクトに影が落ちず、ロが消える時に影に入っていると綺麗にならなかった問題が、こちらで紹介されているシェーダーを使って解決できました!

Blender入門(2.7版)

タイトルで揺れる紙のモデルを作成する時に、UVの貼り方の確認をしました

Home | Screenpresso

操作説明画面の作成に使ったスクリーンショット&画像装飾ツールです。有料のPro版を使っています。

[OFFICIAL]Filmora Video Editor(Win&Mac) | Download Video Editing Software

今回も画面動画の作成はこちらを使いました。Twitterの投稿時はMP4、UnityRoomのアイコンはGIFで出力しました。有料版を使っています。出力時にカスタムで自由に解像度を設定できることにこれまで気付かず、新しい発見でした。

Textureをスクリプトから編集してみる - のしメモ アプリ開発ブログ

ロを上から出現させるテクスチャーパターンを作成する時に参考にしました。

GitHub DesktopでLFSを使う(利用制限について追記11/23)

LFSとは、Large File Storage(大きいファイルの保存領域)のことです。

Gitはソースコードのバージョン管理を目的としていたシステムです。画像や音声データなどのバイナリーデータも放り込めるのですが、本来は大きなサイズのバイナリーファイルを扱うようにできておらず、低速な上に、1ファイル100MByteまでという制約があります。そこで、大容量のデータを効率よく、高速に扱うためのLFSが提供されるようになりました。

詳しくはこちら → Git Large File Storage - How to Work with Big Files - YouTube

LFSを使うことは必須ではありませんが、使った方が速度面でメリットがあったりしますし、100MByte以上のファイルが扱えるようになります。ただし、バンド幅と容量に制限があります。無料ではどちらも1GByte/月です。$5/月を支払うと、50GByte/月に増やすことができます(2017/11/23追記)。オーバーしたからすぐに課金される訳ではありませんが、利用にあたっては使い方や容量などを検討して導入してください。

新旧GitHub Desktopで使う手順をまとめます。

目次

前提

この記事は以下の環境で試したものです。

GitHub Desktop 新版

Electronで作り直された新バージョンですが、旧版より機能が少なくてなんだか使いにくい...という微妙なツールです。旧版だとGUIだけでLFSの設定ができますが、こちらではコマンドラインでの操作が必要になります。では設定を進めていきます。

  • GitHub Desktopを起動します

f:id:am1tanaka:20171122152744p:plain

  • LFSを設定したいリポジトリーを新しく作成するか、クローンなどして開いてください

f:id:am1tanaka:20171122153310p:plain

f:id:am1tanaka:20171122153445p:plain

  • Gitコマンドをインストールしていない場合、以下のような画面が表示されます。その場合は、[Install Git]でGitをインストールします。以下の画面が表示されなければ準備できていますので、LFSで管理したい拡張子を登録に進んでください

f:id:am1tanaka:20171122154122p:plain

  • 1のDownloadをクリックします

f:id:am1tanaka:20171122154403p:plain

  • Gitのページが開くので、最新版(Latest)をダウンロードします

f:id:am1tanaka:20171122154545p:plain

  • ダウンロードが完了したファイルを実行して、インストールしてください。セキュリティの警告などが表示されたら[実行]して、設定はそのままで結構です
  • インストールが完了したら、Release Noteページが表示されますが、閉じて結構です
  • インストールを反映するために、GitHub Desktopを閉じて起動し直します
  • 改めて、[Repository]メニューから[Open in Command Prompt]を選択すると、コマンドプロンプトが開きます

f:id:am1tanaka:20171122153445p:plain

LFSの初期化

リポジトリーのフォルダーにいる状態でコマンドプロンプトが開きます。コマンドで、LFSの設定を行います。

f:id:am1tanaka:20171122161326p:plain

git lfs install

f:id:am1tanaka:20171122161425p:plain

この作業は、リポジトリーに対して一回やればOKです。

LFSで管理したい拡張子を登録

  • LFSに登録したい大きなバイナリーファイルの拡張子を登録します。例えば以下のようにすると、GIF,PNG,JPG,WAV,OGG,MP3LFSに登録するようになります。不要なものは外して、他に必要と思われる拡張子を同様に追加してください
git lfs track *.gif *.png *.jpg *.wav *.ogg *.mp3

f:id:am1tanaka:20171122175050p:plain

これでリポジトリーに.gitattributesというファイルが生成されます。これがLFSの設定ファイルです。これ以降、登録した拡張子のファイルをリポジトリーに追加すると、自動的にLFSに登録するようになります。

試しにサンプルピクチャの菊をリポジトリーに追加してみました。これを適当な件名を入力してコミットします。

f:id:am1tanaka:20171122164435p:plain

コミットが完了したら、Pushします。

f:id:am1tanaka:20171122164525p:plain

LFSに登録されたか確認してみます。[Repository]メニューから[View on GitHub]を選択します。

f:id:am1tanaka:20171122164638p:plain

登録した画像ファイルをクリックして、容量の隣辺りに[Stored with Git LFS]が表示されていれば成功です。

f:id:am1tanaka:20171122175159p:plain

新しいGitHub Desktopでのセットアップ作業は以上です。以降、普通に使えば、登録した拡張子のファイルは自動的にLFSで管理されるようになります。

すでに登録済みのファイルはどうする?

残念ながら、自動的にLFSには移動してくれないようです。

  • 該当ファイルを一度リポジトリーの外に移動させてコミットして、リポジトリーから消す
  • 移動させたファイルを元の場所に戻す
  • 再度コミットして登録
  • プッシュ

とすると、LFSに登録し直されます。

GitHub Desktop 旧版

こちらの方はめちゃくちゃ簡単です。

f:id:am1tanaka:20171122175816p:plain

まずは、LFSを使いたいリポジトリーを作成したり、クローンして開きます。

f:id:am1tanaka:20171122175920p:plain

LFSで管理したい拡張子を登録

f:id:am1tanaka:20171122180002p:plain

  • 右上の歯車アイコンから、[Repository Settings...]を選択します

f:id:am1tanaka:20171122180102p:plain

  • 左から[Git LFS]を選択してから、右の欄に*.gifのように入力して、[+]をクリックして登録していきます。まとめて登録できないので、1つ1つ登録してください

f:id:am1tanaka:20171122180339p:plain

  • 上記は、GIF, PNG, JPG, WAV, OGG, MP3ファイルをLFSで管理する為の例です。登録が完了したら、[OK]を押します。これで設定ファイル.gitattributesが作成されます。以降、登録した拡張子のファイルはLFSで管理されるようになります

f:id:am1tanaka:20171122180615p:plain

試しにファイルを登録する

試しに、サンプルピクチャーの菊の画像を登録してみました。[Changes]のボタンをクリックして、変更内容を確認します。

f:id:am1tanaka:20171122180806p:plain

[Summary]欄に適当にコメントを書いて、[Commit to master]をクリックしてコミットします。

f:id:am1tanaka:20171122180918p:plain

右上の[Sync]、あるいは[Publish]をクリックしてGitHubにプッシュすれば完了です。

f:id:am1tanaka:20171122181038p:plain

LFSで作成されているか確認してみます。リポジトリーを右クリックして、[View on GitHub]を選択します。

f:id:am1tanaka:20171122181124p:plain

追加した画像をクリックします。

f:id:am1tanaka:20171122181339p:plain

容量の隣辺りに[Stored with Git LFS]と表示されていれば成功です。

f:id:am1tanaka:20171122175159p:plain

以上で設定完了です。これ以降は、普通にプロジェクト管理すれば、登録した拡張子のファイルは自動的にLFSで管理されるようになります。

すでにリポジトリーに登録済みのファイルは、自動的にはLFSで管理されるようにはならないようです。再登録の手順はこちら

参考URL

Unityの公式サンプルml-agentsでAIを試す

Unityで機械学習を利用できるようにするUnity公式のml-agentsWindows7で動かすまでのメモです。

(2017/11/11 トレーニングの自動終了について追記)

f:id:am1tanaka:20171108132119p:plain

ざっくりと概要

ml-agentsUnity Machine Learning Agentsを略した名前です。「Unityの機械学習エージェント」ということですね。

機械学習には様々なものがありますが、このプロジェクトでは機械学習の代表格であるTensorFlow(テンソル・フロー)というオープンソースを利用します。ゲーム専用ではなく、デファクトスタンダードなAIシステムを採用しているのは大きな利点だと思います。TensorFlowは手書き文字や写真に写っているものを推定するなど様々な用途に使われていて、応用範囲がとても広いです。以前から使ってみたいと思っていましたが、よいきっかけになりました。

今回のプロジェクトの利用の流れは大体以下の感じです。

  1. [Unity] Unityで機械学習で使うための実行ファイルをビルド
  2. [Python+Unity] Unityでビルドした実行ファイルをPythonから呼び出して、TensorFlowで学習
  3. [Python] 学習結果を.bytesファイルに保存
  4. [Unity] Unityのアセットに.bytesファイルを含める
  5. [Unity] 学習結果を組み込んだ実行ファイルをUnityでビルドして、単体アプリの完成

機械学習には、「学習する段階」「学習成果を使って実行する段階」の2段階があります。機械学習を行うTensorFlowはPythonで動くソフトウェアですので、学習する段階はUnityとPythonを連携させて行います。学習結果はデータファイルに出力されます。それをUnityに含めてビルドすれば、機械学習で作成したAIに状況を判断させることができます。こうやって作成した「学習成果を使って実行する」アプリにはTensorFlowは不要なので、単体で配布することができます。

現在のml-agentsはβ版で、ビルドができるのは[Windows, mac, Linuxスタンドアロン実行形式][iOS][Android]の3種類とありました。

ふとした疑問

  • 単体アプリになったあとは学習しないのだろうか?
    • それなりに効果のある学習をするには1万回とかの試行が必要なので、人間が遊ぶ回数では学習させても効果はなさそう
    • プレイヤーの操作を記録しておいて、別途学習させる、ということになるのかな?

前提

  • Windows7 64-bit版
  • Unity 2017.1以降
  • Anaconda(Python)のインストールに管理者権限が必要

インストール

ml-agents/installation.md at master · Unity-Technologies/ml-agents · GitHubの流れに沿って作業を進めます。大まかには以下のとおりです。

  1. Anaconda 64-bit版のインストール(これでPythonも入る)
  2. ml-agentsリポジトリーの入手
  3. Pythonの仮想環境の作成
  4. ml-agentsのSetupを実行

ではインストールをはじめましょう。

Anaconda 64-bit版のインストール

TensorFlowを動かすのに必要なので、Anacondaというデータサイエンス向けの機能が沢山用意されているPythonパッケージをインストールします。このパッケージはPythonを含むので、同時にPythonのインストールも完了することになります。

(Anacondaについての詳細はこちら)

Downloads | Anacondaを開いて、利用するPythonのバージョンの[64-Bit Graphical Installer]をクリックしてダウンロードします。

f:id:am1tanaka:20171108144633p:plain

ダウンロードが完了したら、実行して、設定はそのままでインストールを完了させます。完了したら[Next]を押して、以下のチェックは不要なので外して、[Finish]をクリックして完了です。

f:id:am1tanaka:20171108154706p:plain

ml-agentsリポジトリーの入手

Unity公式が提供している[ml-agents]リポジトリーを入手します。GitHubリポジトリーなのでクローンするのが本道な気もしますが、今回はシンプルにZIPをダウンロードして使います。

GitHub - Unity-Technologies/ml-agents: Unity Machine Learning Agents を開きます。右の方の[Clone or download]ボタンをクリックして、[Download ZIP]をクリックします(cloneの方がいい人はクローンしてください)。

f:id:am1tanaka:20171108151201p:plain

[ドキュメント]フォルダー下の[Unity Projects]フォルダー内など、Unityからアクセス可能な場所にZIPファイルを展開します。

展開したフォルダー内のunity-environmentフォルダーにUnityのプロジェクト、pythonフォルダーにPython関連のファイルが入っています。ここからは、このフォルダー内にインストールをしていきます。

Pythonの仮想環境の作成

Pythonは、プロジェクトごとに個別に環境を持たせることができます。通常のPython3ではvenvで行いますが、Anacondaはcondaで同様のことを行います。

(余談:Pythonは特別な環境設定をせずに、複数の異なるバージョンや32-bit版、64-bit版のものをインストールしても問題ありません。プロジェクトごとに、[venv]や[conda]で必要なバージョンの仮想環境を作成して使うことができます。進んでます)

Anacondaのプロンプトを起動します。

[スタート]メニューから[すべてのプログラム]>[Anaconda3 (64-bit)]>[Anaconda Prompt]を起動します。

f:id:am1tanaka:20171108161557p:plain

Anaconda版のPythonが利用できるコマンドプロンプトが開きます。この後の作業で、文字コードUTF-8じゃないとエラーが出る部分があるので、以下を実行して、コマンドプロンプト文字コードUTF-8に切り替えておきます。

chcp 65001

cdコマンドでml-agents-masterフォルダーを開きます。エクスプローラーでml-agents-masterフォルダーを開いてから、上のアドレスバーをクリックしてパスをコピーします。

f:id:am1tanaka:20171108161904p:plain

コマンドプロンプトcdと入力して、右クリックして[貼り付け]を選べば楽です。

f:id:am1tanaka:20171108161957p:plain

以下を実行して、Anacondaの環境下にml-agents用の環境を作って、Python3.6.3が使えるようにします。Pythonのバージョンはその時々に応じて変更して構いません。

conda create -n ml-agents python=3.6.3

[Proceed]の問いが表示されたら[Enter]キーを押してインストールを開始します。

f:id:am1tanaka:20171108162522p:plain

ml-agentsのSetupの実行

残りのインストールは、パッケージに含まれるSetup.pyで行えます。これはml-agents環境にインストールしたいので、環境を切り替えます。

activate ml-agents

これで、コマンドラインの行頭が(ml-agents)に変わります。この後のインストールは、全てこの環境内に行われます。

cd python
pip install .

しばらく待って、コマンドラインが表示されたらインストール完了です。この後もコマンドプロンプトは利用しますので、閉じないでおいてください。

f:id:am1tanaka:20171108164918p:plain

ml-agentsのボールのサンプルのセットアップ

Unityで機械学習をさせるための準備をします。ボールのバランスを取るサンプルを使います。ここからはml-agents/Getting-Started-with-Balance-Ball.md at master · Unity-Technologies/ml-agents · GitHubに従って作業をします。

  • Unity2017.1以降のバージョンを起動
  • [OPEN]を選択
  • 先にダウンロードした[ml-agents-master]フォルダー内の[unity-environment]フォルダーを選択して開く
  • 以下のような警告が表示されたら、構わず[Continue]して読み込む

f:id:am1tanaka:20171108165723p:plain

  • [Project]ビューから[ML-Agents]>[Examples]>[3DBall]フォルダーを開いて、[Scene]シーンをダブルクリックして開く

これで、ご存知の以下のシーンが開きます。

f:id:am1tanaka:20171108165956p:plain

  • [Edit]メニューから[Project Settings]>[Player]を開く
  • [Inspector]ビューで以下を設定
    • [Resolution and Presentation]欄の[Run In Background]にチェックが入っていることを確認
    • 同様に[Display Resolution Dialog]が[Disable]になっていることを確認
  • [Hierarchy]ビューから[Ball3DAcademy]オブジェクトを開いて、[Ball3DBrain]を選択

f:id:am1tanaka:20171108170135p:plain

  • [Inspector]ビューで[Brain Type]を[External]に変更

f:id:am1tanaka:20171108170214p:plain

  • [Ctrl]+[S]キーを押して、シーンを保存する
  • [File]メニューから[Build Settings]を選択
  • ビルドターゲットとして、とりあえず[PC, Mac & Linux Standalone]を選択
    • ライブラリ的には、[iOS]と[Android]も対応しているようですが、試してません
    • ログが必要なら[Development Build]にチェック(どっちでもいいです)
  • [Build]をクリック
    • フォルダーを[ml-agents-master]まで戻してから、[python]フォルダーをダブルクリックして開く
    • ファイル名を3DBallとして、[保存]ボタンをクリック

f:id:am1tanaka:20171108170708p:plain

以上でビルドが完了したら、学習用の実行ファイル3DBallの出来上がりです。

トレーニングする

トレーニングはJupyter(ジュピター)を使って行うと楽です。すでにインストール済みなのでコマンドラインから以下で起動します。

jupyter notebook

これで呼び出したパスが参照できます。pythonフォルダーにいた場合、以下のような具合です。

f:id:am1tanaka:20171108173907p:plain

動作確認と環境設定の確認用の[Basics.ipynb]というファイルと、PPOで学習させる[PPO.ipynb]の2つがJupyterのノートブックです。Basicsは飛ばして、早速学習させましょう。

[PPO.ipynb]をクリックして開きます。

f:id:am1tanaka:20171108174312p:plain

ノートブックでは、説明を読んだり、実行するプログラムをステップごとに実行していくことができます。(1)が実行対象で、ここではプロジェクト名である「Unity ML Agents」と、この学習のアルゴリズムは「Proximal Policy Optimization(PPO)」と呼ばれるもので、詳細はhereで読んでくれ、というようなコメントになっています。

(2)の[Run]ボタンで、現在選択されているセルが実行されますが、実行する前に1つだけ環境設定が必要です。下にスクロールさせて、4つ目のセルを表示します。env_nameから始まる行を探して、environmentを消して、実行ファイル名である3DBallに書き換えてください。

f:id:am1tanaka:20171108174807p:plain

これで準備完了です。最初の「Unity ML Agents]のセルをクリックして青枠で囲まれたら、[Run]ボタンを押して実行します。自動的に次のセルがアクティブになりますので、また[Run]を押して実行します。「Export the trained Tensorflow graph]のセルになるまで[Run]をしてください。

f:id:am1tanaka:20171108175000p:plain

しばらく待っていると、以下のような小さいウィンドウが表示されて、先にビルドした[3DBall]が起動して学習を始めます。。

f:id:am1tanaka:20171108224222p:plain

更に待つと、Mean Reward: 10.82324のようなメッセージが表示されはじめます。

f:id:am1tanaka:20171108175119p:plain

何回目かにSaved Modelと表示されたら、その前のMean Rewordの数値を確認してください。それが成功率です。75を越えるぐらいでしたらかなり頭が良くなっていますので、学習を終了させましょう。

[3DBall]の[x]ボタンをクリックして閉じてください。

f:id:am1tanaka:20171108175331p:plain

JupyterにJSONDecodeErrorなどが表示されますが大丈夫です。

f:id:am1tanaka:20171108175519p:plain

Mean Rewardの値は、時々低い値になる場合があります。そのままですと、かなり頭が悪いAIになります。学習を継続させれば改善しますので、改善したい場合は[3DBall]を閉じずに待ってください。再び、Mean Rewardが表示されるようになり、また何回目かでSaved Modelが表示されます。納得がいく値が出るまで待ってください。

納得のいく数字がでて実行ファイルを停止したら、Jupyterに切り替えてExport the trained Tensorflow graphの下のセルを[Run]して実行します。

f:id:am1tanaka:20171108175706p:plain

このように表示されたら、学習した人工知能のデータが保存されます。

なお、手動で停止しなくても、max_stepsで定義されているステップ数を実行したら自動的に学習は終了して、.bytesファイルが保存されます。デフォルトでは5e5が代入されていますが、これは5*105乗で、50万ステップを表しています。1e5ぐらいにしておくと、10万回で自動的に終了して保存されます(2017/11/11追記)

トレーニング結果をUnityに組み込む

プラグインのインポート

TensorFlowの学習成果をUnityに組み込んで、単独のアプリとして動くようにしましょう。TensorflowのデータをUnityで扱えるようにするためのプラグインが必要なので、Unityのプロジェクトにインポートします。

  • https://s3.amazonaws.com/unity-agents/TFSharpPlugin.unitypackage からTF#をダウンロード
  • ダウンロードが完了したら、ダブルクリックするか、Unityの[Project]ビューにドラッグ&ドロップしてインポートする
  • [Edit]メニューから[Project Settings]>[Player]を選択
  • [Inspector]ビューの[Other Settings]欄で以下を設定
    • [Scripting Runtime Version]を[Experimental(.Net 4.6 Equivalent)]にする
    • Scripting Defined Symbols欄にENABLE_TENSORFLOWを入力

f:id:am1tanaka:20171108180751p:plain

以上ができたら、[File]>[Save Scene]、[File]>[Save Project]をしてから、Unityを一度閉じて、起動し直します。これで、TensorFlowのデータを組み込むためのInternal Brain Typeが使えるようになります。

学習データを組み込む

学習データを組み込んで、Unityで結果を見ましょう。

  • Unityを起動して、[unity-environment]プロジェクトを開く
  • [Project]ビューから[ML-Agents]>[Examples]>[3DBall]>[TFModels]フォルダーを開く
  • 予め入っている[3DBall]ファイルは不要なので削除する

f:id:am1tanaka:20171108185534p:plain

  • [Explorer]などで、[ml-agents-master]フォルダー>[python]>[models]>[ppo]フォルダーを開く

f:id:am1tanaka:20171108185317p:plain

  • フォルダー内の[3DBall.bytes]をドラッグして、Unityの[Project]ビューの[ML-Agents]>[Examples]>[3DBall]>[TFModels]フォルダーにドロップ
  • [Hierarchy]ビューから[Ball3DAcademy]オブジェクトを開いて、子供の[Ball3DBrain]を選択
  • [Inspector]ビューの[Brain Type]欄を[Internal]に変更
  • [Project]ビューの[ML-Agents]>[Examples]>[3DBall]>[TFModels]フォルダーから[3DBall]をドラッグして、[Inspector]ビューの[Graph Model]欄の[Missing]となっているところにドラッグ&ドロップ

f:id:am1tanaka:20171108181213p:plain

以下は恐らく最初から設定済みですが、念のため確認しておいてください。

  • [Graph Placeholders]欄を開いて、[Size]が1か確認
  • [epsilon]欄の[Value Type]を[floating point]にして、[Min Value]と[Max Value]をどちらも0にする
    • 上記2つの設定は、3DBallがContinuous controlで制御する設定なので、TensorFlowモデルがノイズパラメーターを必要としているので設定しています。Discrete Controlだった場合はepsilonは不要です

以上できたら実行してください。学習が成功していれば、ボールをなるべく落とさないようにパネルが自動制御されるはずです。以下はRewardが80ぐらいの学習データで動かしたものですが、安定して制御できています。

f:id:am1tanaka:20171108190543g:plain

学習していない状態を確認する

学習を殆どさせていないとどうなるでしょうか。殆ど学習させていないデータを用意したので確認してみましょう。

https://github.com/tanakaedu/unity-ml-agents/raw/master/3DBall.bytes をダウンロードして、[Project]ビューの[TFModels]フォルダーにドラッグ&ドロップします。

f:id:am1tanaka:20171108190805p:plain

[Hierarchy]ビューから[Ball3DAcademy]オブジェクトの子供の[Ball3DBrain]を選択して、[Inspector]ビューの[Graph Model]欄に、[3DBall 1]をドラッグ&ドロップして設定してください。

実行してみてください。全くバランスが取れなくなります。これが初期に近い状態です。この状態から機械学習をさせて、先に確認したような動きに変わったのです。

f:id:am1tanaka:20171108185808g:plain

学習回数について

デフォルトでは5万回学習するごとにSave Modelsが表示されるようになっています。Jupyterの以下のsave_freqが保存するまでの学習回数の設定です。

f:id:am1tanaka:20171108185907p:plain

この値を変更すると、保存タイミングを変更することができるようになります。500回に減らしたのが下手バージョンのデータです。経過を見る限り、今回の内容なら2万回ぐらいで十分に上達するようです。

再学習の手順

学習させたあと、もう一度学習し直そうと最初から[Run]し直しても、[Load the environment]のところでtimeoutが発生して失敗します。

f:id:am1tanaka:20171108191222p:plain

再学習させる場合は、[restart the kernel]アイコンをクリックしてカーネルの再起動をします。

f:id:am1tanaka:20171108191301p:plain

[Restart]をクリックします。

f:id:am1tanaka:20171108191508p:plain

右上に[Restarting kernel]と表示されて、消えるまで待ちます。

f:id:am1tanaka:20171108191528p:plain

f:id:am1tanaka:20171108191533p:plain

これで、一番上から[Run]し直せばtime outせずに学習させられます。

終了方法

色々閉じるので、簡単に手順をまとめておきます。

  • Unityを、[File]>[Save Scene]と[File]>[Save Project]をしてから閉じる
  • Jupyterを開いていたWebブラウザーを閉じる
  • Jupyterを起動した[Anaconda Prompt]で、[Ctrl]+[C]キーを押す
  • Jupyterが停止したら、exitを実行してコマンドプロンプトを閉じる

以上です。

プロジェクトの再起動

設定が完了したプロジェクトを再開する方法です。

  • Unityを起動して、[unity-environment]プロジェクトを開く
  • [スタート]メニューから[すべてのプログラム]>[Anaconda3 (64-bit)]>[Anaconda Prompt]を選択して、コマンドプロンプトを起動
  • 以下を実行して、ml-agentsの環境に切り替え
chcp 65001
activate ml-agents
  • cdコマンドで、[ml-agents-master]フォルダー内の[python]フォルダーに移動
  • 以下でJupyterを起動
jupyter notebook
  • PPO.ipynbをクリックしてノートブックを起動

以上です。

まとめ

長かったですが、以上で機械学習を利用するUnityプロジェクトの環境構築が完了です。TensorFlowを利用した様々な機能を開発するよい土台となりそうです。

次は、このサンプルが何をやっているかの調査をして、把握できたらUnityプロジェクトの[examples]フォルダーに入っている他のサンプル([Basic][GridWorld][Tennis]の3つ)もいじってみたりしつつ、応用範囲を広げて行ければと考えています。

参考URL

CesiumをWebpackでビルドできるようにする

Cesiumとは、Google Earthと同様に3Dで地図をWebブラウザー上に描画するJavaScriptライブラリーです。WebpackでWebアプリとしてビルドできる様にするための手順が公式サイトにあったので、あちこち端折りながらまとめます。

目次

前提環境

  • コマンドラインJavaScript、Web開発の基礎知識
  • WebGLをサポートしたBrowser。対応状況が不明な場合は、こちらを開いて、動くか確認してください
  • コードエディター。CesiumのメンバーはWebstormを利用している。最小限のコードならSublime Textなどでも良い
  • Node.jsがインストールされていること。LTS(Long Time Support)バージョン推奨だが、Version 6以降なら動作します

ここでは、OSはmacOS、エディターはAtomで進めます。また、元のドキュメントではWebブラウザーの表示にwebpack-dev-serverを使っていますが、ライブリロードをしたいのでbrowser-syncに差し替えました。

基本的なWebpackアプリの作成

まずはWebpackで基本的なWebアプリが開発できる様にセットアップします。既知の場合は次に進んでください。

npmの初期化

任意の場所に、プロジェクトを入れておくディレクトリーを作成して、ターミナルを起動して、プロジェクトディレクトリーにcdで移動します。ディレクトリー名はcesium-webpack-appなどにしておきます。

mkdir cesium-webpack-app && cd cesium-webpack-app

以下のコマンドを実行して、npm用のpackage.jsonを生成します。

npm init -y

package.jsonが生成されたので、必要に応じて項目を変更します。今のところ、そのまま進めます。

browser-syncのインストール

他記事に手順を記載済みです。こちらをみて、[Browsersyncをインストール]と[Browsersyncの設定ファイル]を完了させてください。

アプリ用のコードを生成

Atomエディターをインストールしていたら、Atom .として、このディラクトリーをプロジェクトフォルダーとして、Atomを起動します。

Atomでプロジェクトフォルダーを右クリックして、[New Folder]を選択してsrcという名前のディレクトリーを生成してください。アプリ用のソースファイルは全てこの中に保存して、編集していきます。Webpackはsrcディレクトリー内のコードをビルドして、distというディレクトリーに出力します。

Atomsrcディレクトリーを右クリックして、[New File]を選択して、index.htmlという名前のファイルを作成してください。作成したら、以下のコードをコピー&ペーストなどで入力して、保存します。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
    <title>Hello World!</title>
  </head>
  <body>
    <p>Hello World!</p>
  </body>
</html>

次に、WebアプリのエントリーポイントとなるJavaScriptファイルを作成します。Webpackは、Webアプリをビルドするのに必要なJavaScriptCSSなどのファイルを、エントリーポイントから辿って見つけていきます。

src/index.jsを新規ファイルとして作成して、まずは他のファイルは組み込まず、シンプルに1行だけのコードを書いておきます。

console.log('Hello World!');

Webpackのインストールと設定

ターミナルで以下を実行して、Webpackをはじめとするパッケージをプロジェクトに加えます。

npm i --save-dev webpack style-loader css-loader url-loader html-webpack-plugin

これで、以下の様なパッケージがインストールされました。

  • webpack
    • Webアプリをビルドするためのツール。分割されたファイルを統合したり、様々なファイルを再配置したり、ビルドに関連する処理をしてくれます
  • style-loader, css-loader, url-loader
    • CSSや各種リソースファイルを読み込んでくれるローダーです
  • html-webpack-plugin
    • HTMLファイルをバンドルするのに使うツールです

設定

プロジェクトディレクトリー直下に新しいファイルを作成して、webpack.config.jsという名前にしてください。このファイルにWebpackのビルド設定を以下の様に記載します。

const path = require('path');

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    context: __dirname,
    entry: {
        app: './src/index.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist'),
    },
    module: {
        rules: [{
            test: /\.css$/,
            use: [ 'style-loader', 'css-loader' ]
        }, {
            test: /\.(png|gif|jpg|jpeg|svg|xml|json)$/,
            use: [ 'url-loader' ]
        }]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: 'src/index.html'
        })
    ]
};

おおよそ、以下の様なことを設定しています。

  • パス操作をするためにNodeのpathを読み込み
  • webpackモジュールをwebpackという定数に読み込み
  • html-webpack-pluginHtmlWebpackPluginという定数に読み込み
  • __dirnameはNodeのグローバル値で、このファイルのパスを表す。このプロジェクトのベースのパスをcontextを使って指定
  • エントリーポイントとして./src/index.jsを設定
  • 出力先はdistディレクトリーにして、ファイル名を[name].jsで指定
    • この場合、app.jsになります
  • CSSファイルはstyle-loadercss-loaderで読み込む様に指定
  • 画像などの各種リソースは、url-loaderで読み込む様に指定
  • HTMLファイルのテンプレートとして、src/index.htmlを指定
    • Webpackがsrc/index.htmlを雛形にして、必要な項目をページの本文に差し込みます

アプリをバンドルする

package.jsonに設定を追加して、npmコマンドで簡単にバンドルを実行できる様にします。testスクリプトは現状では利用しないので削除しても構いません。

package.jsonを開いて、"scripts"を以下の様にします。

  "scripts": {
    "build": "node_modules/.bin/webpack --config webpack.config.js",
    "start": "node_modules/.bin/webpack --watch --config webpack.config.js & browser-sync start --config bs-config.js"
  },

ビルドの実行

ターミナルで以下を入力することで、バンドルの実行と、開発サーバーでの動作確認ができる様になります。

npm start

これでローカルサーバーが起動して、自動的にWebブラウザーが起動して、 http://localhost:3000 が開きます。これ以降、index.htmlを変更したり、index.jsを変更して保存すると、自動的にビルドが実行されて、Webページが更新される様になります。

まだ作業が残っているので、動作中のターミナルで[Ctrl]+[C]キーを押してローカルサーバーを停止してください。

WebアプリにCesiumを組み込む

Cesiumをインストール

プロジェクトディレクトリーから、以下を実行します。

npm i --save-dev cesium

設定

Cesiumをインストールすると、ライブラリーに加えて、CSSや画像、JSONファイルといったものも組み込まれます。また、他スレッドで処理を行うWebWorkerファイルも含まれます。古いnpmモジュールと異なり、様々な組み合わせができるようにCesiumはエントリーポイントを定義しません。動かすためには、いくらかのオプションを設定する必要があります。

まずは、Cesiumがどこにあるかの指定が必要です。ソースコードを指定して、それをWebpackが利用して個々のファイルの依存関係を解決します。ビルドされたバージョンのCesiumを使う方法もあります。それらのモジュールはRequireJS Optimizerによって最適化されているため、ライブラリーを簡単に改良することが難しく、自由度は下がります。

webpack.config.jsを開いて、以下の設定を最初の方に追加します。

// The path to the Cesium source code
const cesiumSource = 'node_modules/cesium/Source';
const cesiumWorkers = '../Build/Cesium/Workers';

次に、以下のようなオプションを追加して、CesiumがWebpackでどのようにコンパイルされるかを指定します。

    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist'),

        // Needed to compile multiline strings in Cesium
        sourcePrefix: ''
    },
    amd: {
        // Enable webpack-friendly use of require in Cesium
        toUrlUndefined: true
    },
    node: {
        // Resolve node module use of fs
        fs: 'empty'
    },

追加したオプションを簡単に説明します。

  • output.sourcePrefix: ''
    • Webpackのいくつかのバージョンは、デフォルトの設定で、出力するファイルの各行の先頭にタブ文字を追加する設定になっています。Cesiumは複数行の文字列のインスタンスがあるため、この設定を無効にするために必要になります。
  • amd.toUrlUndefined: true
    • AMD版のWebpackはrequireステートメントtoUrlに対応していないことをCesiumに伝えるための設定です。
  • node.fs: 'empty'
    • いくらかのサードパーティーで使われるfsモジュールを解決するための設定です。これはNode環境ではなく、Webブラウザーでの動作時に利用されます。

次に、cesiumエイリアスwebpack.config.jsの適当な場所に追加します。これを設定しておくと、Nodeの伝統的なモジュールのように簡単にアプリのコードから参照できるようになります。

   resolve: {
        alias: {
            // Cesium module name
            cesium: path.resolve(__dirname, cesiumSource)
        }
    },

Cesiumの静的ファイルを管理する

最後に、Cesiumの静的なアセットやウィジェット、Web Workerファイルを提供して、読み込むようにします。

copy-webpack-pluginを使って、ビルド時にCesiumに含まれる各種ファイルをdistディレクトリーにコピーします。まずは以下をターミナルで実行して、プラグインをインストールします。

npm i --save-dev copy-webpack-plugin

それから、webpack.config.jsファイルの上の方に、以下の定義を追加します。

const CopywebpackPlugin = require('copy-webpack-plugin');

plugins配列を以下のようにコード追加します。

   plugins: [
        new HtmlWebpackPlugin({
            template: 'src/index.html'
        }),
        // Copy Cesium Assets, Widgets, and Workers to a static directory
        new CopywebpackPlugin([ { from: path.join(cesiumSource, cesiumWorkers), to: 'Workers' } ]),
        new CopywebpackPlugin([ { from: path.join(cesiumSource, 'Assets'), to: 'Assets' } ]),
        new CopywebpackPlugin([ { from: path.join(cesiumSource, 'Widgets'), to: 'Widgets' } ]),
        new webpack.DefinePlugin({
            // Define relative base path in cesium for loading assets
            CESIUM_BASE_URL: JSON.stringify('')
        })
    ]

web workerは最適化済みのビルドされたものを使いますが、デバッグのためにオリジナルフォームが必要になる場合があります。それらはBuild/Cesium/Workersディレクトリーからコピーされます。

DefinePluginでは、webpackに組み込む静的ファイルのベースURLをCesiumに伝えています。

設定の動作確認

ここまでの設定が間違っていないかをチェックします。以下をターミナルで実行して、ビルドが成功して、Webページが表示されることを確認しましょう。

npm start

エラーが発生せず、Hello World!という文字が表示されればここまで成功です。いよいよ、Cesiumを使ってみましょう。

Hello World!

src/index.jsファイルを開いて、現在の内容は消して、以下を入力してください。

var Cesium = require('cesium/Cesium');
require('cesium/Widgets/widgets.css');

var viewer = new Cesium.Viewer('cesiumContainer');

1行目で、CommonJSスタイルで、CesiumオブジェクトにCesiumの全ての機能を読み込みます。 2行目で、ウィジェットCSSを指定します。 最後に、Cesiumのビュアーを生成して、cesiumContainerのIDを持ったHTML要素に表示する指定をしています。

index.htmlに、cesiumContainer要素を追加する必要があります。src/index.htmlを開いて、<p>Hello World!</p>という行を消して、その場所に以下のコードを入力してください。

<div id="cesiumContainer"></div>

これで設定完了です。ローカルサーバーは起動済みですので、変更したファイルを保存すれば自動的にブラウザーがリロードされるはずです。Webブラウザーに切り替えて、Cesiumの画面が表示されれば成功です。切り替わらない場合は、Webブラウザーをリロードしてみてください。

f:id:am1tanaka:20171103233137p:plain

少し表示領域の周りに白い枠があったり、ブラウザーのクライアント領域全体に表示されておらず、スペースが無駄になっています。

f:id:am1tanaka:20171103233536p:plain

独自のCSSを定義して、ブラウザーいっぱいに表示してみましょう。

src/css/main.cssというファイルを新しく作成して、以下のコードを入力して保存します。

html, body, #cesiumContainer {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
}

src/index.jsの先頭の方に、以下を追加して、css/main.cssを読み込むようにします。

require('./css/main.css');

上書き保存をすれば、自動的にリビルドされて、Webブラウザーが更新されます。変化しない時は、リロードしてみてください。枠がなくなり、ブラウザーのクライアント領域いっぱいに表示されるようになりました。

f:id:am1tanaka:20171103234002p:plain

以上で、簡単なCesium Webアプリの構築は完了です。

補足情報

各種、補足情報です。

アプリからCesiumモジュールを読み込むいくつかの方法

アプリに個別のCesiumモジュールを読み込む方法として、CommonJSの文法を使う方法と、ES6のモジュールを読み込むimportを使う方法があります。

全てのCesiumライブラリーをCesiumオブジェクトに設定する方法もあります。これはSandcastleで採用している方法です。Cesiumは巨大なライブラリーなので、基本的には必要なモジュールだけを読み込む方が良いでしょう。

CommonJSスタイルのrequire

CesiumオブジェクトにCesiumの全てのライブラリーを読み込んで利用するには、以下のようにします。

var Cesium = require('cesium/Cesium');
var viewer = new Cesium.Viewer('cesiumContainer');

個別のモジュールを読み込むには、以下のようにします。

var Color = require('cesium/Core/Color');
var color = Color.fromRandom();

ES6スタイルのimport

CesiumオブジェクトにCesiumの全てのライブラリーを読み込んで利用するには、以下のようにします。

import Cesium from 'cesium/Cesium';
var viewer = new Cesium.Viewer('cesiumContainer');

個別のモジュールを読み込むには、以下のようにします。

import Color from 'cesium/core/Color';
var color = Color.fromRandom();

アセットファイルの読み込み

Webpackの考え方では、全てのファイルはモジュールのように扱うべきというものがあります。これにより、JavaScriptのモジュールと同じようにアセットを読み込むことができます。Webpackが読み込みに使うローダーはwebpack.config.jsloaders属性で設定しているので、JavaScriptファイル内でrequireで以下のように呼び出すだけです。

require('cesium/Widgets/widgets.css');

この後は・・・

Sandcastleの気になったサンプルを見ながら、実装してみると良いでしょう。

発展的なWebpackの設定

Webpackでは、機能を増やしたり、バンドルサイズを減らしたり、追加機能を入れたりと、多様なビルド方法を選択できます。いくつかの設定について触れておきます。

Cesiumを製品に最適化したWebpackの設定例はrelease.webpack.config.jsにあります。

コード分割

デフォルトのCesiumパッケージは、アプリと同じチャンク内にあり、とても巨大になります。CommonChunksPluginを使うことで、Cesiumを分離して、アプリのパフォーマンスを向上させることができます。開発するアプリを複数のチャンクに分けたら、それらすべてが共通のcesiumチャンクを参照するようにします。

webpack.config.jsファイルにプラグインを追加して、Cesiumモジュールを分割するルールを指定するだけです。

    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: 'cesium',
            minChunks: module => module.context && module.context.indexOf('cesium') !== -1
        })
    ]

ソースマップを使うには

デバッグ時に、問題箇所がオリジナルファイルのどこかを示すためのマップファイルを作成できます。webpack.config.jsに以下を追加します。

   devtool: 'eval',

開発時には、この設定をしておくことを推奨します。製品版には含めるべきではありません。

pragmasの削除

開発時のエラーや警告メッセージが、Cesiumに埋め込まれています。これらは製品版には不要です。通常、これらは RequireJS Optimizer を使って、コードを縮小する時に削除します。これはWebpackの組み込み機能ではないので、以下のようにプラグインをインストールします。

npm i uglifyjs-webpack-plugin --save-dev

webpack.config.jsmodule.rulesの設定で、debugfalseにします。

    rules: [{
        // Strip cesium pragmas
        test: /\.js$/,
            enforce: 'pre',
            include: path.resolve(__dirname, cesiumSource),
            use: [{
                loader: 'strip-pragma-loader',
                options: {
                    pragmas: {
                        debug: false
                    }
                }
            }]
    }]

Uglify(最適化/圧縮)とminify(圧縮)

uglifyingとminifyingで、製品コードのサイズを縮小できます。公開用ビルドのために、CesiumはuglifyでJavaScriptファイルを、minifyでCSSファイルを縮小します。

まだuglifyjs-webpack-pluginをインストールしていなければ、以下でインストールします。

npm i uglifyjs-webpack-plugin --save-dev

webpack.config.jsの先頭の方で、以下でrequireします。

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

webpack.config.jsplugins設定に以下を追加します。

    plugins: [
        new webpack.optimize.UglifyJsPlugin()
    ]

CSSの最小化は、css-loaderoptionsminimize設定を書きます。

    module: {
        rules: [{
            test: /\.css$/,
            use: [
                'style-loader',
                {
                    loader: 'css-loader',
                    options: {
                        // minify loaded css
                        minimize: true
                    }
                }
            ]
        }]
    }

学習素材

公式のcesium-webpack-exampleリポジトリーには、最小のwebpack設定や、このチュートリアルで作成したHello Worldのコードが含まれ、コード設定の設定方法の導入として有用です。

データを追加したり、スタイリングを設定する方法など、作成するアプリで利用したい機能がCesium Workshop Tutorialで確認できるかもしれません。

Webブラウザーでコードをすぐに試せるSandcastleドキュメントも使えます。

Webpackについては、Webpack Conceptsや、Webpackのドキュメントを確認してください。

参考URL

WebpackでSass+Codeception+Seleniumの環境を作る

簡単なJavaScriptのプログラムを作る時の雛形プロジェクトを作ったのですが、Sassの組み込みで苦戦したので、備忘録として設定ファイルなどについて残しておきます。

  • 2017/11/3 index.htmlのテンプレートをsrcフォルダーに入れて、html-webpack-plugindistにビルドする手順を追加

目次

前提

プロジェクト用のフォルダーを作成して、cdで移動しておきます。例えば、test-webpackフォルダーに構築する場合は、ターミナルで以下を実行します。

mkdir test-webpack && cd test-webpack

Browsersync

Browsersync - Time-saving synchronised browser testing を参考に、インストール作業をします。

Browsersyncをインストール

ソースコードを変更したりした時に、ブラウザーを自動的に更新したいのでBrowsersyncをグローバルにインストールします。まずはターミナルを起動して、以下を実行してインストール済みか確認します。

browser-sync -v

エラーが表示されたら、以下を実行してグローバルにインストールします。要求されたら管理者パスワードを入力してください。

sudo npm i -g browser-sync

Browsersyncの設定ファイル

Browsersyncが動く様になったら、プロジェクトフォルダー内で以下を実行して設定ファイルを作成します。

browser-sync init

これでプロジェクトフォルダー内にbs-config.jsという設定ファイルが作成されます。Atomなどのテキストエディターで開いて、"files"の項目と、"server"の項目を以下のように設定してください。

    "files": ["./src/**/*"],
    "server": {
        "baseDir": "./dist"
    },

"files"は変更を監視するファイルやフォルダーのリストで、以上でプロジェクトフォルダー内のsrcフォルダー内のいずれかのファイルが変更されたらブラウザーをリロードします。

"server"は表示するブラウザーの基準フォルダーで、プロジェクトフォルダー内のdistフォルダーをドキュメントのベースディレクトリーに指定しています。

WebpackとSassのインストール

WebpackでSassが通るようにまとめてインストールします。情報源は以下のあたりです。

必要なパッケージをインストール

以下で、必要なパッケージをまとめてインストールします。

npm init -y
npm i --save-dev webpack node-sass css-loader sass-loader style-loader extract-text-webpack-plugin html-webpack-plugin
npm i --save lodash
  • 1行目:npmの設定ファイルであるpackage.jsonの生成
  • 2行目:WebpackとSass関連の各種パッケージを開発環境でインストール
  • 3行目:Webpackのサンプルで使われていたし、ランタイムであれこれ便利なのでlodashをついでに入れておく

プロジェクトフォルダー内を構築

簡単なJavaScriptプロジェクトの雛形を構築します。プロジェクトフォルダーを以下のようにしてください。

node_modulesフォルダーとbs-config.jspackage.jsonは作成済みなので、それ以外を作ります。ひとまず、ファイルは空で良いです。

f:id:am1tanaka:20171028212735p:plain

src/index.htmlを開いて、以下の内容にしてください。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>SimpleJavaScriptProject</title>
</head>
<body>
</body>
</html>

CSSJavaScriptのエントリーポイントへのリンクは、ビルド時に自動的に差し込まれるので不要です。

src/sass/styles.scssを開いて、以下の内容にします。

$font-stack:    Helvetica, sans-serif;
$primary-color: red;

.hello {
    font: 100% $font-stack;
    color: $primary-color;
}

src/js/app.jsを開いて、以下の内容にします。

import _ from 'lodash';
import '../sass/styles.scss';

function component() {
    var element = document.createElement('div');

    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    element.classList.add('hello');

    return element;
}

document.body.appendChild(component());

JavaScriptのファイルで、importで必要なファイルを読み込むことが大切です。2行目でSassのscssファイルを読み込む指示をしておくことで、Webpackのビルド作業でそのファイルがビルド対象になります。

設定ファイルを設定

package.jsonを開いて、"scripts"の設定に以下のように"start"の行を追加してください。"test"の行の最後に,を追加するのを忘れないようにしてください。

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack --watch --config webpack.config.js & browser-sync start --config bs-config.js"
  },

プロジェクトフォルダー内にwebpack.config.jsを新しく作成して、以下のような内容にします。

Webpackの実行

ターミナルでnpm startで、ビルドの実行、監視の開始、Webブラウザーの起動が実行できます。以下のようにHello webpackと赤い文字で出力されれば成功です。

f:id:am1tanaka:20171028215404p:plain

試しに、src/app.jsの以下の行を変更してみてください。

    element.innerHTML = _.join(['Hello', 'webpack change'], ' ');

変更して上書き保存をすると、自動的にWebブラウザーが更新されて画面が変わります。変更が確認できない場合、もう一度src/app.js上で[Ctrl]+[S]で上書き保存すると更新が確認できると思います。

f:id:am1tanaka:20171028215829p:plain

確認ができたら、次の作業のために[Ctrl]+[C]キーでWebpackの監視を停止してください。

Seleniumのインストール

CodeceptionでWebブラウザー上で動作確認をするAcceptanceテストを動かすために、最新のSelenium Standalone Serverをダウンロードしてプロジェクトフォルダーに入れておきます。

http://www.seleniumhq.org/download/ を開いて、最新版をダウンロードします。

f:id:am1tanaka:20171028221109p:plain

以下のような警告が表示されたら、構わないので[保存]してください。

f:id:am1tanaka:20171028221319p:plain

ダウンロードが完了したら、Finderなどを使って、selenium-server-standalone-3.6.0.jarをプロジェクトフォルダーに移動させてください。3.6.0の部分は、実際にダウンロードしたバージョンに読み替えてください。

SeleniumとCodeceptionの起動コマンドを作成

Selenium Standalone Serverの起動と、まだインストールはしていませんがCodeceptionによるテストを起動するコードをpackage.jsonの"scripts"欄に追加します。以下のように修正してください。

  "scripts": {
    "test": "composer exec codecept run -v",
    "start": "webpack --watch --config webpack.config.js & browser-sync start --config bs-config.js & java -jar ./selenium-server-standalone-3.6.0.jar"
  },

Codeception

最後に、テストのためにCodeceptionをインストールします。

以下を実行して、インストールとテスト用の環境を展開します。

composer require codeception/codeception --dev
composer exec codecept bootstrap

testsフォルダーが作成されて、その中にテスト用のファイルが作成されました。Acceptanceテスト用の設定をします。

Acceptanceテスト用の設定

tests/acceptance.suite.ymlを開いて、以下のように編集します。

actor: AcceptanceTester
modules:
    enabled:
        - WebDriver:
            url: http://localhost:3000/
            browser: chrome
        - \Helper\Acceptance

以上、Google Chromeでのテスト設定です。2017/10/27現在、Firefox56.0 ではうまく動かないようでした。

テストファイルの作成

ターミナルで以下を実行して、動作確認用のテストファイルを作成します。

composer exec codecept generate:cest acceptance CheckInst

tests/acceptance/CheckInstCest.phpを開いて、以下のようにします。

<?php

class CheckInstCest
{
    // tests
    public function tryToTest(AcceptanceTester $I)
    {
        $I->amOnPage('/');
        $I->see('Webpack and Test');
    }
}

ベースディレクトリーをWebページで表示して、画面にWebpack and Testと表示されるかを試すテストです。

開発とテストの実行

開発を始める時には、プロジェクトフォルダーで以下を実行します。

npm start

Webpackのビルドとファイル変更の監視、Browsersyncによるライブリロード、そしてSelenium Standalone Serverが起動します。

ターミナルは待機状態になって操作できなくなるので、もう一つターミナルを起動して、プロジェクトフォルダーを開きます。テストは以下で実行できます。

npm test

最初は以下のように失敗します。これは、期待している文字列Webpack and Testが画面に表示されていないからです。

f:id:am1tanaka:20171028224053p:plain

src/app.jsを開いて、表示内容を以下のように修正します。

    element.innerHTML = _.join(['Webpack', 'and', 'Test'], ' ');

上書き保存をしたら、npm testを再実行してください。表示内容が期待のものになったので、以下のようにテストが成功します。

f:id:am1tanaka:20171028224440p:plain

まとめ

以上で環境構築完了です。最初に表示されるWebページはdist/index.htmlJavaScriptのコードはsrc/app.js、Sassのコードはsrc/sass/styles.scssに書きます。また、Webブラウザー上でのテストはtests/acceptance/CheckInstCest.phpに書き加えたり、新しくCestファイルやCeptファイルを作成して書きます。

Seleniumについて補足

このブログを書いた時点では、Firefox56.0をSeleniumで呼び出せていません。調査不足かも知れませんが、Releases · mozilla/geckodriver · GitHub で新しいgeckodriverが出てきたら動くようになるかも知れません。その際は、最新のgeckodriverをダウンロードしてプロジェクトフォルダーに保存して、package.jsonの"scripts"に以下の設定を追加します。

    "selenium-ff": "java -Dwebdriver.gecko.driver=./geckodriver -jar ./selenium-server-standalone-3.6.0.jar"

npm run selenium-ffでgeckodriverを指定したSelenium Standalone Serverが起動するので、これで動くようになるかも知れません。

参考URL

Linux(やmacで)のbashでインストール済みか確認する方法

安PCのセットアップスクリプトで、インストールとアップデートを自動的に処理できるように、bashシェルスクリプトでインストール済みかの確認方法を調べました。

例えば、PHPがインストールされているかは以下のような感じ。

php -v &> /dev/null
if [ $? ] ; then
  echo インストール処理
else
  echo バージョンアップ処理
fi

コマンドの意味

記号だけだとよくわからないので、それぞれの意味。

php -v

phpのバージョンチェックです。このようにバージョンチェックなどを実行して、それが成功するか、失敗するかを試します。

&> /dev/null

php -vが返すメッセージは不要なので、標準出力、エラーのいずれも破棄しています。&>が標準出力、エラーのいずれもリダイレクトするコマンド、/dev/nullは送られてきたメッセージを破棄する記述です。

if [ $? ] ; then

$?は、先に実行されたコマンドの実行結果を返します。成功の時は0、失敗時は0以外が帰ります。これをif文で判定します。bashif0の時、成立します。[ $? ]とすることで、前の実行結果が成功したかを判定します。

elseからfiの間には、ifが不成立だった時の処理を書きます。

参考URL

します。インストールされていれば成功、インストールされていなければ失敗

Unity認定試験、受けてきました

japan.unity3d.com

日本最初のUnity認定試験。無事、合格できました!ざっくりどのような感じだったかをまとめておきます。

試験時間

90分で100問って、1問1分無いので大変そう。と思ったのですが、杞憂でした。40分ぐらいで解答を終えられました。ちゃんと勉強しておけば、じっくり取り組んでも60分はかからないと思います。

Unityのバージョンは?

不安な点の一つでしたが、試験対策講座で基準のバージョンを教えていただけました。自分はUnity5.3.8をインストールして対策勉強をしました。とはいえ、Unityコラボなどは5.5からのものですので、必ずしもその時代のものだけでもありません。バージョンによって変わるような細かいところは試験に出ない、という理解で大丈夫と思います。

試験の難易度

広く浅く知識を問われる、Unity版のITパスポートといった感じです。出題形式は以下の3タイプ。

  • 正解や間違いを一つ選ぶ選択肢形式
  • 数個のキーワードを対応づける紐付け形式
  • 画面にUnityEditorの画面が表示されて、操作する場所などを指し示すホットスポット形式

論述やコードを自分で書く必要はありません。気をつけるのは用語です。普段、何気なく使っている機能や操作をなんと呼ぶのか把握していないと、あれ?っとなります。何問か、あれ?っとなりました・・・。

どの程度対策をしたか

期間は2週間ぐらいで、本格的に集中したのは最後の1週間です。

2週間前ぐらいから、Unityの公式ページに掲載された試験目的一覧に目を通して、自分が弱い部分について公式マニュアルやチュートリアルを眺め始めました。

試験会場でもあったVRアカデミーさんの試験対策講座に申し込んでいて、事前にUnityサービスの対策情報をメーリングリストで送ってくださったので確認しました。

試験一週間前に試験対策講座。受験するならこれは絶対参加した方がいいです! 知りたいことが全て詰め込まれていました。

残り一週間で、講座で教えてもらった要点を押さえながら、Unity公式サイトのマニュアルを読み込みながらUnityを操作して練習しました。気になった用語はメモ帳に書き出して、20ページ強の対策PDFを作って、電車の移動中とかに目を通すという受験生のようなことをやってました。

コースウェアは必要か

僕はコースウェアを使わなかったので必須ということはありません。ただ、試験対策講座に参加するか、コースウェアをやらないと入手できない情報がいくつかあります。どちらか一方はやらないと大変だと思います。

コースウェアがどんなものか知らないので憶測になりますが、試験範囲が絞れるので準備が楽になると思います。あと、満点目指すのにも役立つのではと思います。

こんな人におススメ

Unityを使い始めて1~3年ぐらいで、自分がやりたいことはある程度できるけど、まだ知らないところがちらほらある、という人には、Unityの機能を俯瞰する良い機会ですのでおススメです。こんなのあったのか、というような発見があると思いますし、表現の幅が広がると思います。自腹で受験するというよりも、社員の基礎技術力向上のために会社が受験を支援するのが一番しっくりくる感じがします。

僕のように製品には関わっていないけど、講師業をやっている人にも有用だと思います。よく使う機能以外は結構知らないもので、基礎の確認に有用でした。

すでに業務でUnityを使っていたり、シェーダーとかプラグインに突っ込んでいる方が自腹で受験するのは見合わないと思います。結局のところ、認定より作品の方が説得力がありますので、名刺代わりの作品があれば必要ないと思います。ただ、Unityさんにお世話になっている気持ちを表すお賽銭代わりに受験するのは、大いにアリだと思います。ファングッズみたいなものですよね。お、持ってますね、ニヤッ、みたいな。

準備の仕方

ざっくりと準備の仕方です。

まずは、試験目的一覧のうち、「職務における心構え」「ゲームアートの原則」「ゲームデザインの原則」「業界情報」の4項目以外について、Unityの公式マニュアルに目を通しつつ、Unityを操作して、関連する操作などを全てやっておきます。突っ込んだ問題は殆ど出ませんので、一通りの操作方法と効果を確認して、あとは用語の把握、マニュアルに書いてある操作手順を確認しておけばオッケーです。マニュアルで分からない部分は、公式チュートリアルYouTubeを探すと色々と見つかると思います。

あと、知的財産権と、秘密保持契約については、簡単に調べてまとめておくとよいです。

ここまで終わらせるのにどれぐらいかかるかは、キャリアや知識によって大きく異なると思います。キャリアが浅い場合は何ヶ月かかかるかも知れません。期間が読めないので、ここまで終わらせてから受験日を設定するのが無難と思います。一覧の項目を全て触ったことがあるなら、一覧を見るだけで十分かも知れません。

4項目以外の試験目的一覧の内容や操作が把握できたら、試験日程を調べて、受験一週間前のVRアカデミーさんの試験対策講座とセットで申し込むのをおススメします。

試験対策講座で、試験についての具体的な内容や重点ポイント、対策しなかった4項目について教えていただけます。あとはそれらについて準備すれば合格点は取れると思います。

試験対策講座に出られないとか、自力では操作が調べられなかった場合はコースウェアを検討するとよいと思います。

最後に

これまでノータッチだったAudioMixerやUnity Ads、あやふやだったLightingやアニメーション、UI周りについて、試験対策のために、かなりまじめに読み込んで理解を深められました。受験料を無駄にしたくない一心で頑張れたのは大きかったです。

僕はUnityでゲームを作ることはできますが、製品を作っている訳ではありません。では何をもって人に教えているのかとなった時に、少なくとも認定試験は通っている、というのは励みになりそうです(とかいいつつ、日本最速の!という部分で楽しくなって勢いで申し込んだような気もしますが)。

最後にの最後に

退室時にシャツをいただきました。暖かそうな生地でこれから活躍しそうです。VRアカデミーさん、的確なサポートと運営、ありがとうございました!

一緒に受験されたみなさま、お疲れ様でした。合格されたみなさま、おめでとうございます!不合格だった方も、問題の雰囲気や内容は把握できたことと思いますので、対策したら一気に点数が伸びると思います。懲りずに頑張ってください!

f:id:am1tanaka:20171015012308j:plain

リンク