【SvelteでRPGゲーム開発】マップ背景を表示する〜基本編


※ 当ページには【広告/PR】を含む場合があります。
2023/01/22
【Scratch拡張機能をJavascriptで自作】SVG画像からスプライトをアニメーション的に動かす拡張機能の作成方法
【SvelteでRPGゲーム開発】requestAnimationFrameを使いながらアニメーションを意識したスプライトを操作する
合同会社タコスキングダム|TacosKingdom,LLC.

ここまで当初の予定だと、Scratchだけで作る自作のRPGサンプルゲーム・
『猫くえすと』をバリバリ開発したい!...という気持ちはありました。

合同会社タコスキングダム|タコキンのPスクール
【ミ二ゲーム開発・リリースノート】とても狭い猫の冒険〜『猫くえすと』まとめ

サイト内で不定期ながら開発中のスクラッチ・ミニRPG『猫くえすと』のリリースノートです。

結論から言うと、
「ScratchだけだとRPGゲームは無理...」ということで事実上のギブアップ宣言です。

...Scratch一本で本格的なゲームを作るのはかなり果てしない作業が予想されており、これより先に進むのはイバラの道かも知れません。

もちろん世の中にはScracthで非常に複雑なゲームを作っていらっしゃる素晴らしい開発者はたくさんおられます。

これらのゲームは、見えないところで大変な作業量と根性で作られていると思うと、常人には真似できず個人的には脱帽です。

ここまでScratchで開発をすすめてきた「猫くえすと」ですが、すでにScratchのプログラミング解説講座というレベルを越えて難しい拡張機能をゴリゴリ作っており、専門的なJavascript言語の深みまで踏み入れてしまったと判断します。

これ以上深みにはまると、「小学生〜高校生レベルのScratch講座」の当初このブログが掲げていた範囲を軽く外れてしまうので、もういっそのこと
「ScratchからSvelteへ引き継ぐ」形で記事の内容をバトンタッチいたします。

ここまでの内容をScratchで追従していただいた方は果たしていらっしゃるかはわかりませんが...もしいらしたら申し訳無い!...ここからは
SvelteでRPG開発の内容に舵切りしてブログを継続してまいります。

なお、このブログではSvelteでのソースコードの実装だけを中心に説明しています。

Svelte/Typescriptの基本プロジェクトの新規作成の手順については、以下のサイトを参考にしてみてください。

Svelte チュートリアルへようこそ|Svelte公式

Dockerを活用すると、簡単にNodejs環境が整います。

Svelteの開発環境をDocker Alpine内で簡単に構築する|タコキンのブログ

以下の記事にも書きましたが、Svelteを始めるなら何かと
「Vite」を導入していた方が楽です。

Svelteアプリ開発でrollup.jsからViteに移行する|タコキンのブログ


JavaScriptとHTMLで「レトロ風RPG」を作ろう 全コード解説

【Svelte.js入門】ReactやVueに挫折した人でも大丈夫!Svelteとfirebaseでシンプルアプリ開発

合同会社タコスキングダム|タコキンのPスクール【Html&Cssアプリ】Html/JavascriptとSassを使った四択クイズゲームの作り方

Svelteコンポーネントに画像をBase64で表示する

ということで当面はScratchアプリでやれていた機能をSvelteに移植させるところまでを中心に解説していきます。

まずは、マップ用のタイルによる背景画像を表示させる機能から作り始めましょう。

今回の記事では、以前
Scratch版のブログで紹介していた内容のように、マップ用の画像をBase64にしてSvelteで表示するところまで確認します。

Svelteプロジェクトの構成(のnodejs等の設定ファイルは除く)は、主に以下のようになっているところからスタートします。

            
            .
├── index.html
└── src
     ├── App.svelte
     ├── app.scss
     ├── main.ts
     ├── components
     │   └── tile.svelte
     └── lib
          └── GameStage.svelte
#(その他のファイルは省略)
        
アプリの起点となるindex.htmlは以下のようにシンプルなものにしておきます。

            
            <!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset='utf-8'>
        <meta name='viewport' content='width=device-width,initial-scale=1'>
        <title>Svelteで自作RPG!</title>
    </head>
    <body>
        <div id="app"></div>
        <script type="module" src="/src/main.ts"></script>
    </body>
</html>
        
そこで読み込まれるメインの実行コード・main.tsは以下の通りです。

            
            import './app.scss'
import App from './App.svelte'

const app = new App({target: document.getElementById('app')})

export default app
        
メインのスタイルファイル・app.scssも最低限の設定を与えておきましょう。

            
            body {
    margin: 0;
    display: flex;
    place-items: center;
    min-width: 320px;
    min-height: 100vh;
    #app {
        margin: 0 auto;
        padding: 12px;
    }
}
        
では、Svelteコードを詳しく見ていきましょう。

まずはアプリが表示される枠にあたる
App.svelteを以下のようにしておきます。

            
            <script lang="ts">
    import GameStage from './lib/GameStage.svelte';
</script>

<div><GameStage/></div>

<style lang="scss">
    div {display: block;}
</style>
        
まだ単純でGameStage.svelteを呼んでいるだけです。

実質ゲームの中身にあたる
GameStage.svelteを、とりあえず動かすだけのテストコードを以下のように作成します。

            
            <script lang="ts">
    import Tile from '../components/tile.svelte';

    //👇試しに与えるマップ配列
    const _map = [...Array(20).keys()].map((x: number) => {
        return [...Array(20).keys()].map((y: number) => {
            return {x: 24*x, y: 24*y}
        })
    });
</script>

<section>
    {#each _map as mapx}
        {#each mapx as mapxy}
            <Tile left={mapxy.x} top={mapxy.y}/>
        {/each}
    {/each}
</section>

<style lang="scss">
    section {
        width: 24px * 20;
        height: 24px * 20;
        box-sizing: border-box;
        border: solid rgb(0, 0, 0) 1px;
        margin: 10px auto;
        position: relative;
        display: block;
        overflow: hidden;
        span { display: block; }
    }
</style>
        
ここで試しにタイル画像を1枚、以下のサイトから頂いてきて使わせてもらいます。

スクラッチ用RPGマップ作成ツール

例えば利用させてもらうのは以下の山の画像です。

合同会社タコスキングダム|タコキンのPスクール

オンラインゲームなどの主にブラウザで動くアプリケーションでは、
base64形式の画像が利用されています。

以下のサイトでは、画像ファイルをBase64形式に変換してもらえるので、

変換ツール(オンライン)

ここではこのツールで変換すると以下のようになります。

            
            data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAJTSURBVEhLjZXBbtNAEIbH66ROI0oOiEBBAXEqL8BTcOiJY0+9IyROSHAqghMSQjwBHDlWiFdA4gVyBCTSEtqiChSaxuuFf+LfnWxslU+ydj37zz87aztJdvdvBJ8HcWlHxBeSulOxHK1ek2zyWVZbTpxvSeESsfrMzyRvh1I9Z7w3lf56pnMnRZB2O5PD0bHMpKVByyTPJO9clVnR1vuDbyfy8/tUvA+qhzkMLTCfx3JxIfcSQtBgx02WxCtfh9KbHkn2TwOgu3x9TVbcVPVNdAd9CUkqybu9jdANzUKy9ehCOZvz9vnvhaOwMP7D3ZTk/WigW2OQHdhEmL+4f1jezXn46pIWsdiCnCevx/fCrfyjBmO469icsIg1jnGxOTs4z5xA12QOXDlWQFxnbk045xFRD3yR6siNagHegNg83h3urZ465qXO68g8LVCXZI05t6Ndjzs5Tvo6guqIkGBbBdbEYnXU2E56YaxzsPQM7O7vTB7raEGn0LAINLiQYztZeAYAweGTBwvmn7pPqyKjsK7j3d5OZYYcaAB1LEIfLcDd0JDm2MXtnZe6tvlnuzIBds4iFnbhaI7dEyQgzg+JBXnRnF0QxHHZLrQDmjPRGnAOIxoQu2ax8aWHDHgs1qwJbo45hPGlAhTaI4tpMovjQAtwockc8brY/6A/1/EZEpjWmYPzijI32R1tBHeaydrJFfl1cVgunz24OnMQd0BDy5tnhSQfvgzC/kH973lTZ4CvIoh1WOOXXP2jESzUFQN2jQZNWrLwFjWZ15lhHmupO0PkL0Q+bDUvpbHbAAAAAElFTkSuQmCC
        
Svelteでは、このBase64形式のdata:image/png;base64,より後の文字列を利用することになります。

スプライトとして動くSvelteコード(コンポーネント)を
tile.svelteという名前を付けて以下のように作成しましょう。

            
            <script lang="ts">
    export let top: number;
    export let left: number;
    const mountain = 'iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAJTSURBVEhLjZXBbtNAEIbH66ROI0oOiEBBAXEqL8BTcOiJY0+9IyROSHAqghMSQjwBHDlWiFdA4gVyBCTSEtqiChSaxuuFf+LfnWxslU+ydj37zz87aztJdvdvBJ8HcWlHxBeSulOxHK1ek2zyWVZbTpxvSeESsfrMzyRvh1I9Z7w3lf56pnMnRZB2O5PD0bHMpKVByyTPJO9clVnR1vuDbyfy8/tUvA+qhzkMLTCfx3JxIfcSQtBgx02WxCtfh9KbHkn2TwOgu3x9TVbcVPVNdAd9CUkqybu9jdANzUKy9ehCOZvz9vnvhaOwMP7D3ZTk/WigW2OQHdhEmL+4f1jezXn46pIWsdiCnCevx/fCrfyjBmO469icsIg1jnGxOTs4z5xA12QOXDlWQFxnbk045xFRD3yR6siNagHegNg83h3urZ465qXO68g8LVCXZI05t6Ndjzs5Tvo6guqIkGBbBdbEYnXU2E56YaxzsPQM7O7vTB7raEGn0LAINLiQYztZeAYAweGTBwvmn7pPqyKjsK7j3d5OZYYcaAB1LEIfLcDd0JDm2MXtnZe6tvlnuzIBds4iFnbhaI7dEyQgzg+JBXnRnF0QxHHZLrQDmjPRGnAOIxoQu2ax8aWHDHgs1qwJbo45hPGlAhTaI4tpMovjQAtwockc8brY/6A/1/EZEpjWmYPzijI32R1tBHeaydrJFfl1cVgunz24OnMQd0BDy5tnhSQfvgzC/kH973lTZ4CvIoh1WOOXXP2jESzUFQN2jQZNWrLwFjWZ15lhHmupO0PkL0Q+bDUvpbHbAAAAAElFTkSuQmCC';
</script>

<object title="" data="data:image/png;base64,{mountain}" type="image/png" style="left: {left}px; top: {top}px"></object>

<style lang="scss">
object {
    display: block;
    width: 24px;
    height: 24px;
    position: absolute;
}
</style>
        
これで一通りテストコードが揃ったので、yarn devでアプリケーションを動かしてみると、

合同会社タコスキングダム|タコキンのPスクール

というように、山のタイル画像が画面いっぱいに貼り付くだけのプログラムが出来ました。


JavaScriptとHTMLで「レトロ風RPG」を作ろう 全コード解説

【Svelte.js入門】ReactやVueに挫折した人でも大丈夫!Svelteとfirebaseでシンプルアプリ開発

合同会社タコスキングダム|タコキンのPスクール【Html&Cssアプリ】Html/JavascriptとSassを使った四択クイズゲームの作り方

他のタイル画像を組み合わせてマップを作る

先程は1つの画像で画面を埋めてみただけで、使い物にはなりません。

本番では、
マップ定義からそれに応じた画像を配置してあげる必要があります。

そこでまず修正していく前に、先程
GameStage.svelteのスクリプトの中で適当に与えていたマップ配列の部分をもう一度良く見てみましょう。

            
            <script lang="ts">
    ...
    const _map = [...Array(20).keys()].map((x: number) => {
        return [...Array(20).keys()].map((y: number) => {
            return {x: 24*x, y: 24*y}
        })
    });
    ...
</script>

...
<section>
    {#each _map as mapx}
        {#each mapx as mapxy}
            <Tile left={mapxy.x} top={mapxy.y}/>
        {/each}
    {/each}
</section>
...
        
見てのように、 [...Array(20).keys()]という部分は、適当に展開された数字の配列・[0, 1, 2, ...., 19]になるJavascriptのテクニックです。

これだと意味がないので、きちんとしたマップ配列として生成したものを利用します。

タイルマップのインデックス配列化については、以下の記事で概要を掘り下げて説明していましたので、そちらを参考にしてみてください。

合同会社タコスキングダム|タコキンのPスクール
【Scratch拡張機能をJavascriptで自作】svg画像からRPG風のマップを生成する拡張機能を作る〜マップ作成編②

Scratchの自作拡張機能で、RPGゲームのマップの種となるcsvファイルを使ってBase64化したタイルの画像を所定の座標に張り合わせるプログラムを作ります。

タイル画像をもう一つ草原のものを追加してみます。

合同会社タコスキングダム|タコキンのPスクール

タイルにインデックス(識別番号)をルール付します。

            
            山のタイル ... 1
草原のタイル ... 2
        
そしてこのルールを元に、マップ配列(20 x 20の行列)を以下のように与えます。

            
            ...
const _arr = [
    [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
    [1,1,1,2,1,2,2,1,1,2,2,2,1,1,2,1,2,1,1,1],
    [1,1,2,2,1,2,2,2,1,2,2,2,1,2,2,1,2,2,1,1],
    [1,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,1],
    [1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
    [1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1],
    [1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1],
    [1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
    [1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1],
    [1,2,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,1],
    [1,2,2,2,2,2,2,2,2,1,1,1,2,2,2,2,2,2,1,1],
    [1,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,1,1],
    [1,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,1],
    [1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,1],
    [1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1],
    [1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1],
    [1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
    [1,2,2,2,2,1,2,2,2,2,2,1,2,1,2,2,1,2,2,1],
    [1,1,2,2,1,1,1,1,2,2,1,1,1,2,2,2,1,1,2,1],
    [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
];
...
        
この配列の配列いわゆる2次元配列を「マップ配列」とここでは呼んでおきましょう。

このマップ配列に従って、インデックス番号に対応したタイル画像を画面に貼り付ける際の設計図になります。

まずはインデックス番号でタイル画像を選択できるように
tile.svelteコンポーネントから修正していきます。

            
            <script lang="ts">
    export let top: number;
    export let left: number;
    //👇インプット変数(=インデックス番号)を新しく追加
    export let pattern: number;
    const mountain = 'iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAJTSURBVEhLjZXBbtNAEIbH66ROI0oOiEBBAXEqL8BTcOiJY0+9IyROSHAqghMSQjwBHDlWiFdA4gVyBCTSEtqiChSaxuuFf+LfnWxslU+ydj37zz87aztJdvdvBJ8HcWlHxBeSulOxHK1ek2zyWVZbTpxvSeESsfrMzyRvh1I9Z7w3lf56pnMnRZB2O5PD0bHMpKVByyTPJO9clVnR1vuDbyfy8/tUvA+qhzkMLTCfx3JxIfcSQtBgx02WxCtfh9KbHkn2TwOgu3x9TVbcVPVNdAd9CUkqybu9jdANzUKy9ehCOZvz9vnvhaOwMP7D3ZTk/WigW2OQHdhEmL+4f1jezXn46pIWsdiCnCevx/fCrfyjBmO469icsIg1jnGxOTs4z5xA12QOXDlWQFxnbk045xFRD3yR6siNagHegNg83h3urZ465qXO68g8LVCXZI05t6Ndjzs5Tvo6guqIkGBbBdbEYnXU2E56YaxzsPQM7O7vTB7raEGn0LAINLiQYztZeAYAweGTBwvmn7pPqyKjsK7j3d5OZYYcaAB1LEIfLcDd0JDm2MXtnZe6tvlnuzIBds4iFnbhaI7dEyQgzg+JBXnRnF0QxHHZLrQDmjPRGnAOIxoQu2ax8aWHDHgs1qwJbo45hPGlAhTaI4tpMovjQAtwockc8brY/6A/1/EZEpjWmYPzijI32R1tBHeaydrJFfl1cVgunz24OnMQd0BDy5tnhSQfvgzC/kH973lTZ4CvIoh1WOOXXP2jESzUFQN2jQZNWrLwFjWZ15lhHmupO0PkL0Q+bDUvpbHbAAAAAElFTkSuQmCC';
    const grassland = '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';

    //👇インデックス番号からタイル画像を選択
    const image =
        pattern == 1 ? mountain  :
        pattern == 2 ? grassland :
        '';
</script>

<object title="" data="data:image/png;base64,{image}" type="image/png" style="left: {left}px; top: {top}px"></object>

<style lang="scss">
object {
    display: block;
    width: 24px;
    height: 24px;
    position: absolute;
}
</style>
        
これで親コンポーネントからインデックス番号付きでtileコンポーネントを呼び出して自由にマップタイルが貼り付けできるようになりました。

GameStage.svelte側も以下のように修正します。

            
            <script lang="ts">
    import Tile from '../components/tile.svelte';

    //👇マップ配列
    const _arr = [
        [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
        [1,1,1,2,1,2,2,1,1,2,2,2,1,1,2,1,2,1,1,1],
        [1,1,2,2,1,2,2,2,1,2,2,2,1,2,2,1,2,2,1,1],
        [1,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,1],
        [1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
        [1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1],
        [1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1],
        [1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
        [1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1],
        [1,2,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,1],
        [1,2,2,2,2,2,2,2,2,1,1,1,2,2,2,2,2,2,1,1],
        [1,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,1,1],
        [1,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,1],
        [1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,1],
        [1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1],
        [1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1],
        [1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
        [1,2,2,2,2,1,2,2,2,2,2,1,2,1,2,2,1,2,2,1],
        [1,1,2,2,1,1,1,1,2,2,1,1,1,2,2,2,1,1,2,1],
        [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
    ];

    //👇マップ配列の中身を{インデックス番号,x座標,y座標}になるように変換
    const _map = _arr.map((r: number[], i: number) => {
        return r.map((c: number, j: number) => {
            return {tile_index: c, x: 24*i, y: 24*j}
        })
    });
</script>

<section>
    {#each _map as mapx}
        {#each mapx as mapxy}
            <Tile pattern={mapxy.tile_index} left={mapxy.x} top={mapxy.y}/>
        {/each}
    {/each}
</section>

<style lang="scss">
    section {
        width: 24px * 20;
        height: 24px * 20;
        box-sizing: border-box;
        border: solid rgb(0, 0, 0) 1px;
        margin: 10px auto;
        position: relative;
        display: block;
        overflow: hidden;
        span { display: block; }
    }
</style>
        
これで再度yarn devして起動してみましょう。

合同会社タコスキングダム|タコキンのPスクール

と、このようにマップ配列に対応した地形が狙い通り表示されていたらひとまずOKです。

今後の課題

課題としてまず挙げたいのが、手動でマップ配列を作るのは大変ということです。

その点を踏まえて、Scratchでのマップ配列作成に関しては、専用のエクステンションを作って対応していました。

合同会社タコスキングダム|タコキンのPスクール
【Scratch拡張機能をJavascriptで自作】svg画像からRPG風のマップを生成する拡張機能を作る〜拡張機能の実装③

RPG風のタイルパターンを使ったマップを作成するScratch拡張機能をJavacriptプログラミングから完成させます。

ゲームとして拡張していくためには、
先程紹介させて頂いたサイトようなタイルマップを作る補助的なツールをSvelte用として自作する必要があるでしょう。

この辺はおいおい後日のブログ記事で説明していこうかと思っています。


JavaScriptとHTMLで「レトロ風RPG」を作ろう 全コード解説

【Svelte.js入門】ReactやVueに挫折した人でも大丈夫!Svelteとfirebaseでシンプルアプリ開発

合同会社タコスキングダム|タコキンのPスクール【Html&Cssアプリ】Html/JavascriptとSassを使った四択クイズゲームの作り方

まとめ

今回から『自作するRPG』のプロジェクトを「Scratch」から「Svelte(Javascript)」へバトンタッチすることで、もっと気軽に作業を楽に作ることを目指します。

Scratchでも当然頑張ればやれないことは無いのですが、本格的なゲームを作ることは「一人でエベレスト登頂」をやってのけるようなものです。

Scratchエクステンションを使いこなすには、Javascriptの深い知識が必要とされるので、ITエンジニア級の実力が備わっていることは必須です。

そこで、Svelteに開発言語を変えることで、Scratchでやれるエベレストほどの高さも、富士山登山くらいにはハードルが下がると思います。

今回説明するRPGに限らず、Scratchでのアプリ開発に息詰まったら、多言語への切り替えのサインだと思って、思い切ってプロジェクトごと移行してみるのもプログラマーの重要な判断かと考えます。