投稿されたすべてのトピック

WebAssembly の短期集中コース

この記事は WebAssembly と何が速くしたのかのシリーズの 3 部です。もしまだ前の記事を読んでいない場合、最初から読むことをお勧めします。どのように WebAssembly が動いているかを理解するために、アセンブリが何でありどのようにアセンブリを生成するのかを理解することが役に立ちます。

JIT の記事では、機械とのやりとりがエイリアンとのコミュニケーションのようなものだと話しました。

A person holding a sign with source code on it, and an alien responding in binary

エイリアンの脳がどのように働いているのか、機械の脳はどのように解析してそこに入ってくるコミュニケーションを理解しているのかを見てみたいと思います。

この脳の一部は、思考に専念しています。つまり、加減算や論理演算などです。短期記憶を提供する脳の部分と、長期記憶を提供するもう一つの部分もあります。

これらの異なる部分には名前があります。

  • 思考を行う部分は算術論理ユニット (ALU) です。
  • 短期記憶はレジスタによって提供されます。
  • 長期記憶はランダムアクセスメモリ (もしくはRAM) です。

A diagram showing the CPU, including ALU and Registers, and RAM

マシン語の文章は命令と呼びます。

これらの命令の 1 つが脳に入ったらどうなりますか?それは異なることを意味する異なる部分に分割されます。

この命令が分割される方法はこの脳の配線に固有のものです。

例えばこのように配線された脳は、常に最初の 6 ビットを取り、それを ALU にパイプすることができます。 ALU は 1 と 0 の位置に基づいて、2 つのものを一緒に追加する必要があることを理解します。

この 塊は ALU にどのような操作を実行するかを指示するため、「オペコード」またはオペレーションコードと呼ばれます。

6-bits being taken from a 16-bit instruction and being piped into the ALU

次に、この脳は次の 2 つのチャンクをそれぞれ 3 ビットずつ取って、どの 2 つの数字を追加するかを決定します。 これらはレジスタのアドレスになります。

Two 3-bit chunks being decoded to determine source registers

ここで機械語の上に注釈があることに注意してください。これは人間が何が起こっているのかを理解しやすくします。これがアセンブリです。シンボリックマシンコードとも呼ばれており、人間が機械語を理解する方法です。

ここには、この機械のためのアセンブリと機械語の間にかなり直接的な関係があることがわかります。このため、さまざまな種類の機械のアーキテクチャー向けにに異なる種類のアセンブリがあります。機械の内部で別のアーキテクチャを使用している場合は、独自の方言のアセンブリが必要になる可能性があります。

だから私たちは翻訳の目標を一つだけ持っているわけではありません。これは、機械語と呼ばれる単なる言語ではありません。これは、さまざまな種類の機械語です。私たちが人としてさまざまな言語を話すように、機械は異なる言語を話します。

人からエイリアンへの翻訳では英語、ロシア語、または北京語からエイリアン語Aまたはエイリアン語Bに移行している可能性があります。プログラミング上、これはC、C ++、Rustからx86またはARMへの変換に似ています。

これらの高レベルのプログラミング言語のいずれかをこれらのアセンブリ言語のいずれかに翻訳したいと考えています (異なるアーキテクチャに対応しています)。これを行うための 1 つの方法は、各言語から各アセンブリに変換することができるさまざまな翻訳者をたくさん作成することです。

Diagram showing programming languages C, C++, and Rust on the left and assembly languages x86 and ARM on the right, with arrows between every combination

それはかなり非効率的になるでしょう。これを解決するため、ほとんどのコンパイラは少なくとも 1 つのレイヤを中間に配置します。コンパイラはこの高水準のプログラミング言語をとり、これを高レベルではないものに変換しますが、機械語のレベルでは動作しません。 それは中間表現 (IR) と呼ばれています。

Diagram showing an intermediate representation between high level languages and assembly languages, with arrows going from high level programming languages to intermediate representation, and then from intermediate representation to assembly language

これはコンパイラがこれらの上位レベルの言語のいずれかを取り、それを 1 つの IR 言語に翻訳できることを意味します。そこから、コンパイラの別の部分がその IR を取得し、ターゲットアーキテクチャに固有のものにコンパイルすることができます。

コンパイラのフロントエンドは、上位レベルのプログラミング言語を IR に変換します。コンパイラのバックエンドは、IR からターゲットアーキテクチャのアセンブリコードに移行します。

Same diagram as above, with labels for front-end and back-end

Conclusion

これはアセンブリの仕組みと、コンパイラがどのように高水準のプログラミング言語をアセンブリに変換するかです。次の記事では、WebAssembly がこれにどのように適合するかを見ていきます。

Lin Clark に関して

Lin は Mozilla Developer Relations チームのエンジニアです。 彼女は JavaScript、WebAssembly、Rust、Servo を使っています。また、コードの漫画を描きます。

Lin Clark によるその他の記事はこちら…

ジャスト・イン・タイム (JIT) コンパイラの短期集中コース

この記事は WebAssembly と何が速くしたのかのシリーズの2部です。もしまだ前の記事を読んでいない場合、最初から読むことをお勧めします。JavaScript は最初は遅かったですが、JIT と呼ばれるもののお陰で速くなりました。JIT はどのように機能しているのでしょうか?

JavaScript はブラウザ上でどのように動作しているか

開発者として JavaScript を追加すると、ゴールと問題が出てきます。

ゴール : コンピュータへ何かを伝えたいと思います

問題 : あなたとコンピュータは別の言語を話します

あなたは人間の言語を話し、コンピュータは機械語を話します。JavaScript や他の高レベルのプログラミング言語を人間の言語として考えていなくても、実際にはそうです。これらは人間の認知のために開発されたものであり、コンピュータの認知のために考えられたものではありません。

JavaScript のエンジンの仕事は人間の言葉を機械が理解できるように変換することです。

人間とエイリアンがお互いに話そうとしている映画、「メッセージ」のように考えています。

A person holding a sign with source code on it, and an alien responding in binary

この映画では、人間とエイリアンは一語一語の翻訳をするわけではありません。2つのグループは世界に関して別の考え方を持っています。そして人間と機械に関してもそうです (次の記事でこの映画に関してはもっと説明します) 。

では翻訳はどのように行いますか?

プログラミングでは、機械語に翻訳するには一般的に 2 つの方法があります。

インタープリタでは、この翻訳は直ちに一行一行実施します。

A person standing in front of a whiteboard, translating source code to binary as they go

一方コンパイラは直ちに翻訳を行いません。翻訳を作成して、それを書きとめる前に動作します。

A person holding up a page of translated binary

これらの翻訳処理方法にはそれぞれ長所と短所があります。

インタープリタの長所と短所

インタープリタはすぐに起動して実行できます。コードの実行を開始する前に、コンパイルの手順全体を踏む必要はありません。 最初の行を翻訳して実行するだけです。

このため、インタプリタは JavaScript のようなものに自然にフィットするように見えます。Web 開発者がコードをすぐに実行できるようにすることが重要です。

そしてそれが様々なブラウザが最初から JavaScript インタープリタを使用していた理由です。

しかし同じコードを何度も実行するときに毎回翻訳が必要というインタープリタの問題があります。例えば、ループを使用するときがそうです。この時同じ翻訳を何度も何度も実行する必要があります。

コンパイラの長所と短所

コンパイラは対称的なトレードオフを持っています。

開始時にコンパイルを行うステップを経ないといけないため、起動に少し時間がかかります。 しかし、ループ内のコードパスはそのループを通過するたびに翻訳を繰り返す必要がないため、実行速度が速くなります。

もう一つの違いはコンパイラはコードの中身を確認し、より速く動作するように編集を行う時間があることです。これらの編集は最適化と呼ばれています。

インタープリタは実行時に作業を行っているため、これらの最適化を理解の翻訳フェーズでは時間がかかりません。

ジャスト・イン・タイム コンパイラ : 2つの世界の最も優れたもの

インタプリタの非効率性を取り除く方法として、インタプリタがループを通過するたびにコードの再翻訳を続ける必要がある場合に、ブラウザがコンパイラを混在させることを開始しました。

別のブラウザではこの方法はやや異なっていますが、基本的なアイデアは同じです。これらではモニター (別名プロファイラ) と呼ばれる JavaScript エンジンへ新しい機能を追加しました。そのモニターは実行中のコードを監視し、何回動作したかとどのようなタイプで使われるのかを記録します。

まず最初にモニターはインタープリタを通してすべてを実行します。

Monitor watching code execution and signaling that code should be interpreted

もし同じ行を何度か通った場合、コードのその部分は “warm” と呼ばれます。もし何度も動作する場合、ここは “hot” と呼ばれます。

ベースラインコンパイラ

関数が “warm” な状態になると、JIT はそれを送信しコンパイルします。そしてコンパイル結果を保存します。

Monitor sees function is called multiple times, signals that it should go to the baseline compiler to have a stub created

関数の各行は “スタブ” にコンパイルが行われます。スタブは行番号と変数タイプによって索引付けします (なぜ重要なのかは後で説明します) 。 モニタにより同じ変数の型で同じコードを実行していることが確認した場合、コンパイルしバージョンを取り出します。

それはスピードアップするのに役立ちます。しかし、先程述べたように、コンパイラができることはもっとあります。最適化を行うための最も効率的なやり方を理解するまでには時間がかかることがあります。

ベースラインコンパイラはこれらの最適化の幾つかを行います (以下に例を示します )。長い時間作業を保留にしたくないため、これらに多くの時間をかけたくありません。

しかしコードが本当に “hot” な場合、—もしそれが一杯になったら— このような時にさらなる最適化を実施する時間を余分にとる価値があります。

コンパイラの最適化

コードの一部がとても “hot” な時、モニターは最適化コンパイラに対してそれを送信します。これにより、保存される関数の別のより高速なものが作成されます。

Monitor sees function is called even more times, signals that it should be fully optimized

コードのより高速なバージョンを作るために、最適化コンパイラはいくつかの過程を行う必要があります。

例えば、特定のコンストラクタによって作成されたすべてのオブジェクトが同じ形状を持っていると仮定することができます。つまり、それらは常に同じプロパティ名を持ち、それらのプロパティは同じ順序で追加され、それに基づいていくつかのコーナーをカットすることができます。

最適化コンパイラはモニターが監視したコードの実行状態の情報を使用します。ループが通る前のすべてのパスが真だった場合、それらは引き続き真だとみなされます。

もちろん JavaScript を使用した場合、それらの保証はありません。あなたが 99 個の同じ形状のオブジェクトを持ってしたとしても、100 個目のオブジェクトはプロパティが無いかもしれません。

従ってコンパイルされたコードは仮定が正しいかどうかを動作させる前に確認する必要があります。もし正しければコンパイルされたコードを動作させます。もし正しくなければ、JIT は誤った仮定とみなし、最適化したコードを破棄します。

Monitor sees that types don't match expectations, and signals to go back to interpreter. Optimizer throws out optimized code

その後、実行するコードはインタプリタまたはベースラインのコンパイルされたバージョンに戻ります。このプロセスは最適化解除 (または救済) と呼ばれます。

たいていの最適化コンパイラはコードを速く動くようにしますが、時々期待されないパフォーマンスの問題が発生します。最適化を続けて最適化を行わないコードがある場合、ベースラインのコンパイル済みバージョンを実行するよりも遅くなります。

ほとんどのブラウザでは最適化/最適化解除のサイクルに問題が発生した時、終了させる制限を加えています。もし JIT が最適化を 10 回以上試行しそれを捨て続けた場合、試行をやめます。

最適化の例 : 型の特殊化

さまざまな種類の最適化がありますが、1 つの型を見て最適化がどのように起こるかを感じることができます。コンパイラの最適化で最も大きな成果を得たのは、型の特殊と呼ばれるものです。

JavaScriptが利用する動的型システムでは、実行時に余分な作業が必要です。例えば、次のコードで考えてみましょう。

<code>

function arraySum(arr) {
  var sum = 0;
  for (var i = 0; i &lt; arr.length; i++) {
    sum += arr;
  }
}
</code>
ループ内の += ステップは単純に思えるかもしれません。これを 1 ステップで計算できるように思えるかもしれませんが、動的な型付けのために予想以上に多くのステップが必要となります。

arr が 100 個の整数の配列であるとしましょう。コードが “warm up” すると、ベースラインコンパイラは関数内の各演算のスタブを作成します。そのため sum += arr のスタブがあり、これは += 演算を整数加算として扱います。

しかし、sum arr は整数であるとは限りません。 JavaScript では型が動的なので、ループの後の反復で、arr が文字列になる可能性があります。 整数の加算と文字列の連結は非常に異なる2つの操作なので、非常に異なる機械語にコンパイルされます。

JIT がこれを処理する方法は、複数のベースライン・スタブをコンパイルすることです。 コードの一部が単調である (つまり、常に同じ型で呼び出される) 場合、それは 1 つのスタブを取得します。 それがポリモーフィックである場合 (あるコードから別のコードへと異なるタイプで呼び出されます) 、その操作を経たタイプの各組み合わせに対してスタブを取得します。

これは JIT はスタブを選ぶ前に多くの質問をする必要が有ることを意味します。

Decision tree showing 4 type checks

コードの各行はベースラインコンパイラに独自のスタブセットを持つため、JIT はコードの各行が実行されるたびに型のチェックを実施し続ける必要があります。そしてループを通るそれぞれのイテレーションのために、同じ質問をする必要があります。

Code looping with JIT asking what types are being used in each loop

JIT がこれらのチェックを繰り返す必要がない場合、コードはより高速に実行されます。 そして、これは最適化コンパイラが行うことの 1 つです。

最適化コンパイラでは、関数全体が一緒にコンパイルされます。 型チェックは、ループの前に実施するように移動されます。

Code looping with questions being asked ahead of time

一部の JIT ではこれをさらに最適化します。 例えば、Firefox には、整数だけを含む配列の特別な分類があります。 arr がこれらの配列のいずれかである場合、JIT は arr が整数かどうかを確認する必要はありません。これは、JIT がループに入る前にすべての型チェックを実行できることを意味します。

結論

それを簡潔に言えば JIT です。コードを実行しながらコードを監視し、”hot” なコードパスを送信して最適化することで、JavaScript をより速く実行できます。 これにより、ほとんどの JavaScript アプリケーションのパフォーマンスが数倍に向上しました。

しかし、これらの改良によっても、JavaScript のパフォーマンスは予測できません。さらに高速化するために、JIT は実行時にいくつかのオーバーヘッドが増えています :

  • 最適化と最適化解除
  • 救済措置が起こったときのモニタの記録と復旧情報に使用されるメモリ
  • 関数のベースラインバージョンと最適化バージョンを格納するために使用されるメモリ
ここに改善の余地があります : オーバーヘッドが取り除かれ、パフォーマンスが予測可能になります。それが WebAssembly が行うことの 1 つです。

次の記事では、アセンブリとコンパイラがどのように動作するかについて、さらに詳しく説明します。

Lin Clark に関して

Lin は Mozilla Developer Relations チームのエンジニアです。 彼女は JavaScript、WebAssembly、Rust、Servo を使っています。また、コードの漫画を描きます。

Lin Clark によるその他の記事はこちら…

WebAssembly の漫画での紹介

[この記事は”A cartoon into to WebAssembly“の翻訳です]

WebAssembly は高速です。あなたはおそらくこのことは聞いたことがあるでしょう。しかし何が WebAssembly を高速に動作することをできるようにしているのでしょうか?

このシリーズでは、なぜ WebAssembly が高速に動作するのかの説明を行いたいと思います。

WebAssembly とは何ですか?

WebAssembly は JavaScript 以外のプログラミング言語で書かれたコードをブラウザ上で実行する方法です。人々が WebAssembly が高速と言っているときは、JavaScript と比較しています。

今、私はあなたがWebAssemblyを使用しているかJavaScriptを使用しているかに関しては暗示したくありません。 実際、開発者が同じアプリケーションで WebAssembly と JavaScript の両方を使用することを期待しています。

しかし、これら2つを比較することは有益であり、WebAssembly が持つであろうインパクトを理解することができるでしょう。

パフォーマンスの歴史を少し

JavaScript は1995年に作成されました。しかし高速に動くように設計されてはおらず、最初の10年は速くありませんでした。

その後ブラウザはより競争的になりました。

2008年、人々がパフォーマンス戦争と呼ぶ期間が始まりました。複数のブラウザに JIT とも呼ばれるジャストインタイムコンパイラが追加されました。 JavaScript が実行されているため、JIT はパターンを見て、そのパターンに基づいてコードをより高速に実行することができます。

これらの JIT の導入により、JavaScript のパフォーマンスに変革がもたらされました。 JavaScript の実行速度は10倍になりました。

A graph showing JS execution performance increasing sharply in 2008

パフォーマンスが改良されたことにより、JavaScript は Node.js を使ったサーバーサイドプログラミングのように、これまでに使用されることが予想されなかったものに対して使用され始めました。 パフォーマンスの向上により、全く新しい種類の問題に JavaScript を使用することが可能になりました。

もしかすると我々は今、WebAssembly によって新たな変曲点にいるのかもしれません。

A graph showing another performance spike in 2017 with a question mark next to it

では、WebAssembly を高速化する要素を理解するために詳細を掘り下げてみましょう。

背景:

過去の WebAssembly:

未来の WebAssembly:

Lin Clark に関して

Lin は Mozilla Developer Relations チームのエンジニアです。 彼女は JavaScript、WebAssembly、Rust、Servo を使っています。また、コードの漫画を描きます。

Lin Clark によるその他の記事はこちら…

Firefox 54 アドオン互換性情報

Mozilla では Firefox 57 へ向けたロードマップ を投稿しています。もしまだ読んでいなければ目を通してみてください。

Firefox 54 は 6 月 13 日 [日本時間同日深夜] リリース となります。Firefox 54 の変更点でアドオンの互換性に影響を及ぼす可能性のあるものを以下にまとめました。Firefox 54 for Developers により詳しい情報が載っていますので、こちらも併せてご覧ください。

一般

  • -moz-appearance が削除されました。この変更は chrome:// URL で読み込まれたスタイルシートには適用されませんが、XUL や JavaScript コード内のインライン CSS には影響します。

XPCOM とモジュール

WebExtensions

この一覧に載っていない変更点や間違いを見つけたらコメント欄でお知らせください。もしあなたのアドオンが Firefox 54 で動かなくなった場合は、筆者の方でも調査したいと思います。

AMO に登録されているアドオンの 自動互換性テストと対応バージョンの更新 は数週間以内に行われますので、AMO に Firefox 53 対応のアドオンを登録している方は後日メールをチェックしてみてください。

Firefox 53 アドオン互換性情報

Mozilla では Firefox 57 へ向けたロードマップ を投稿しています。もしまだ読んでいなければ目を通してみてください。Firefox 53 は重要なマイルストーンで、AMO で旧式アドオンの「新規」受付が停止され、マルチプロセス Firefox が初期設定で有効化され、WebExtensions API を経由しないアドオンからのバイナリアクセスが制限されます。

Firefox 53 は 4 月 18 日 [日本時間同日深夜] リリース となります。Firefox 53 の変更点でアドオンの互換性に影響を及ぼす可能性のあるものを以下にまとめました。Firefox 53 for Developers により詳しい情報が載っていますので、こちらも併せてご覧ください。

一般

パスワードマネージャー

以下 3 つの変更は関連しており、アドオンが findSlotByName("") を呼び出してマスターパスワードが設定されているかどうかを確認できなくなったことが主な影響として挙げられます。該当するコードの変更方法は こちら の例を見てください。

XPCOM とモジュール

WebExtensions

この一覧に載っていない変更点や間違いを見つけたらコメント欄でお知らせください。もしあなたのアドオンが Firefox 53 で動かなくなった場合は、筆者の方でも調査したいと思います。

AMO に登録されているアドオンの 自動互換性テストと対応バージョンの更新 は数週間以内に行われますので、AMO に Firefox 52 対応のアドオンを登録している方は後日メールをチェックしてみてください。

JavaScript ゲームにおける操作方法

[この記事は、Control mechanisms in JavaScript games の翻訳です。]

ラップトップやデスクトップをはじめ、スマートフォンやタブレット、TV や冷蔵庫でさえも、共通してブラウザを持つようになりました。ということは、それらの端末上で HTML5 ゲームをプレイできるようになったという風にも思えますが、実際にプレイするためには、ゲーム画面を描画するのと同時に、何らかの方法でゲームを操作できなければなりません。キーボードやマウスはもちろん、タッチ操作、ゲームパッド、TV リモコン、さらにはバナナに至るまで、それぞれのプラットフォームごとに適した選択肢はたくさん存在します(MDN では、control mechanisms に関する一連の記事でそれらのインターフェースを取り上げています)。

captainrogers2-cover

今回は、実際のプロジェクトにおける例として、Phaser を用いて作成された Captain Rogers: Battle at Andromeda のデモを使ってぞれぞれの操作方法の実装方法について紹介します。プラットフォームの違いによってゲームの操作性がどう変わっていくかをご確認ください。また、異なるプラットフォームに対応する際に別々にビルドする必要がないということもお見せします。ウェブのマルチプラットフォームという特性によって、コーディングに多くの労力を費やすことなく複数のデバイスに対応できることがお分かりいただけると思います。

controls-purejsgame

また、GitHub には、小さいですが純粋な JavaScript によるデモがオープンソースとして公開されています。操作方法がどのように実装されているかを実際に確認できるので、ご自身のゲーム開発プロジェクトでもお使いいただけます。以下に、主な項目をハイライトでご紹介しますので、このままお読みいただいても良いですし、今すぐコーディングを開始しても良いでしょう。

モバイル タッチ

HTML5 ゲームではモバイルファースト開発が人気ですので、まずはモバイル タッチへの対応から見ていきましょう。

document.addEventListener("touchstart", touchHandler);
document.addEventListener("touchmove", touchHandler);
function touchHandler(e) {
    if(e.touches) {
        playerX = e.touches[0].pageX - canvas.offsetLeft - playerWidth / 2;
        playerY = e.touches[0].pageY - canvas.offsetTop - playerHeight / 2;
    }
}

たった数行の JavaScript コードですが、これがゲーム内でタッチ操作を実現するために必要な最低限のコードです。これだけでモバイル端末上で機能します。最初の 2 行は、タッチ操作に対するイベントリスナーの設定です。それぞれ、画面をタッチしたとき、および、指で画面をなぞったときに対応します。関数内では、タッチ操作が行われたことを確認し、プレイヤーの座標を設定しています。これにより、ゲームの Canvas 上でプレイヤーの機体が正しい位置に描画されます。

上記はベースとなるコードですので、ここからマルチタッチやジェスチャーなど様々な発展形を実装することができます(むしろ、実装した方がいいでしょう)。ゲームの種類や、何をどのように操作するかということを考慮して、実装する操作方法を決めましょう。また、移動用の矢印や発射ボタンなど、特定のアクションを起こすためのボタンを画面上に設置することもできます。詳しくは、Mobile touch controls をご覧ください。

デスクトップ マウスとキーボード

移動用の矢印について触れましたが、モバイル端末向けに画面上に矢印を表示するのはもちろん、デスクトップ向けにそれらを実装することも可能です。ゲーム内のキャラクターを動かす方法としては、カーソルキーや WASD キーがよく使われます。例えば、以下のコードではカーソルキーを使用しています。

document.addEventListener("keydown", keyDownHandler);
function keyDownHandler(e) {
    if(e.keyCode == 39) {
        rightPressed = true;
    }
    else if(e.keyCode == 37) {
        leftPressed = true;
    }
    if(e.keyCode == 40) {
        downPressed = true;
    }
    else if(e.keyCode == 38) {
        upPressed = true;
    }
}

押されたキーを定常的に検出しその情報を保存するということですので、これは描画ループとして以下のように処理することが可能です。

function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    if(rightPressed) {
        playerX += 5;
    }
    else if(leftPressed) {
        playerX -= 5;
    }
    if(downPressed) {
        playerY += 5;
    }
    else if(upPressed) {
        playerY -= 5;
    }
    ctx.drawImage(img, playerX, playerY);
    requestAnimationFrame(draw);
}

プレイヤーの位置 x および y を表す変数が調整され、機体画像が新たな位置に表示されます。

controls-howtoplay

一方、デスクトップにおけるマウスは、コーディングにおいてモバイルのタッチと非常に似ています。タッチやクリックが起こった場所に関する情報を取得し、プレイヤーの位置を更新するだけです。

document.addEventListener("mousemove", mouseMoveHandler);
function mouseMoveHandler(e) {
    playerX = e.pageX - canvas.offsetLeft - playerWidth / 2;
    playerY = e.pageY - canvas.offsetTop - playerHeight / 2;
}

マウスポインターの位置が変化するたびに mousemove イベントが検出されるので、プレイヤーの位置がマウスポインターの中央の位置に来るように調整します。こうして、デスクトップのキーボードとマウスの両方で操作可能なゲームを実現することができます。さらに詳しく知りたい方は、Desktop mouse and keyboard controls をご覧ください。

ゲームパッド

個人的に大好きな操作方法です。プレゼンテーションを行う際は、HTML5 ベースの自分のスライドを Gamepad APIを使って操作しているくらいです。ゲームパッドについては、すでに数回お話したこともありますし、ゲームもいくつか実装したこともあります。詳しくは、Gamepad API Content Kit に全て記載しています。 とにかく、コンピューター上でコンソール気分を体験できることは本当に素晴らしいと思いますし、それがウェブ技術によって実現されているということも素晴らしいと思います!ゲームパッドを使用すれば、Captain Rogers のプレイ体験がさらに向上しますし、単純に良い気分になります。

controls-gamepadinfo

Gamepad API への対応はタッチやキーボードよりもやや複雑になりますが、それでも非常に簡単です。

window.addEventListener("gamepadconnected", gamepadHandler);
function gamepadHandler(e) {
    controller = e.gamepad;
}
function gamepadUpdateHandler() {
    buttonsPressed = [];
    if(controller.buttons) {
        for(var b=0; b<controller.buttons.length; b++) {
            if(controller.buttons[i].pressed) {
                buttonsPressed.push(b);
            }
        }
    }
}
function gamepadButtonPressedHandler(button) {
    var press = false;
    for(var i=0; i<buttonsPressed.length; i++) {
        if(buttonsPressed[i] == button) {
            press = true;
        }
    }
    return press;
}

ゲームパッドが接続されるとイベントが発生し、ゲームパッドに関するデータの参照が変数に保存されます。以降は、その変数を使用してゲームパッドに関するデータにアクセスします。更新が起こると、押されたボタンの配列が新たに生成されるため、常に最新の状態が保持されます。また、あるボタンが押されたかどうかを判定するために配列をループ処理する関数もあります。これらはキーボードチェックと同様に、描画ループの中で使用できます。

function draw() {
    // ...
    gamepadUpdateHandler();
    if(gamepadButtonPressedHandler(0)) {
        playerY -= 5;
    }
    else if(gamepadButtonPressedHandler(1)) {
        playerY += 5;
    }
    if(gamepadButtonPressedHandler(2)) {
        playerX -= 5;
    }
    else if(gamepadButtonPressedHandler(3)) {
        playerX += 5;
    }
    if(gamepadButtonPressedHandler(11)) {
        alert('BOOM!');
    }
    // ...
}

こうすることで、プレイヤーの機体を DPad ボタン(十字キー)で操作したり、A ボタンで爆弾を爆発させることができるようになります。このほか、スティック操作を検知することもできますし、独自の小さいライブラリを作ってゲームパッドからの入力を処理することもできます。詳しくは、Desktop gamepad controls をご覧ください。

特殊な操作方法

さらにもっと進んで、リビングにある大型 TV のリモコンを使ったり、ラップトップの前で手を振ったり、食材とPCを線で繋いでその食材を押したりすることで、ゲームをプレイすることも可能です。

controls-tvremote

例えば、Panasonic 製の TV リモコンはキーボードイベントを再利用しているので、対応が非常に簡単です。リモコンの方向矢印はキーボードのカーソルキーと全く同じコード(37383940)を使用しているので、すぐに対応できます。リモコン特有のボタンについては、こちらに一覧がありますので、詳細情報とともにご覧ください。

controls-leapmotion

また、リモコンのボタンを押す代わりに、Leap Motion 機器の機能を使用して自分の手の位置や他のパラメーターを検知することで、何にも触れることなくプレイヤーの機体を操作することもできます。あらかじめ定義されている loop 内で、手に関する情報を取得できるので、

Leap.loop({
    hand: function(hand) {
        horizontalDegree = Math.round(hand.roll() * toDegrees);
        verticalDegree = Math.round(hand.pitch() * toDegrees);
        grabStrength = hand.grabStrength;
    }
});

それを使用してプレイヤーの位置を更新します。

function draw() {
    // ...
    if(horizontalDegree > degreeThreshold) {
        playerX -= 5;
    }
    else if(horizontalDegree < -degreeThreshold) {
        playerX += 5;
    }
    if(verticalDegree > degreeThreshold) {
        playerY += 5;
    }
    else if(verticalDegree < -degreeThreshold) {
        playerY -= 5;
    }
    if(grabStrength == 1) {
        alert('BOOM!');
    }
    // ...
}

その他にも、Unconventional controlsでは、 ドップラー効果や Proximity API、MaKey MaKeyなど興味深い操作方法の実装方法を紹介しています。

まとめ

最近は、HTML5 ゲームをプレイするのに使える機器がますます増えています。ご自身の腕時計も使えるかもしれませんし、はたまた音声認識によるウェブゲームも良いかもしれません。まさに、可能性は無限です。覚えておいて頂きたいのは、多くの操作方法に対応しているほど、ゲームにとっては良いことだということです。なぜなら、幅広い種類の機器を用いて、どんなプラットフォームでもプレイ可能になるからです。ぜひ、ブラウザがもたらす可能性を存分に活用しましょう。

kvmでfirefox-build-env(Mozilla build用VM)を使用する

これは https://kusanagi.lv7777.org/2017/01/05/kvm%E3%81%A7firefox-build-envmozilla-build%E7%94%A8vm%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B/ のクロスポストです。

 

以下のurlはmdnのfirefox-build-envについての記事。現在、筆者がtranslationしている。

https://developer.mozilla.org/ja/docs/Mozilla/Developer_Guide/Using_the_VM

が、上記の記事にはkvmによるMozilla buildの方法が書いていない。

といっても難しいことはなく、普通のova(vmware拡張子)をkvmにインポートするようにすればできる。
<ol>
<li>ovaのダウンロード</li>
<li>ovaを解答</li>
<li>vmのインポート</li>
<li>vmの起動とビルド</li>
<li>ビルドしたfirefoxの起動</li>
</ol>
まずvmのダウンロードだが上記記事(MDN)の中からダウンロードできる。黄緑のボタンで大きく書かれているためUXがいい。

このvmがかなり重い。通常の環境だと2時間ぐらいかかるかもしれない。なにせmozilla-centralとubuntuが入っているので。

次のovaの解答というステップだが、`tar  -vxf ダウンロードしてきたova`で解凍できる。

ovaはvmware専用形式(アプライアンス)だがそれの中身はvmをvmware用のメタ情報と一緒に圧縮したもの。

さて、解凍が終わればvmdkという拡張子が出てくるはず。こいつをqemu-convertでqcow2に変換する。

変換し終わったらvirt-managerを使って新規追加(星とディスプレイのアイコン)からインポートを選んで仮想マシンとして認識させる。cpu設定などはお好みで。

この辺は一般的なkvmのノウハウだが、intel-vtdを有効にしておかないとエラーが出るはず。(大抵の環境では有効になってると思うが)

また、ネットワーク関係でエラーが出た場合edit > connection details > visual networksタブ の下のスタートボタンを押せば外部(ネットワーク)にvmが繋がった状態になるはず。

次にvmの起動とビルドだが、起動させたら自動ログインが有効なため、すでにログインしてる状態になってるはず。

sublimetext2を起動させればmozilla-centralのソースを編集できる状態になっている。つまりもうfirefoxのソースをいじったりbuildすることができる。

sublimetext2の上のtoolsからbuildを選べばすぐにbuildを開始する。

“`
ビルドの処理が開始するので、お茶や美味しい食事でもして休憩しましょう。
“`

自分の場合は30分かからなかった気がする。VMがビルド用に最適化処理をかけてくれている。もちろんデバッグ用ビルドをするときも簡単に変更できる。

ビルド終わったら起動させる。tools > runを押せばfirefoxが起動できるはず。

 

割と楽にできるのでfirefox-build-envを使うのがおすすめです

A-Blast: 宇宙からの可愛い侵略者から世界を救え!

[この記事は “A-Blast: Save the World from the Cutest Creatures in the Universe!” の抄訳です]

準備できたら VR コントローラーを握って、https://aframe.io/a-blast へ行け! ブラウザーの設定確認も忘れるな。Nightly 版 Firefox なら大丈夫だ。Chromium を使っているなら、chrome://flags/#enable-webvrchrome://flags/#enable-gamepad-extensions のフラグを忘れずに on にしておけ。

A-Blast のプレー画面

次々にやってくる敵を撃つシューテイングゲームは、VR ではポピュラーなジャンルです。実装も簡単です。プレーヤーが動き回る必要がないため、 位置に関する機能を実装する必要がありませんし、視点が固定されているためステージを単純にできるためです。 また射撃と弾との衝突判定のみを考えれば良いため、敵キャラとのインタラクションの実装も簡単です。 このようなシューティングゲームは単純であるだけに、プレイして楽しく、 Raw Data のように、時にはプレーヤーキャラクターになりきってしまうことすらあります。

A-Blast
はスムースな操作性とアセットのクオリティに着目し、A-Frame とブラウザーの性能を示す例として作成されました。 また A-Frame や WebVR が搭載された Firefox といった、我々の作ったツールを自分たちで使用して評価するためでもあります。

テストをする中でパフォーマンス上の問題がいくつも見つかりました。これに対処するため、初期実装のうちのいくつかを最適化し、 pool コンポーネントのような機能を A-Frame に追加しました。 これらに関する詳細は別の記事として、後日公開します。

このゲームの遊び方はシンプルです:武器をとり、飛び回るキャラクターを狙って、トリガーを引きます。 敵弾をかわすこともできます。ライフは 5 です。 敵を倒せば倒すほど、スコアが入ります。ローカルではありますが、ハイスコアランキングもあります。

イベントでのデモでの使用を考慮して、多くの人に試してもらえるように 5 分以内でプレーできるゲームを目指しました。 短すぎるかもしれません。完全版では、より凝ったステージを用意したいと思っています。 しかしこれは技術デモなのです。何時間もプレーできるコンテンツを作成したわけではありません。

A-Blast で使用するブラスター

HTC VIVE での使用を念頭に作成しましたが、キーボードとマウスでもプレーできます。 またスマートフォンを使っても遊べます。その時はスクリーンをタップして敵を撃ちます。

このゲームは JavaScript の VR フレームワークである A-Frame を利用して、 2 人のプログラマーと 1 人のアーティストが 2 ヶ月で実装しました。 2016 年 12 月にハワイであった Mozilla All-Hands で披露され、多くの Mozillian にプレーされました。

All Hands での試遊風景

A-Blast は A-Frame の tour de force、 つまり A-Frame が複雑なアプリケーションでの利用に耐える信頼性と負荷への耐性のテストを兼ねています。 その結果を利用して、我々は A-Frame を改善してゆきます(なお A-Blast のソースコードは、A-Painter のそれよりもわずかに大きいものとなっています)。

グローバルのハイスコアランキングや、動作する可能なコントローラーやデバイスの追加といった改善のためのアイディアをお持ちであれば、 お気軽に pull request を送ってください。A-Blast のソースコードは GitHub で公開されています

最後に、サウンドトラックを作成してくれた José Manuel Pérez Paredes (JosSs) に大きな感謝の言葉を贈ります。 彼の作成した音楽のおかげで、ゲームの体験がぐっと良いものになりました。

Adobe Flash利用を削減するFirefox

この投稿は米国 Mozilla Tech Blog の記事 “Reducing Adobe Flash Usage in Firefox” の抄訳です。

ブラウザプラグイン、特にFlashは、ビデオ再生やインタラクティブなコンテンツを含む、いくつかの素晴らしい機能をウェブの世界で使えるようにしてきました。しかし、プラグインはしばしば安定性、パフォーマンスやセキュリティの課題をブラウザに引き起こして来ました。これはユーザが受け入れなければならないトレードオフではありません。

Mozillaおよびウェブ業界は、日々のブラウジングにFlashの必要性が低くなるように段階を踏んできました。2016年8月、Firefoxはユーザ体験に必須ではない、いくつかのFlashコンテンツをブロックしましたが、レガシーのFlashコンテンツはサポートを継続しております。これらの変更および将来の変更により、Firefoxユーザにとってはセキュリティの拡張、バッテリー寿命延長、ページロードの高速化や、より良いブラウザー反応性が実現する予定です。

ここ何年かに亘り、Firefoxはこれまでプラグインでしか提供されていなかった機能をWebAPIで代替する実装を行ってきました。これはビデオ・音声再生やストリーミング機能、クリップボード統合、高速2Dおよび3Dグラフィックス、WebSocketネットワーキングやマイク・カメラアクセスなどです。ウェブサイトがFlashから他のウェブ技術に移行するに従って、プラグインによるFirefoxのクラッシュレートは劇的に低下しました。

Firefoxはユーザに見えない特殊なFlashコンテンツをブロックすることにより、この傾向を継続していきます。これによりFlashのクラッシュやハングは最大10%になる見込みです。ウェブサイトの互換性問題を最小化するため、これらの変化はHTMLに置き換え可能な少なく厳選されたFlashコンテンツのリストに当初は限定されていました。私たちは時間をかけてこのリストを追加していく予定です。

2016年末、私たちは広告測定でよく使われるコンテンツの可視性(viewability)をチェックするために使われるFlashをこのリストに追加しました。これはFirefoxのパフォーマンスとデバイスバッテリー寿命を向上させます。この変更と同時にFirefoxはHTMLで同等の機能となるIntersection Observer API (Firefox bug 1243846)を実装いたします。可視性測定に現在Flashを利用されているコンテンツ製作者のみなさんには、このAPIが有効になり次第、この新しいAPIを適用いただくことをお勧めいたします。

2017年には、Firefoxはすべてのコンテンツについて、Flashプラグイン持つウェブサイトを有効にする前に、クリックによる有効化承認作業を必要とする予定です。現在ビデオやゲームでFlashやSilverlightをご利用のウェブサイトはできるだけ早期にHTML技術への適用を計画すべきです。Firefoxはビデオプラグインの代替として、Adobe PrimetimeとGoogle Widevineの暗号ビデオ再生をサポートしています。

私たちは引き続きAdobe社と密接に連携し、最適に実現可能なFlash体験をユーザのみなさんに提供していきます。この開発パートナーシップにより、パフォーマンスと安定性を改善するWindowsでの高DPIの改善や、拡張サンドボックス、高速化Flashレンダリングパイプラインを実装していきます。

これらの変更により、ユーザのみなさんが使いやすいウェブ体験を損なうことなく、ブラウジングを安全に高速にするための私たちの進めるさまざまな活動の一部です。2015年に発表しましたとおり、2017年3月にFirefoxはFlashを除くすべてのNPAPIプラグインのサポートを停止する計画です。次のメジャーバージョンであるFirefox ESR (法人向け延長サポート版)リリースは同じ2017年3月に予定されていますが、移行に時間が必要なユーザのみなさまのために、ESRではSilverlightやJavaなどのプラグインのサポートを2018年初頭まで継続する予定です。

私たちは多くのその他の機能や改善を試み、Firefoxを発見や協調のためのより素晴らしいプラットフォームにしてきます。フィードバックや機能リクエストをお待ちしています。

2017年のアドオン

この投稿は米国 Mozilla Tech Blog の記事 “Add-ons in 2017” の抄訳です。

1年以上前に私たちはアドオンはどこに向かうのか、そして将来はどんな風になるのか、について会話を開始しました。それは多忙でした。そして2017年にやりたいと考えているガイダンスをご提供し、そのアップデートをご提供したいと思いました。

2015年を通して、私たちはコミュニティとしてFirefoxとaddons.mozilla.org(AMO)のWebExtensionsサポートを追加する基礎的な作業を行うことに注力してきました。そして開発中の標準をメンテナンスする間にレビューすべきリスト化されたアドオンに関わる時間を削減し、アドオンのe10sへの準備を済ませてきました。私たちは、Signing APIやアドオンマネージャの改良版Discovery Paneのようなイニシアティブを通してアドオンの投稿、配信と発見を簡単にするプロセスや製品を数多く変革してきました。そうして、私たちは直接のコンタクトやメーリングリスト、Eメールキャンペーン、wikiやアドオンブログを通して開発者コミュニティに変革をお知らせすることに注力してきました。

私たちが申し上げてきましたとおり、WebExtensionsはFirefoxのアドオンの将来であり、2017年も集中して取り組むエリアです。WebExtensionsはプラットフォームと切り離されており、我々がFirefoxに対してこれから、そしてそれ以降の年に予定する変革はプラットフォームには影響しません。(WebExtensionsの)開発はより簡単で、起動や実行するためにFirefoxの内部処理について学ぶ必要はありません。あなたのアドオンを最小の変更で他のブラウザーからの移植や他のブラウザーへの移植を行うことも簡単です。なぜなら、これらのAPIは – 当然ですが – Opera、ChromeやEdgeのような製品と互換性があるためです。

2017年末までに、Firefox 57のリリースに伴い、私たちはWebExtensionsだけのサポートに切り替え、デスクトップ上の他の種類の拡張機能をロードしないようにします。新しい拡張機能が2017年末以降も動作できるように、Firefox 53でAMOはWebExtensionsではない新しい拡張機能の署名受付を終了いたします。本年を通して私たちはAPIセットを拡張し、Firefoxに機能を追加し、それはまだ他のブラウザでは搭載していませんが、ユーザの前にもっとたくさんのWebExtensionsをご提供します。

移行する部品はたくさんあります。Mozilla WikiのWebExtensionsセクションで、時間軸やロードマップを含むもっと詳細な情報を追跡していきます。もしあなたがアドオンコミュニティやWebExtensionsに参加するご興味がありましたら、いくつかの方法があります。私たちは2017年を楽しみにしており、更新情報や追加情報をこちらのアドオンブログでお知らせしてまいります。

Add-onやWebExtensionsについてのより詳細な情報は、こちらをご覧ください。

注意:Firefox 53の時期にはさらなる具体的な更新を行います