第2回html5jゲーム部勉強会 oh! javascript...

27
夢の続きを語ろうよ Emscriptenの逆襲 HTML5

Upload: takashi-toyoshima

Post on 12-Apr-2017

1.538 views

Category:

Technology


2 download

TRANSCRIPT

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

夢の続きを語ろうよ

Emscriptenの逆襲HTML5編

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

sun6925 とよしま

ウェブ大好きっ子

低レイヤー大好きっ子

レトロPC大好きっ子

X68000大好きっ子

わーい!すごーい!たーのしー!

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

知ってますか?● なぜか 編集部が作ったゲーム

○ 創刊10周年記念 PRO-68K に収録(雑誌付録ディスク)

○ 編集部制作の強力インフラ

■ MAGIC2 - 3D描画ライブラリ

■ Z-MUSIC - サウンドドライバ

○ ゲーム自体、普通に面白い

○ 25年前!

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

実演原作@エミュレータ

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

あれ?ショボい!

256 x 256 ドット 16 色 ワイヤフレーム

・・・

んじゃ、高解像度化しますか

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

実演ハイレゾ@ウェブ

bit.ly/sion2

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

原作をウェブで

Powered by Emscripten

run68 (in C)

sion2.x(Binary for X68k)

実行

JavaScript VM

実行

互換レイヤー(in JavaScript)

DOS/IOCSMAGIC

Z-MUSICGVRAM I/O

z-music.js

zmusic.x(Binary for X68k)

非同期RPC化

ここで気合ハイレゾ化するぞ!

X68Sound.dll (in C++)

run68 (in C)

基本方針:エミュレータ+黒魔術

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

高解像度+16:9化

256 pixel

256 lines

ピクセルアスペクト比

4:3 1080 lines

1440 pixel

4:3

1920 pixel

16:9

アスペクト比補正+ベクトル拡大

+本来見えていなかった部分の表示

ワイヤーフレームは楽勝

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

スプライトやBGパターンの描画

座標とパタン番号等を拾ってCanvasに高解像度で描画

X : 140Y : 80Pattern: 1Xflip : NoYflip : No

I/OアクセスからGVRAMの中身を追跡

❏ (140, 8)を表示座標に変換

❏ Pattern 1なら星を描画

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

ビットマップ文字のベクターフォント置き換え

一部の文字(4×6サイズ)が画像だった

● 仕方ないのでGVRAMのアクセスパタンから文字推定

{ “111010101110101010100000”: 64, ... }

文字コード64 A

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

内部で使ってる主な技術

● Web App Manifest : ホーム追加・全画面起動

● HTML5 Canvas(2D)○ requestAnimationFrame : 60fps

○ ダブルバッファ

○ WebFonts : Canvasで正しく使おう

● Gamepad API / TouchEvent

● DeviceOrientationEvent

● Web Audio API : FM音源と音響処理

● Web MIDI API : 外部音源による演奏対応

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

モバイルでホームに追加・全画面起動

Web App Manifest (manifest.json)

❏ ファイルを置くだけ { "name": "SION2 HD", "icons": [ … ], "start_url": "index.html", "display": "standalone", "orientation": "landscape"}

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

画面描画

描画ループに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で正しく使う❏ 遅延読み込みを正しく扱う必要があるので注意しましょう

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

WebFontsについて補足(1)

遅延読み込みについて❏ 実際にレンダリングに必要になったときに読み込みが始まる

❏ 読み込み完了までは利用できない❏ HTMLで使っている分には自動的に読み込み待ちや再描画が行われる

❏ Canvas API経由で使うためには正しく読み込みを待って描画する必要がある

正しく読み込み待ちするための手順(Edge非対応)1. document.fonts (FontFaceSet)にフォントを登録

2. フォントの読み込みを開始させる

3. フォントの読み込み完了を待つ

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

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 を待つ

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

Gamepad API

❏ Androidでも利用可能❏ この手(→)のBluetoothの物が使える

(Amazonで今日現在260円!!!)

❏ Cardboard対応を考えると一家に一台

❏ APIの仕様は極めて単純明快

❏ ただし、WebKit系では利用できない

const gamepads = navigator.getGamepads();// gamepads[].axes[], gamepads[].buttons[]をチェック

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

TouchEvent

❏ タッチ対応デバイスならmobile/desktopで利用可能❏ マルチタッチも対応可能

❏ 基本的にネイティブアプリと同等の処理ができるはず

❏ 使いやすい「方向キー」実現のためにはノウハウも必要

今回利用したアルゴリズム例:

❏ タッチ地点を起点として、移動した方向に入力を取る

❏ 逆方向の移動を検知したら入力キャンセル、起点の取り直し

ノウハウを持った人によるライブラリ化が望まれる

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

DeviceOrientationEvent

❏ Cardboardを使ってヘッドトラッキング!❏ この手(→)のスマホ用VRケースが使える

(Amazonで今日現在998円!!!)

❏ EventListenerを登録するだけ

デバイスの傾きがEular角で通知される

→3D計算の視点に取り込めば向いた方向で視点を動かせる

window.addEventListener('deviceorientation', e => { // e.alpha, e.beta, e.gamma});

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

Web Audio API

❏ JavaScriptでリアルタイム波形合成❏ 現仕様はノイズ耐性が低い(描画負荷やGCに気をつける)

❏ 今年登場すると思われるAudio Workletを使えば改善される

❏ FM音源エミュレーション❏ とは言いつつEmscriptenでコンパイルしたC++コードでも動いてる

❏ バッファサイズ2048の場合:~42msecごとに1-2msecの合成処理

❏ リバーブ❏ ConvolverNodeにインパルス応答を渡すだけで実現可能

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

Web MIDI API

❏ Web MIDI経由で外部音源による演奏をサポート❏ 中で動いているZ-MUSICに対し、MIDIボードに対するI/O操作を

フックしてWeb MIDIに繋ぎこんでいる

❏ Web Audio / MIDIについて詳しく知りたい人❏ Web Music Developers JP

❏ WebAudio.tokyo

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

まとめ

● エミュレータ+黒魔術で昔のゲームを移植

● HTML5でネイティブ同様の作り込みが可能○ モバイルホーム画面追加・全画面起動

○ 60フレーム+ダブルバッファでヌルヌル描画

○ リッチなフォント

○ ゲームパッド・タッチ操作

○ ヘッドトラッキングによる視点移動

○ リアルタイム合成による音源エミュレーション

○ 外部楽器を用いたBGM演奏

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

質問など

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

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でこの関数から戻らない

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

Emscriptenまめ知識〜その2

常駐するサービス・ライブラリを作る

❏ emscripten_exit_with_live_runtime()で常駐void emscripten_exit_with_live_runtime(void)

❏ ひとまず実行終了

❏ ただしatexit()系やリソース解放処理は走らない

❏ JavaScriptからC/C++の関数を継続して呼び出し可能

❏ 空のmain()から呼べば共有ライブラリっぽい物が作れる

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

Emscriptenまめ知識〜その3

JavaScriptから呼び出せる関数を(確実に)作る

❏ リンク時に-s EXPORTED_FUNCTIONS="..."❏ "..."にはmainを含めた関数のリストを渡す

例:"['_main', '_myAPI1', '_myAPI2']"

❏ 関数名は"_"のプレフィクスが付くので注意

❏ 数値以外は直接渡せない点に注意❏ C/C++側のメモリ空間はModule.HEAPU8等でアクセス

❏ Module.cwrap()やWebIDL-Binderなどの道具はある

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

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

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

Emscriptenまめ知識〜その5

実行開始を遅延させる

❏ preInit内でaddRunDependency()を呼ぶ❏ 対応するremoveRunDependency()が呼ばれるまで待つ

❏ WebFonts読み込みを待つ例preInit: function() { Module.addRunDependency("fonts"); document.fonts.ready.then(function() { Module.removeRunDependency("fonts"); });},