Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

第2回html5jゲーム部勉強会 Oh! JavaScript 夢の続きを語ろうよ〜emscriptenの逆襲 - html5編

2,830 views

Published on

SION2HDについてHTML5の観点から

Published in: Technology
  • Be the first to comment

  • Be the first to like this

第2回html5jゲーム部勉強会 Oh! JavaScript 夢の続きを語ろうよ〜emscriptenの逆襲 - html5編

  1. 1. 夢の続きを語ろうよ Emscriptenの逆襲 HTML5編
  2. 2. sun6925 とよしま ウェブ大好きっ子 低レイヤー大好きっ子 レトロPC大好きっ子 X68000大好きっ子 わーい!すごーい!たーのしー!
  3. 3. 知ってますか? ● なぜか 編集部が作ったゲーム ○ 創刊10周年記念 PRO-68K に収録 (雑誌付録ディスク) ○ 編集部制作の強力インフラ ■ MAGIC2 - 3D描画ライブラリ ■ Z-MUSIC - サウンドドライバ ○ ゲーム自体、普通に面白い ○ 25年前!
  4. 4. 実演 原作@エミュレータ
  5. 5. あれ?ショボい! 256 x 256 ドット 16 色 ワイヤフレーム ・ ・ ・ んじゃ、高解像度化しますか
  6. 6. 実演 ハイレゾ@ウェブ bit.ly/sion2
  7. 7. 原作をウェブで Powered by Emscripten run68 (in C) sion2.x (Binary for X68k) 実行 JavaScript VM 実行 互換レイヤー (in JavaScript) DOS/IOCS MAGIC Z-MUSIC GVRAM I/O z-music.js zmusic.x (Binary for X68k) 非同期RPC化 ここで気合 ハイレゾ化するぞ! X68Sound.dll (in C++) run68 (in C) 基本方針:エミュレータ+黒魔術
  8. 8. 高解像度+16:9化 256 pixel 256 lines ピクセル アスペクト比 4:3 1080 lines 1440 pixel 4:3 1920 pixel 16:9 アスペクト比補正+ベクトル拡大 +本来見えていなかった部分の表示 ワイヤーフレームは楽勝
  9. 9. スプライトやBGパターンの描画 座標とパタン番号等を拾ってCanvasに高解像度で描画 X : 140 Y : 80 Pattern: 1 Xflip : No Yflip : No I/OアクセスからGVRAMの中身を追跡 ❏ (140, 8)を表示座標に変換 ❏ Pattern 1なら星を描画
  10. 10. ビットマップ文字のベクターフォント置き換え 一部の文字(4×6サイズ)が画像だった ● 仕方ないのでGVRAMのアクセスパタンから文字推定 { “111010101110101010100000”: 64, ... } 文字コード64 A
  11. 11. 内部で使ってる主な技術 ● Web App Manifest : ホーム追加・全画面起動 ● HTML5 Canvas(2D) ○ requestAnimationFrame : 60fps ○ ダブルバッファ ○ WebFonts : Canvasで正しく使おう ● Gamepad API / TouchEvent ● DeviceOrientationEvent ● Web Audio API : FM音源と音響処理 ● Web MIDI API : 外部音源による演奏対応
  12. 12. モバイルでホームに追加・全画面起動 Web App Manifest (manifest.json) ❏ ファイルを置くだけ { "name": "SION2 HD", "icons": [ … ], "start_url": "index.html", "display": "standalone", "orientation": "landscape" }
  13. 13. 画面描画 描画ループにrequestAnimationFrameを使う ❏ Emscripten内からはemscripten_set_main_loop(fps=0)を使いましょう void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop) Canvas 2面を重ねて交互に表示 ❏ display: [none|block]を交互に切り替える ❏ オフスクリーン→Canvas転送は(読み出しが)遅いので避けるべき WebFontsをCanvasで正しく使う ❏ 遅延読み込みを正しく扱う必要があるので注意しましょう
  14. 14. WebFontsについて補足(1) 遅延読み込みについて ❏ 実際にレンダリングに必要になったときに読み込みが始まる ❏ 読み込み完了までは利用できない ❏ HTMLで使っている分には自動的に読み込み待ちや再描画が行われる ❏ Canvas API経由で使うためには正しく読み込みを待って描画する必要がある 正しく読み込み待ちするための手順(Edge非対応) 1. document.fonts (FontFaceSet)にフォントを登録 2. フォントの読み込みを開始させる 3. フォントの読み込み完了を待つ
  15. 15. WebFontsについて補足(2) 1. FontFaceSetに登録 ❏ FontFaceで作成したフォントの場合: document.fonts.add(fontFace) ❏ CSSで指定したフォントの場合、自動的に登録されるので考慮不要 2. フォントの読み込みを開始させる ❏ FontFaceで作成したフォントの場合: FontFace.load() ❏ 登録済みのフォントの場合: document.fonts.load(“50px myfont”) 3. 読み込み完了を待つ ❏ フォント個別: FontFace.load / document.fonts.loadの返すPromiseを待つ ❏ フォント全部: document.fonts.ready : Promise を待つ
  16. 16. Gamepad API ❏ Androidでも利用可能 ❏ この手(→)のBluetoothの物が使える (Amazonで今日現在260円!!!) ❏ Cardboard対応を考えると一家に一台 ❏ APIの仕様は極めて単純明快 ❏ ただし、WebKit系では利用できない const gamepads = navigator.getGamepads(); // gamepads[].axes[], gamepads[].buttons[]をチェック
  17. 17. TouchEvent ❏ タッチ対応デバイスならmobile/desktopで利用可能 ❏ マルチタッチも対応可能 ❏ 基本的にネイティブアプリと同等の処理ができるはず ❏ 使いやすい「方向キー」実現のためにはノウハウも必要 今回利用したアルゴリズム例: ❏ タッチ地点を起点として、移動した方向に入力を取る ❏ 逆方向の移動を検知したら入力キャンセル、起点の取り直し ノウハウを持った人によるライブラリ化が望まれる
  18. 18. DeviceOrientationEvent ❏ Cardboardを使ってヘッドトラッキング! ❏ この手(→)のスマホ用VRケースが使える (Amazonで今日現在998円!!!) ❏ EventListenerを登録するだけ デバイスの傾きがEular角で通知される →3D計算の視点に取り込めば向いた方向で視点を動かせる window.addEventListener('deviceorientation', e => { // e.alpha, e.beta, e.gamma });
  19. 19. Web Audio API ❏ JavaScriptでリアルタイム波形合成 ❏ 現仕様はノイズ耐性が低い(描画負荷やGCに気をつける) ❏ 今年登場すると思われるAudio Workletを使えば改善される ❏ FM音源エミュレーション ❏ とは言いつつEmscriptenでコンパイルしたC++コードでも動いてる ❏ バッファサイズ2048の場合:~42msecごとに1-2msecの合成処理 ❏ リバーブ ❏ ConvolverNodeにインパルス応答を渡すだけで実現可能
  20. 20. Web MIDI API ❏ Web MIDI経由で外部音源による演奏をサポート ❏ 中で動いているZ-MUSICに対し、MIDIボードに対するI/O操作を フックしてWeb MIDIに繋ぎこんでいる ❏ Web Audio / MIDIについて詳しく知りたい人 ❏ Web Music Developers JP ❏ WebAudio.tokyo
  21. 21. まとめ ● エミュレータ+黒魔術で昔のゲームを移植 ● HTML5でネイティブ同様の作り込みが可能 ○ モバイルホーム画面追加・全画面起動 ○ 60フレーム+ダブルバッファでヌルヌル描画 ○ リッチなフォント ○ ゲームパッド・タッチ操作 ○ ヘッドトラッキングによる視点移動 ○ リアルタイム合成による音源エミュレーション ○ 外部楽器を用いたBGM演奏
  22. 22. 質問など
  23. 23. Emscriptenまめ知識〜その1 描画ループにrequestAnimationFrameを使う ❏ emscripten_set_main_loop()を使いましょう void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop) ❏ fpsに0を指定するとrequestAnimationFrameが使われる ❏ それ以外の値だとsetTimeoutを使うので注意 ❏ 失敗談:知らずにsetTimeoutを書き換えて中からrAF呼んでた ❏ simulate_infinite_loop=1でこの関数から戻らない
  24. 24. Emscriptenまめ知識〜その2 常駐するサービス・ライブラリを作る ❏ emscripten_exit_with_live_runtime()で常駐 void emscripten_exit_with_live_runtime(void) ❏ ひとまず実行終了 ❏ ただしatexit()系やリソース解放処理は走らない ❏ JavaScriptからC/C++の関数を継続して呼び出し可能 ❏ 空のmain()から呼べば共有ライブラリっぽい物が作れる
  25. 25. Emscriptenまめ知識〜その3 JavaScriptから呼び出せる関数を(確実に)作る ❏ リンク時に-s EXPORTED_FUNCTIONS="..." ❏ "..."にはmainを含めた関数のリストを渡す 例:"['_main', '_myAPI1', '_myAPI2']" ❏ 関数名は"_"のプレフィクスが付くので注意 ❏ 数値以外は直接渡せない点に注意 ❏ C/C++側のメモリ空間はModule.HEAPU8等でアクセス ❏ Module.cwrap()やWebIDL-Binderなどの道具はある
  26. 26. Emscriptenまめ知識〜その4 JavaScriptのライブラリを呼び出す ❏ リンク時に--js-library myLibrary.jsで組み込む ❏ 渡すJavaScriptは特定の方法で記述されている必要がある mergeInto(LibraryManager.library, { myFunc: function(a, b) { // ここから外の世界は直接触れる(this==Window) console.info(‘hello my func’); return a + b; }, // 以下、同様に関数を定義 }); ❏ 登録なしでCから呼ぶとundefined symbolで実行時abort
  27. 27. Emscriptenまめ知識〜その5 実行開始を遅延させる ❏ preInit内でaddRunDependency()を呼ぶ ❏ 対応するremoveRunDependency()が呼ばれるまで待つ ❏ WebFonts読み込みを待つ例 preInit: function() { Module.addRunDependency("fonts"); document.fonts.ready.then(function() { Module.removeRunDependency("fonts"); }); },

×