【SvelteでRPGゲーム開発】Svelteコンポーネントを使ったHTML中の表示画面のフレキシブル対応
※ 当ページには【広告/PR】を含む場合があります。
2023/02/18

この記事ではSvelteでHTML製ゲームアプリを作る過程をステップ・バイ・ステップでまったり解説していく連載企画です。
4回目の今回は、ブラウザの表示サイズに合わせてアプリの画面サイズを調整する機能を追加するまでを見ていきます。
Svelteゲームの作り方の基本は、あらかた前回の記事で説明した通り、
HTMLゲーム開発としては少し脇道にそれた課題して、
例えば、前回までのアプリをスマホのブラウザから表示させたとしましょう。

このままだとゲーム画面の一部が見切れてますし、コントローラーも半分くらいしか表示されていません。
出来る限り多くの人に遊んでもらいたい場合、いまどきスマホ対応なしだとユーザーを半分以上失ってしまうようなものですので、
この記事で目的としてかかげるポイントは以下の通りです。
1. svelte:window要素のプロパティバインドから画面サイズを取得する
2. iframeを使う場合のフレキシブル対応の注意点
なお、最後まで実装していただくとゲームの画面は以下のようにブラウザに合わせて調整されることが確認できます。
説明
RPG風マップでネコ(?)を動かすだけの実験プログラムです。
画面下にあるコントローラーからの操作が有効になります。
現状は十字キーで上下左右に動くのみです。
svelte:window要素のプロパティバインド
一般的にブラウザは現在の表示状態に関連したいくつかの情報を裏側で保持しています。
この情報を取得して別の処理に利用するにはJavascriptでの実装が不可欠です。
SvelteでDOM要素のサイズ調整をおこないたい場合、
svelte:window
- innerWidth: 現在のページのinnerWidthを取得
- innerHeight: 現在のページのinnerHeightを取得
- outerWidth: 現在のページのouterWidthを取得
- outerHeight: 現在のページのouterHeightを取得
- scrollX: 現在の水平方向のスクロール位置を取得か設定
- scrollY: 現在の垂直方向のスクロール位置を取得か設定
- online: オンラインかオンラインの判定(window.navigator.onLine相当)
HTMLアプリにおいて特に重要になってくるのが、現在のユーザーがブラウザ上に表示しているページの
ブラウザに表示されているページの横幅が分かれば、それに合わせてアプリの画面を調整(=フレキシブル化)することができます。
では早速
svelte:window
Svelteプロジェクトの構成(のnodejs等の設定ファイルは除く)は前回から変わりませんが、今回は
GameStage.svelte
.
├── index.html
└── src
├── App.svelte
├── app.scss
├── main.ts
├── components
│ ├── player.svelte
│ ├── title.svelte
│ └── controller.svelte
└── lib
├── models.ts
└── GameStage.svelte○
#(その他のファイルは省略)
前回までの
GameStage.svelte
<script lang="ts">
//...中略
//👇innerWidthを保持する変数
let innerWidth = 0;
//👇拡大比率(=デフォルトの横幅480pxと現在の横幅の比率)
let ratio = 1;
//👇と、ついでにratioとinnerWidthをリアクティブ化して変化を監視・自動更新
$: ratio = innerWidth/480;
//...中略
</script>
//...中略
//👇svelte:window要素にinnerWidthをバインド
<svelte:window
bind:innerWidth
on:keydown|preventDefault={onKeyDown}
on:keyup|preventDefault={onKeyUp}/>
<div id="wrapper" on:selectstart|preventDefault>
//👇ゲームのメイン画面の要素にstyle属性からwidthとheightをリアルタイム修正
<section style="width: {24*20*ratio}px; height: {24*20*ratio}px;">
{#each _map as mapx}
{#each mapx as mapxy}
<Tile pattern={mapxy.tile_index} left={mapxy.x} top={mapxy.y} ratio={ratio}/>
{/each}
{/each}
<Player left={player.L + slipX} top={player.T + slipY} ratio={ratio}></Player>
</section>
//...中略
</div>
<style lang="scss">
div#wrapper {
width: 480px;
height: 740px;
section {
//👇スタイルファイルからはwidth/heightを設定しないようにコメントアウト
// width: 24px * 20;
// height: 24px * 20;
box-sizing: border-box;
border: solid rgb(0, 0, 0) 1px;
margin: 0;
position: relative;
display: block;
}
}
</style>
ここでのポイントとして、
svelte:window
innerWidth
bind:innerWidth
ratio
ちなみにプロパティバインドするプロパティ名と変数名が一致するときには以下のような略記形が利用できます。
<svelte:window bind:innerWidth={innerWidth}/>
//👇略記形
<svelte:window bind:innerWidth/>
他のJSフレームワークと比較しても、Svelteならばスッキリとした実装テクニックになっている気がします。
iframeを使う場合のフレキシブル対応の注意点
必須ではありませんが、HTMLアプリを一般のブログのようなウェブサイトに埋め込む際には、
iframeを使ったウェブページへのフレキシブル対応は、iframeの性質を良く理解されていないと、全然思う通りにならずに結構つまずきやすいポイントです。
というのも、
iframe要素自体は当然現在のブラウザのコントロール下にあって、cssスタイル付けやjsスクリプトによる操作も受け付けます。
他方、iframeの内部は無法地帯の"別ブラウザ"ですので、その"別ブラウザ"の中身まで操作しようとするのは非常に困難なのです。
iframeのフレキシブル対応は下のリンク記事の解説が詳しいのでとことん理解したい方はそちらを一読されてみてください。
他のHTML系の技術記事でも
「iframeのスマホ対応」
<div class="wrapper">
<iframe src="埋め込みたいアプリの外部URL" scrolling="no" frameborder="0" style="border:0" allowfullscreen></iframe>
</div>
<style lang="scss">
div#wrapper {
position: relative;
width: 100%;
$targetWidth: [外部アプリの表示される幅];
$targetHeight: [外部アプリの表示される高さ];
padding: 0 0 calc($targetHeight / $targetWidth * 100%);
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}
</style>
理解のポイントは、
ここでのiframeの親要素である
div
iframeに指定できるのは基本的に横幅だけで、
何もしないとiframeは高さ0で設定されてしまい、何も表示してくれない...という初心者つまずきポイントになるわけです。
そこでこのテクニックでは、iframeの親要素に
padding
最適な隙間のサイズが、
[外部アプリの表示される高さ] / [外部アプリの表示される幅] * 100%
アスペクト比といえば、一般的にYoutubeに標準アスペクト比は
16:9
9 / 16 * 100%
ただしこれはYoutubeに限った話で、このテクニックを使う場合、iframeの読み込み先の外部アプリが提供しているアスペクト比が最低限分かっている必要があります。
逆に言うと、アスペクト比が分からない・決まったサイズの無いアプリでは上手く使えないことが多いです。 (※例えばTwitterのように画像が遅延読み込みされて表示されるタイプのアプリ)
その場合には、MutationObserverのようなより高度なJavascriptによる実装が必要です。
まとめ
今回はSvelteアプリがブラウザ上に表示されるときにフレキシブルになるように実装を少しだけ改良する話を行っていきました。
1. svelte:window要素のプロパティバインドから画面サイズを取得する
2. iframeを使う場合のフレキシブル対応の注意点
ゲームの内容とは直接関係はしないものの、