FlashゲームをHTML5に変換するときに知っておくべきことは何ですか?
公開: 2022-03-10HTML5の使用が増えるにつれ、多くの企業が最も人気のあるタイトルをやり直して、古いFlashを取り除き、製品を最新の業界標準に適合させ始めています。 この変化は、ギャンブル/カジノ&エンターテインメント業界で特に顕著であり、数年前から起こっているため、適切なタイトルの選択はすでに変換されています。
残念ながら、インターネットを閲覧していると、一見急いでいる仕事の例に出くわすことがよくあります。その結果、最終製品の品質が高くなります。 そのため、ゲーム開発者は、FlashからHTML5への変換の主題に精通し、仕事に取り掛かる前に避けるべき間違いを学ぶために時間を割くのが良い考えです。
Flashの代わりにJavaScriptを選択する理由の中には、明らかな技術的な問題は別として、ゲームデザインをSWFからJavaScriptに変更すると、ユーザーエクスペリエンスが向上し、モダンな外観が得られるという事実もあります。 しかし、それを行う方法は? この時代遅れのテクノロジーを取り除くために専用のJavaScriptゲームコンバーターが必要ですか? さて、FlashからHTML5への変換は簡単なことかもしれません—これがそれを処理する方法です。
推奨読書: HTML5ゲームデザインの原則
HTML5ゲーム体験を改善する方法
ゲームを別のプラットフォームに変換することは、ゲームを改善し、問題を修正し、視聴者を増やす絶好の機会です。 以下は、簡単に実行でき、検討する価値のあるいくつかのことです。
モバイルデバイスのサポート
FlashからJavaScriptに変換すると、より多くのユーザー(モバイルデバイスのユーザー)にリーチできます。 タッチスクリーンコントロールのサポートは、通常、ゲームにも実装する必要があります。 幸い、AndroidデバイスとiOSデバイスの両方がWebGLもサポートするようになったため、通常、30または60FPSレンダリングを簡単に実現できます。 多くの場合、60 FPSは問題を引き起こしませんが、モバイルデバイスのパフォーマンスが向上するにつれて、時間の経過とともに改善されます。- パフォーマンスの向上
ActionScriptとJavaScriptの比較に関しては、後者の方が前者よりも高速です。 それ以外に、ゲームの変換は、ゲームコードで使用されているアルゴリズムを再検討する良い機会です。 JavaScriptゲーム開発を使用すると、それらを最適化するか、元の開発者が残した未使用のコードを完全に取り除くことができます。 - バグの修正とゲームプレイの改善
新しい開発者にゲームのソースコードを調べてもらうと、既知のバグを修正したり、新しくて非常にまれなバグを発見したりするのに役立ちます。 これにより、プレイヤーがゲームをプレイする際のイライラが少なくなり、サイトでの滞在時間が長くなり、他のゲームを試すようになります。 - Web分析の追加
トラフィックの追跡に加えて、Web分析を使用して、プレーヤーがゲーム内でどのように動作し、ゲームプレイ中にどこでスタックするかについての知識を収集することもできます。 - ローカリゼーションの追加
これは視聴者を増やすことになり、ゲームをプレイする他の国の子供たちにとって重要です。 または、ゲームが英語ではなく、その言語をサポートしたい場合はどうでしょうか。
ゲーム内UIでHTMLとCSSをスキップするとゲームのパフォーマンスが向上する理由
JavaScriptゲーム開発に関しては、ゲーム内のボタン、ウィジェット、およびその他のGUI要素にHTMLとCSSを活用したくなるかもしれません。 ここで注意することをお勧めします。 直感に反しますが、実際にはDOM要素を活用することは、複雑なゲームではパフォーマンスが低下し、モバイルではより重要になります。 すべてのプラットフォームで一定の60FPSを達成したい場合は、HTMLおよびCSSからの辞任が必要になる場合があります。
ヘルスバー、弾薬バー、スコアカウンターなどの非対話型GUI要素は、通常の画像( Phaser.Image
クラス)を使用し、トリミングに.crop
プロパティを使用し、単純なPhaser.Text
クラスを使用することで、Phaserに簡単に実装できます。テキストラベル。
ボタンやチェックボックスなどのインタラクティブな要素は、組み込みのPhaser.Button
クラスを使用して実装できます。 その他のより複雑な要素は、グループ、画像、ボタン、テキストラベルなど、さまざまな単純なタイプで構成できます。
注: Phaser.TextまたはPIXI.Textオブジェクトをインスタンス化するたびに、テキストをレンダリングするための新しいテクスチャが作成されます。 この追加のテクスチャは頂点のバッチ処理を壊すので、それらが多すぎないように注意してください。
カスタムフォントがロードされていることを確認する方法
カスタムベクターフォント(TTFやOTFなど)を使用してテキストをレンダリングする場合は、テキストをレンダリングする前に、フォントがブラウザによってすでにロードされていることを確認する必要があります。 Phaser v2はこの目的のためのソリューションを提供していませんが、別のライブラリを使用できます:Webフォントローダー。
フォントファイルがあり、ページにWeb Font Loaderが含まれていると仮定すると、フォントをロードする方法の簡単な例を以下に示します。
Webフォントローダーによってロードされる単純なCSSファイルを作成します(HTMLに含める必要はありません)。
@font-face { // This name you will use in JS font-family: 'Gunplay'; // URL to the font file, can be relative or absolute src: url('../fonts/gunplay.ttf') format('truetype'); font-weight: 400; }
次に、 WebFontConfig
という名前のグローバル変数を定義します。 通常、これと同じくらい単純なもので十分です。
var WebFontConfig = { 'classes': false, 'timeout': 0, 'active': function() { // The font has successfully loaded... }, 'custom': { 'families': ['Gunplay'], // URL to the previously mentioned CSS 'urls': ['styles/fonts.css'] } };
最後に、上記の「アクティブな」コールバックにコードを配置することを忘れないでください。 以上です!
ユーザーがゲームを簡単に保存できるようにする方法
ローカルデータをActionScriptに永続的に保存するには、SharedObjectクラスを使用します。 JavaScriptでは、単純な置き換えはlocalStorage APIです。これにより、後で取得できるように文字列を保存し、ページの再読み込みを存続させることができます。
データの保存は非常に簡単です。
var progress = 15; localStorage.setItem('myGame.progress', progress);
上記の例では、数値であるprogress
変数が文字列に変換されることに注意してください。
ロードも簡単ですが、取得される値は文字列になるか、存在しない場合はnull
になることに注意してください。
var progress = parseInt(localStorage.getItem('myGame.progress')) || 0;
ここでは、戻り値が数値であることを確認しています。 存在しない場合は、 progress
変数に0が割り当てられます。
JSONなどのより複雑な構造を保存および取得することもできます。
var stats = {'goals': 13, 'wins': 7, 'losses': 3, 'draws': 1}; localStorage.setItem('myGame.stats', JSON.stringify(stats)); … var stats = JSON.parse(localStorage.getItem('myGame.stats')) || {};
localStorageオブジェクトが使用できない場合があります。 たとえば、 file://
プロトコルを使用する場合、またはページがプライベートウィンドウにロードされる場合です。 try and catchステートメントを使用して、コードが引き続き機能し、デフォルト値を使用するようにすることができます。これを以下の例に示します。
try { var progress = localStorage.getItem('myGame.progress'); } catch (exception) { // localStorage not available, use default values }
もう1つ覚えておくべきことは、保存されたデータはURLごとではなく、ドメインごとに保存されるということです。 したがって、多くのゲームが1つのドメインでホストされるリスクがある場合は、保存時にプレフィックス(名前空間)を使用することをお勧めします。 上記'myGame.'
はそのような接頭辞であり、通常はゲームの名前に置き換えます。
注:ゲームがiframeに埋め込まれている場合、localStorageはiOSで保持されません。 この場合、代わりに親iframeにデータを保存する必要があります。
デフォルトのフラグメントシェーダーの置き換えを活用する方法
PhaserとPixiJSがスプライトをレンダリングするとき、それらは単純な内部フラグメントシェーダーを使用します。 速度に合わせて調整されているため、多くの機能はありません。 ただし、目的に応じてそのシェーダーを置き換えることができます。 たとえば、これを利用して、オーバードローを検査したり、レンダリング用のより多くの機能をサポートしたりできます。
以下は、独自のデフォルトフラグメントシェーダーをPhaserv2に提供する方法の例です。
function preload() { this.load.shader('filename.frag', 'shaders/filename.frag'); } function create() { var renderer = this.renderer; var batch = renderer.spriteBatch; batch.defaultShader = new PIXI.AbstractFilter(this.cache.getShader('filename.frag')); batch.setContext(renderer.gl); }
注:デフォルトのシェーダーは、テクスチャにレンダリングするときだけでなく、すべてのスプライトに使用されることを覚えておくことが重要です。 また、ゲーム内のすべてのスプライトに複雑なシェーダーを使用すると、レンダリングパフォーマンスが大幅に低下することに注意してください。
デフォルトのシェーダーで色付け方法を変更する方法
カスタムのデフォルトシェーダーを使用して、PhaserおよびPixiJSのデフォルトの色付け方法を置き換えることができます。
PhaserとPixiJSの色付けは、テクスチャピクセルに特定の色を掛けることで機能します。 乗算は常に色を暗くしますが、これは明らかに問題ではありません。 フラッシュの色合いとはまったく異なります。 私たちのゲームの1つでは、Flashと同様の色合いを実装する必要があり、カスタムのデフォルトシェーダーを使用できると判断しました。 以下は、そのようなフラグメントシェーダーの例です。
// Specific tint variant, similar to the Flash tinting that adds // to the color and does not multiply. A negative of a color // must be supplied for this shader to work properly, ie set // sprite.tint to 0 to turn whole sprite to white. precision lowp float; varying vec2 vTextureCoord; varying vec4 vColor; uniform sampler2D uSampler; void main(void) { vec4 f = texture2D(uSampler, vTextureCoord); float a = clamp(vColor.a, 0.00001, 1.0); gl_FragColor.rgb = f.rgb * vColor.a + clamp(1.0 - vColor.rgb/a, 0.0, 1.0) * vColor.a * fa; gl_FragColor.a = fa * vColor.a; }
このシェーダーは、色合いにベースカラーを追加することでピクセルを明るくします。 これを機能させるには、必要な色のネガを指定する必要があります。 したがって、白を取得するには、次のように設定する必要があります。
sprite.tint = 0x000000; // This colors the sprite to white Sprite.tint = 0x00ffff; // This gives red
私たちのゲームの結果は次のようになります(ヒットしたときに戦車が白く点滅することに注意してください):
オーバードローを検査してフィルレートの問題を検出する方法
デフォルトのシェーダーを置き換えることも、デバッグに役立てることができます。 以下では、このようなシェーダーを使用してオーバードローを検出する方法について説明しました。
オーバードローは、画面上の多くまたはすべてのピクセルが複数回レンダリングされるときに発生します。 たとえば、多くのオブジェクトが同じ場所に配置され、次々にレンダリングされます。 GPUが1秒間にレンダリングできるピクセル数は、フィルレートとして表されます。 最新のデスクトップGPUは、通常の2Dの目的では過剰なフィルレートを持っていますが、モバイルGPUははるかに低速です。
PixiJSとPhaserのデフォルトのグローバルフラグメントシェーダーを次のシェーダーに置き換えることで、画面上の各ピクセルが何回書き込まれたかを確認する簡単な方法があります。
void main(void) { gl_FragColor.rgb += 1.0 / 7.0; }
このシェーダーは、処理中のピクセルを明るくします。 数値7.0は、ピクセルを白にするために必要な書き込み回数を示します。 この番号をお好みに合わせて調整できます。 つまり、画面上の明るいピクセルは数回書き込まれ、白いピクセルは少なくとも7回書き込まれました。
このシェーダーは、何らかの理由でまだレンダリングされている「非表示」オブジェクトと、除去する必要のある周囲に過度の透明領域があるスプライトの両方を見つけるのにも役立ちます(GPUはテクスチャ内の透明ピクセルを処理する必要があります)。
左側の画像はプレーヤーがゲームをどのように見ているかを示し、右側の画像は同じシーンにオーバードローシェーダーを適用した効果を示しています。
物理エンジンがあなたの友達である理由
物理エンジンは、物理ボディ(通常は剛体のダイナミクス)とそれらの衝突のシミュレーションを担当するミドルウェアです。 物理エンジンは2Dまたは3D空間をシミュレートしますが、両方をシミュレートすることはできません。 典型的な物理エンジンは以下を提供します:
- 速度、加速度、関節、モーターを設定することによるオブジェクトの動き。
- さまざまな形状タイプ間の衝突を検出します。
- 衝突応答、つまり2つのオブジェクトが衝突したときにどのように反応するかを計算します。
Merixstudioでは、Box2D物理エンジンの大ファンであり、数回使用しました。 この目的に適したPhaserプラグインがあります。 Box2Dは、UnityゲームエンジンとGameMaker Studio2でも使用されます。
物理エンジンは開発をスピードアップしますが、実行時のパフォーマンスの低下という代償を払わなければなりません。 衝突の検出と応答の計算は、CPUを集中的に使用するタスクです。 携帯電話のシーンでは、数十の動的オブジェクトに制限されたり、パフォーマンスが低下したり、60FPSをはるかに下回るフレームレートが低下したりする場合があります。
画像の左側はゲームのシーンで、右側は同じシーンを示しており、Phaser物理デバッグオーバーレイが上に表示されています。
.flaファイルからサウンドをエクスポートする方法
.flaファイル内にFlashゲームのサウンドエフェクトがある場合、この目的に役立つメニューオプションがないため、GUIからそれらをエクスポートすることはできません(少なくともAdobe Animate CC 2017では)。 しかし、別の解決策があります。それを実行する専用のスクリプトです。
function normalizeFilename(name) { // Converts a camelCase name to snake_case name return name.replace(/([AZ])/g, '_$1').replace(/^_/, '').toLowerCase(); } function displayPath(path) { // Makes the file path more readable return unescape(path).replace('file:///', '').replace('|', ':'); } fl.outputPanel.clear(); if (fl.getDocumentDOM().library.getSelectedItems().length > 0) // Get only selected items var library = fl.getDocumentDOM().library.getSelectedItems(); else // Get all items var library = fl.getDocumentDOM().library.items; // Ask user for the export destination directory var root = fl.browseForFolderURL('Select a folder.'); var errors = 0; for (var i = 0; i < library.length; i++) { var item = library[i]; if (item.itemType !== 'sound') continue; var path = root + '/'; if (item.originalCompressionType === 'RAW') path += normalizeFilename(item.name.split('.')[0]) + '.wav'; else path += normalizeFilename(item.name); var success = item.exportToFile(path); if (!success) errors += 1; fl.trace(displayPath(path) + ': ' + (success ? 'OK' : 'Error')); } fl.trace(errors + ' error(s)');
スクリプトを使用してサウンドファイルをエクスポートする方法:
- 上記のコードを.jsflファイルとしてコンピューターに保存します。
- AdobeAnimateで.flaファイルを開きます。
- トップメニューから[コマンド]→[コマンドの実行]を選択し、開いたダイアログでスクリプトを選択します。
- これで、エクスポート先ディレクトリを選択するための別のダイアログファイルがポップアップ表示されます。
そして完了! これで、指定したディレクトリにWAVファイルが作成されます。 あとは、MP3、OGG、AACなどに変換するだけです。
FlashからHTML5への変換でMP3を使用する方法
一部の特許が失効し、すべてのブラウザがMP3をデコードして再生できるようになったため、古き良きMP3形式が復活しました。 最終的に2つの別々のオーディオ形式を準備する必要がないため、これにより開発が少し簡単になります。 以前は、たとえばOGGファイルとAACファイルが必要でしたが、現在はMP3で十分です。
それでも、MP3について覚えておく必要のある重要なことが2つあります。
- MP3はロード後にデコードする必要があり、特にモバイルデバイスでは時間がかかる可能性があります。 すべてのアセットが読み込まれた後に一時停止が表示される場合は、MP3がデコードされていることを意味している可能性があります。
- ループしたMP3をギャップなしで再生するのは少し問題があります。 解決策はmp3loopを使用することです。これについては、CompuPhaseによって投稿された記事で読むことができます。
では、なぜFlashをJavaScriptに変換する必要があるのでしょうか。
ご覧のとおり、FlashからJavaScriptへの変換は、何をすべきかを知っていれば不可能ではありません。 知識とスキルがあれば、Flashで苦労するのをやめ、JavaScriptで作成されたスムーズで面白いゲームを楽しむことができます。 Flashを修正しようとしないでください。全員が修正を余儀なくされる前に、Flashを削除してください。
詳細を知りたいですか?
この記事では、主にPhaserv2に焦点を当てました。 ただし、新しいバージョンのPhaserが利用可能になりました。複数のカメラ、シーン、タイルマップ、Matter.js物理エンジンなど、多数の新鮮でクールな機能が導入されているため、ぜひチェックしてください。
あなたが十分に勇敢で、ブラウザで本当に素晴らしいものを作りたいのなら、WebGLはゼロから学ぶのに正しいことです。 これは、さまざまなゲーム構築フレームワークやツールよりも抽象化のレベルが低くなりますが、2Dゲームやデモで作業している場合でも、より高いパフォーマンスと品質を実現できます。 WebGLの基本を学ぶときに役立つと思われる多くのWebサイトの中には、WebGL Fundamentals(インタラクティブなデモを使用)があります。 それに加えて、WebGL機能の採用率の詳細については、WebGL統計を確認してください。
特にゲーム開発に関しては、知識が多すぎるということはないことを常に忘れないでください。