この記事は Leon Nicholls による Google Developers - Medium の記事 "Optimize your web apps for Interactive Canvas " を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。
Interactive Canvas を使って Google アシスタント用の Action を作成すると、最高の会話型インターフェースと HTML の豊かな視覚表現を組み合わせることができます。
私たちは、ここしばらくの間、Interactive Canvas を使ってさまざまなアイデアを実験し、Action を作成するパートナーと協力しながら、どうすればうまくいくのかという知見を得ることができました。この投稿では、をお伝えすることで、Interactive Canvas を使った Action を成功させるお手伝いをしたいと思います。
注: 現時点で、Google は Canvas Action をゲームに限って承認しています。
設計
Interactive Canvas を使う Action は、会話型 Action です。ゲームの設計は、Interactive Canvas による視覚表現を使ってどのように音声ユーザー インターフェースを補完できるかを考えるところから始める必要があります。Action の会話を設計する着手点として、設計ガイドライン をご確認ください。
Interactive Canvas を使う Action では、ゲームの主なステージを網羅したストーリーボードを作ることをお勧めします。これには、読み込み画面、ようこそ画面とチュートリアル画面、ゲームのメイン画面、終了画面などを含めます。
ユーザーがゲーム中に画面に触れることもあるので、タッチイベントに対してフィードバックを行う方法も考えます。ユーザーの入力に対するコールバックの応答を待つのではなく、ウェブアプリ内ですぐに確認することをお勧めします。
さらに、Interactive Canvas ウェブアプリにはさまざまな制限 があることも考慮しなければなりません。たとえば、ローカル ストレージは使えず、メモリは 200 MB の制限を超えてはいけません。
Action で使う視覚要素、GUI コンポーネント、アニメーションが決まったら、Interactive Canvas をサポートする端末にとって技術的にベストな実装を選択します。次のセクションでは、すべてのサポート対象の Interactive Canvas で問題なく動作するさまざまな推奨 HTML 技術を紹介します。ここで紹介する内容は、下に示す今回試作したデモ用 Action のようなものを作る際に役立ちます。
Interactive Canvas Action
ローディング ページ
ウェブページが完全に読み込まれてアニメーション本体が表示されるまでの間は、ローディング ページを表示することをお勧めします。これにより、アニメーションのパフォーマンスに大きな違いが出るだけでなく、ページ アセットの読み込み中に起きがちなレイアウトの問題を避けることもできます。
ローディング ページが表示されている間に、JavaScript のロジックを使って非同期的に任意のアセット(画像ファイルやテクスチャなど)を読み込むことができます。
一番簡単にローディング ページをデザインするには、単色の塗りつぶし背景上にアニメーションする読み込み中のインジケーターを表示させます。JavaScript によるアニメーションは避けた方がよいので、CSS かアニメーション GIF を使いましょう。ローディング ページの参考として、こちらのクールな CSS ローダー をご覧ください。
レスポンシブ デザイン
現在のところ、Interactive Canvas は Google アシスタント スマート ディスプレイと Android モバイル端末でサポートされています。これらの端末は画面解像度が異なり、ランドスケープ モード(横向き)とポートレート モード(縦向き)の両方をサポートしている可能性もあります。
そのため、それぞれの種類のディスプレイでレイアウトとテキストが適切なサイズになるように、レスポンシブ デザインのウェブアプリにするとよいでしょう。簡単にこれを行うには、Sass ブレークポイントを使います。
@mixin for-small-display-landscape {
@media screen and (min-width: 1024px) and (min-height: 600px) {
@content ;
}
}
@mixin for-medium-display-landscape {
@media screen and (min-width: 1280px) and (min-height: 700px) {
@content ;
}
}
また、Action の画面上部にはヘッダーがあり、Action の名前とアイコンが表示されます。また、ユーザーはヘッダーから Action を閉じることができます。このヘッダーの後ろに重要なコンテンツやテキストを配置してはいけません。
Interactive Canvas では、ヘッダーの高さ(ピクセル単位)を非同期的に決める getHeaderHeightPx() API が提供されています。この値を使うと、ウェブアプリが読み込まれた際にレイアウトを動的に調整することができます。
window.onload = () => {
const callbacks = {
onUpdate(data) {
// update game state based on intent response data
},
}
interactiveCanvas.ready(callbacks)
interactiveCanvas.getHeaderHeightPx().then((height) => {
// initialize web app layout with header height value
})
}
アニメーション
HTML では、DOM の操作、CSS アニメーション、HTML キャンバス、WebGL など、さまざまな方法でアニメーションを行うことができます。
私たちの経験上、JavaScript でほぼリアルタイムに計算を行うアニメーションには多くの最適化が必要になります。しかし、スムーズで FPS の高いアニメーションを行う方法は他にもあります。
CSS
JavaScript で DOM を操作する代わりに、CSS アニメーション を使うことを検討します。ブラウザは GPU を使ってこの種のアニメーションを高速化できるだけでなく、メイン UI スレッドとは別にアニメーションを管理することもできます。
低レベルの CSS プロパティを使いたくない場合は、animate.css などの CSS ライブラリを利用できます。こういったライブラリには、さまざまな高品質アニメーションに利用できる CSS クラスが含まれています。このようなアニメーションを使う場合、まず、要素と必要な CSS アニメーション プロパティを宣言します。
.title {
animation-duration: 3s;
animation-delay: 2s;
animation-iteration-count: infinite;
}
その後、アニメーション クラスを HTML 要素とともに静的に宣言するか、JavaScript を使ってアニメーション クラスを動的に呼び出します。
const element = document.querySelector('.title');
element.classList.add('animated', 'bounceInUp');
element.style.visibility = 'visible';
element.addEventListener('animationend', () => {
element.style.visibility = 'hidden';
});
アニメーションの同時実行は避け、前のアニメーションの終了イベントで次のアニメーションを呼び出して連続したアニメーションを行うことをお勧めします。
Web Animations API の利用も検討できます。これを使うと、CSS による最適なパフォーマンスと JavaScript の動的機能を両立させることができます。
SVG
SVG を使うと、JavaScript や CSS を通して動的に操作できる 2 次元ベクター グラフィックを作成できます。
SVG は、時間によって要素の属性をアニメーションさせる <animate> タグをサポートしています。基本的なアニメーションなら、Canvas 端末で非常にスムーズに動作します。
しかし、CSS を使う方が、SVG のグラフィック要素をスムーズにアニメーションさせることができます。SVG の <path> にはクラスを割り当てることができ、そのクラスと CSS アニメーション を使ってアニメーションさせることができます。この方式のアニメーションも、端末でスムーズにレンダリングされます。
WebGL
WebGL は、端末の GPU を使ってウェブページのアニメーションのパフォーマンスを大幅に改善します。WebGL を使った経験がない方は、PixiJS などのさまざまなライブラリを使うことができます。こういったライブラリは、使いやすい高レベルの JavaScript API を提供しており、WebGL でレンダリングされるアニメーションをデザインできます。
Adobe Animate などのツールに親しんでいるアニメーターの方なら、PixiAnimate 拡張機能を使ってコンテンツをエクスポートし、PixiJS ラインタイム ライブラリで再生することができます。Canvas ウェブアプリでは、Pixi Animate プラグイン を使ってエクスポートしたアニメーションを読み込むことができます。読み込んだアニメーションは、JavaScript のコードで制御できます。図形の色を変えるなど、動的に外見を変えることもできます。
Adobe Animate の「シェイプ トゥイーン」の使用は避けることをお勧めします。この機能はたくさんのテクスチャを生成するので、Canvas ウェブアプリのメモリ制限を超過する可能性があります。代わりに、「クラシック トゥイーン」を使うようにしてください。
WebAssembly
他の言語で書かれた既存のコードがあるデベロッパーの方には、WebAssembly (WASM)はおもしろい選択肢です。たとえば、C や C++ で書かれた既存のゲームがある場合、Emscripten などのツールチェーンを使って WebAssembly にコンパイルできます。Canvas ウェブアプリは、WASM コードを読み込んでインスタンス化することが可能です。すると、JavaScript のロジックから WASM の機能を呼び出せるようになります。
WebAssembly は、デベロッパーに低レベルの制御と高レベルのパフォーマンスを提供します。試しに、ガベージ コレクションを回避するように Rust to WASM をコンパイルしてみたところ、60 FPS の非常にスムーズなアニメーションを実現できました。
WASM を使うと、テキストの高速レンダリングと静的要素の表示に HTML を利用しつつ WASM アニメーションをオーバーレイさせ、両者の長所を共存させることができます。
動画
ゲームで動画アセットを使うと、高度な視覚表現を効果的に表示し、カットシーン のような魅力的な場面を作ることができます。
「その場で」生成するとコストが高すぎる視覚表現を使いたい場合、動画としてレンダリングしたアニメーションをウェブアプリの HTML メディア要素で再生することを検討します。これにより、表現力豊かな背景をとても効果的に実現できます。動的 DOM 要素やアニメーションと組み合わせることもできます。
Canvas では、アクティブなメディア要素は 1 つしか許可されず、video 要素を CSS でスタイル設定することはできません。
長期間継続する効果の場合、メディア要素の “loop” 属性を指定して動画をループさせることができます。ただし、自動ループを行うと、ループの終わりと次のループの始まりの間で遅延が生じる可能性があります。
この遷移をシームレスに行うには、Media Source Extensions (MSE)を使う必要があります。これによってメディア要素が拡張され、JavaScript で再生用のメディア ストリームを生成できるようになります。MSE を使うと、HTML5 の video タグのバッファに直接メディアのセグメントを渡すことができます。動画が永久にループし続け、ループ間で遅延が発生しないことを保証するには、JavaScript のコードを使って動画データのダウンロードとバッファリングを行う必要があります。
状態管理
ウェブアプリは、Interactive Canvas の sendTextQuery() API を使って Dialogflow エージェントのインテントを呼び出し、その状態をフルフィルメント ロジックと同期させます。この呼び出しはユーザーの音声応答と同じライフサイクルに従います。バックエンドに永続化する際の遅延を追加することもできます。
バックエンドに対して状態の更新を永続化するタイミングが重要になる場合、ウェブアプリがフロントエンドの JavaScript ロジックから直接 Cloud Firestore などの永続化 API を呼び出すことができます。
テスト
Chrome DevTools を使ってウェブアプリのパフォーマンスとメモリ使用量をプロファイリングすることをお勧めします。PC のシミュレータ で Action をテストする場合は、ウェブアプリを埋め込むために使われている iframe を探し、DevTools を使ってウェブアプリの DOM を調査します。
メモリや CPU の使用状況のプロファイリングには、DevTools が便利です。DevTools を使うと、コードのボトルネックを見つけてアニメーションの FPS を改善できます。
ゲームのリアルタイム FPS をトラックしてオーバーレイ表示させるなら、stats.js もお勧めです。
パフォーマンスに満足できるようになったら、Interactive Canvas をサポートするすべての端末で Action をテストします。これが必要なのは、端末によって画面の比率やパフォーマンスが異なるためです。
次のステップ
Interactive Canvas で開発するゲームの種類によっては、さまざまな方法でスムーズなアニメーションや効果を実現できます。多少のテストとプロファイリングは必要になりますが、迫力のある楽しい Interactive Canvas ゲームを実現できるはずです。
Interactive Canvas を使ったゲームはまだ生まれたばかりなので、ぜひこの機会に実際に試してみて、HTML の力でできることを体験してください。
意見や質問を共有したい方は、 /r/GoogleAssistantDev から Reddit に参加してください。私たちのチームの詳しい最新情報を受け取るには、Twitter で @ActionsOnGoogle をフォローします。#AoGDevs を付けてツイートし、皆さんが作っているものについて教えてください。
Reviewed by Chiko Shimizu - Developer Relations Team