<?xml version="1.0" encoding="UTF-8" ?>
<rdf:RDF
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns="http://purl.org/rss/1.0/"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">

  <channel rdf:about="https://cript.game-ss.com/RSS/100/">
    <title>JavaScriptゲーム</title>
    <link>https://cript.game-ss.com/</link>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="https://cript.game-ss.com/RSS/" />
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" />
    <description>JavaScriptでゲームを作る！</description>
    <dc:language>ja</dc:language>
    <dc:date>2025-04-18T09:38:01+09:00</dc:date>
    <items>
    <rdf:Seq>
      <rdf:li rdf:resource="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E3%82%B9%E3%83%86%E3%83%BC%E3%82%BF%E3%82%B9%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95" />
      <rdf:li rdf:resource="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E5%A0%B4%E9%9D%A2%E3%82%92%E9%81%B7%E7%A7%BB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95" />
      <rdf:li rdf:resource="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95" />
      <rdf:li rdf:resource="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95" />
      <rdf:li rdf:resource="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E7%A7%BB%E5%8B%95%E3%81%97%E3%81%AA%E3%81%8C%E3%82%89%E3%83%95%E3%82%A7%E3%83%BC%E3%83%89%E3%82%A4%E3%83%B3%EF%BC%8F%E3%82%A2%E3%82%A6%E3%83%88%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95" />
      <rdf:li rdf:resource="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E3%83%95%E3%82%A7%E3%83%BC%E3%83%89%E3%82%A4%E3%83%B3%EF%BC%8F%E3%82%A2%E3%82%A6%E3%83%88%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95" />
      <rdf:li rdf:resource="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E7%94%BB%E5%83%8F%E3%82%92%E7%A7%BB%E5%8B%95%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95" />
      <rdf:li rdf:resource="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E7%94%BB%E5%83%8F%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95" />
    </rdf:Seq>
    </items>
  </channel>

  <item rdf:about="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E3%82%B9%E3%83%86%E3%83%BC%E3%82%BF%E3%82%B9%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95">
    <link>https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E3%82%B9%E3%83%86%E3%83%BC%E3%82%BF%E3%82%B9%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95</link>
    <title>ステータスウィンドウを表示する方法</title>
    <description>記事が長すぎてアップロードできなかったので、こちらに上げました。
ステータスウィンドウを表示する方法： 
https://cf033538.cloudfree.jp/Game/sample08/blog/...</description>
    <content:encoded><![CDATA[記事が長すぎてアップロードできなかったので、こちらに上げました。<br />
ステータスウィンドウを表示する方法： <br />
<a href="https://cf033538.cloudfree.jp/Game/sample08/blog/" title="" target="_self">https://cf033538.cloudfree.jp/Game/sample08/blog/</a>]]></content:encoded>
    <dc:subject>JavaScript紹介</dc:subject>
    <dc:date>2025-04-18T09:38:01+09:00</dc:date>
    <dc:creator>No Name Ninja</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>No Name Ninja</dc:rights>
  </item>
  <item rdf:about="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E5%A0%B4%E9%9D%A2%E3%82%92%E9%81%B7%E7%A7%BB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95">
    <link>https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E5%A0%B4%E9%9D%A2%E3%82%92%E9%81%B7%E7%A7%BB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95</link>
    <title>場面を遷移する方法</title>
    <description>
前回の「選択肢を表示する方法」のコードでは、選択肢毎にコードを書く必要がありif文だらけのコードになっていました。
今回はこの問題を解消する方法を記します。
以下の例では、見た目では分かりませんが、画像、メッセージ、選択肢情報といったパラメータを変えただけで、全て共通のコードを実行しています。
そ...</description>
    <content:encoded><![CDATA[<div class="本文">
<p>前回の「選択肢を表示する方法」のコードでは、選択肢毎にコードを書く必要がありif文だらけのコードになっていました。<br />
今回はこの問題を解消する方法を記します。<br />
以下の例では、見た目では分かりませんが、画像、メッセージ、選択肢情報といったパラメータを変えただけで、全て共通のコードを実行しています。<br />
そのため、どれだけ画像やメッセージ、選択肢が増えても、if文等のコードが増えることはありません。</p>
<div class="iframe-container"><iframe width="670" height="930" style="border: 0;" src="https://cf033538.cloudfree.jp/Game/sample07/index.html"></iframe></div>
<h2 class="heading-018">ファイル構成</h2>
<p>ファイルとそれを入れるフォルダーを以下のような構成します。<br />
※背景と人物の画像はBing Image Creatorで生成しています（AI生成）。</p>
<div class="ファイル構成">
<ul class="list-13">
<li><span>sample07</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/index.html" target="_blank">index.html</a></li>
<li><span>js</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/js/sample.js" target="_blank">sample.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/js/messageWindow.js" target="_blank">messageWindow.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/js/data.js" target="_blank">data.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/js/com.js" target="_blank">com.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/js/imageManager.js" target="_blank">imageManager.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/js/sprite.js" target="_blank">sprite.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/js/layer.js" target="_blank">layer.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/js/loop.js" target="_blank">loop.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/js/commandWindow.js" target="_blank">commandWindow.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/js/scene.js" target="_blank">scene.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/js/sceneTransition.js" target="_blank">sceneTransition.js</a></li>
</ul>
</li>
<li><span>css</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/css/sample.css" target="_blank">sample.css</a></li>
</ul>
</li>
<li><span>img</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/img/bg02.jpg" target="_blank">bg02.jpg　※町の画像（1024x1024px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/img/bg03.jpg" target="_blank">bg03.jpg　※宿屋の画像（1024x1024px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/img/chara01.png" target="_blank">chara01.png　※プレイヤーの画像（1024x1024px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample07/img/chara03.png" target="_blank">chara03.png　※受付の画像（661x909px）</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<h2 class="heading-018">scene.js　-　場面情報クラス</h2>
<pre class="code"><code>class 選択肢情報クラス {
    constructor(ar) {
        this.id = ar[0];
        this.名称 = ar[1];
    }
}

class 画像情報クラス {
    constructor(ar) {
        this.スプライトid = ar[0];
        this.レイヤーid = ar[1];
        this.画像id = ar[2];
        this.x1 = ar[3];
        this.y1 = ar[4];
        this.x2 = ar[5];
        this.y2 = ar[6];
        this.表示メソッド = ar[7];
        this.p1 = ar[8];
        this.p2 = ar[9];
        this.p3 = ar[10];
    }
}

export class 場面情報クラス {
    constructor(ar) {
        this.id = ar[0];
        this.メッセージ = ar[1];

        this.選択肢情報リスト = [];
        ar[2].forEach(x =&gt; this.選択肢情報リスト.push(new 選択肢情報クラス(x)));

        this.画像情報リスト = [];
        if (ar[3]) ar[3].forEach(x =&gt; this.画像情報リスト.push(new 画像情報クラス(x)));
    }
}
</code></pre>
<h3 class="heading-23">1. 選択肢情報クラス</h3>
<p>このクラスは「選択肢」を管理するためのものです。</p>
<ul class="箇条書き1">
<li><span class="bold">コンストラクタ：</span>クラスを作るときに、配列 ar を受け取ります。
<ul class="箇条書き2">
<li>ar[0] は選択肢の「id」。</li>
<li>ar[1] は選択肢の「名称」（例えば「はい」や「いいえ」など）。</li>
</ul>
</li>
</ul>
<p>このクラスを使うことで、選択肢のデータを簡単に扱えるようになります。</p>
<h3 class="heading-23">2. 画像情報クラス</h3>
<p>このクラスは、プログラム内で表示する画像の情報を管理します。</p>
<ul class="箇条書き1">
<li><span class="bold">コンストラクタ：</span>配列 ar を受け取り、画像に関する情報を格納します。
<ul class="箇条書き2">
<li><span class="bold">スプライトid：</span>画像の識別ID。</li>
<li><span class="bold">レイヤーid：</span>どの層（レイヤー）に画像を表示するか。</li>
<li><span class="bold">画像id：</span>実際の画像データの識別子。</li>
<li><span class="bold">x1, y1：</span>画像の開始位置（左上の座標）。</li>
<li><span class="bold">x2, y2：</span>画像の終了位置（右下の座標）。</li>
<li><span class="bold">表示メソッド：</span>画像をどのように表示するか（例えば拡大・縮小）。</li>
<li><span class="bold">p1, p2, p3：</span>追加のパラメータ（用途に応じて設定）。</li>
</ul>
</li>
</ul>
<p>このクラスにより、画像を座標やレイヤーに基づいて管理できます。</p>
<h3 class="heading-23">3. 場面情報クラス</h3>
<p>このクラスは、「場面」を管理するためのメインクラスです。</p>
<ul class="箇条書き1">
<li><span class="bold">コンストラクタ：</span>配列 ar を受け取り、以下の情報を設定します。
<ul class="箇条書き2">
<li><span class="bold">id：</span>場面の識別子。</li>
<li><span class="bold">メッセージ：</span>この場面で表示する文章。</li>
<li><span class="bold">選択肢情報リスト：</span>ar[2] に含まれる選択肢のデータを 選択肢情報クラス に変換して保存します。</li>
<li><span class="bold">画像情報リスト：</span>ar[3] が存在する場合、画像データを 画像情報クラス に変換して保存します。</li>
</ul>
</li>
</ul>
<p>このクラスを利用すると、場面に対応するメッセージ、選択肢、画像を一括して扱えます。</p>
<h2 class="heading-018">sceneTransition.js　-　場面遷移クラス</h2>
<pre class="code"><code>import { スプライトクラス } from './sprite.js'; // クラスをインポート

export class 場面遷移 {
    static レイヤー管理 = {};
    static スプライト管理 = {};
    static 場面情報管理 = {};
    static 場面情報 = null;
    static 画像管理 = null;
    static メッセージウィンドウ = null;
    static コマンドウィンドウ = null;

    static async 開始する() {
        if (!場面遷移.場面情報) throw new Error("場面情報が初期化されていません");

        while (1) {
            await 場面遷移.画像を表示する();
            await 場面遷移.メッセージを表示する();
            const 選択肢情報 = 場面遷移.場面情報.選択肢情報リスト[0];
            if (!選択肢情報.名称) {
                // 選択肢情報に名称が無い場合は場面を遷移する
                場面遷移.場面情報 = 場面遷移.場面情報管理[選択肢情報.id];
                continue;
            }
            await 場面遷移.コマンドウィンドウを表示する();
        }
    }

    static async 画像を表示する() {
        if (場面遷移.場面情報.画像情報リスト.length == 0) return; // 画像情報が無い場合は何もしない

        let スプライト, 画像要素;
        const プロミスリスト = [];
        場面遷移.場面情報.画像情報リスト.forEach(画像情報 =&gt; {
            スプライト = 場面遷移.スプライト管理[画像情報.スプライトid];
            if (!画像情報.画像id) {
                if (!スプライト) return; // 画像idが無い場合はスプライトを作成できないので何もしない
            } else {
                画像要素 = 場面遷移.画像管理.取得する(画像情報.画像id);
                if (スプライト) {
                    // 指定したスプライトに別の画像を設定したい場合は新たにスプライトを作り直す
                    if (スプライト.画像要素 != 画像要素) スプライト = 場面遷移.スプライトを作成する(画像要素, 画像情報);
                } else {
                    // 指定したスプライトが存在しない場合は新たに作成する
                    スプライト = 場面遷移.スプライトを作成する(画像要素, 画像情報);
                }
            }

            場面遷移.表示メソッドに従って画像を表示する(画像情報, スプライト, プロミスリスト);
        });

        if (プロミスリスト.length == 0) return;
        await Promise.all(プロミスリスト);
    }

    static スプライトを作成する(画像要素, 画像情報) {
        const スプライト = new スプライトクラス(
            場面遷移.レイヤー管理[画像情報.レイヤーid],
            画像要素,
            画像情報.x1,
            画像情報.y1,
            画像情報.x2,
            画像情報.y2
        );
        場面遷移.スプライト管理[画像情報.スプライトid] = スプライト;
        return スプライト;
    }

    static 表示メソッドに従って画像を表示する(画像情報, スプライト, プロミスリスト) {
        if ((画像情報.表示メソッド == "フェードインする") || (画像情報.表示メソッド == "フェードアウトする")) {
            プロミスリスト.push(スプライト[画像情報.表示メソッド](画像情報.p1));
        } else if (画像情報.表示メソッド == "移動してフェードインする") {
            const 正位置 = { x: スプライト.x, y: スプライト.y };
            const 移動距離 = { x: 0, y: 0 };
            場面遷移.移動距離を取得する(画像情報, 移動距離, -640);
            スプライト.座標を設定する(
                画像情報.x1 + 移動距離.x,
                画像情報.y1 + 移動距離.y,
                画像情報.x2 + 移動距離.x,
                画像情報.y2 + 移動距離.y
            );
            プロミスリスト.push(スプライト[画像情報.表示メソッド](画像情報.p1, 画像情報.p2, 正位置.x, 正位置.y, 画像情報.p3));
        } else if (画像情報.表示メソッド == "移動してフェードアウトする") {
            const 移動距離 = { x: 0, y: 0 };
            場面遷移.移動距離を取得する(画像情報, 移動距離, 640);
            プロミスリスト.push(スプライト[画像情報.表示メソッド](画像情報.p1, 画像情報.p2, 移動距離.x, 移動距離.y, 画像情報.p3));
        }
    }

    static 移動距離を取得する(画像情報, 移動距離, 基本移動距離) {
        if (画像情報.p1 &gt; 0) 移動距離.x = 基本移動距離;
        else if (画像情報.p1 &lt; 0) 移動距離.x = -基本移動距離;

        if (画像情報.p2 &gt; 0) 移動距離.y = 基本移動距離;
        else if (画像情報.p2 &lt; 0) 移動距離.y = -基本移動距離;
    }

    static async メッセージを表示する() {
        if (!場面遷移.場面情報.メッセージ) return; // 表示するメッセージが無い場合は何もしない
        await 場面遷移.メッセージウィンドウ.表示する();
        await 場面遷移.メッセージウィンドウ.メッセージを表示する(場面遷移.場面情報.メッセージ);
    }

    static async コマンドウィンドウを表示する() {
        const id = await 場面遷移.コマンドウィンドウ.表示する(場面遷移.場面情報.選択肢情報リスト);
        場面遷移.場面情報 = 場面遷移.場面情報管理[id];
    }
}
</code></pre>
<h3 class="heading-23">1. 場面遷移クラス全体の役割</h3>
<p>このクラスは、プログラムの場面を管理するためのメインクラスです。例えば、特定の画像やメッセージを表示したり、場面を切り替えたりします。</p>
<ul class="箇条書き1">
<li><span class="bold">静的プロパティ：</span>各種データ（レイヤー管理、スプライト管理、場面情報管理など）を一括で管理します。</li>
<li><span class="bold">場面遷移：</span>開始する メソッドを呼び出すことで、プログラムの場面遷移が始まります。</li>
<li><span class="bold">ループ構造：</span>無限ループ (while(1)) を使って、場面表示の処理を繰り返します。</li>
</ul>
<h3 class="heading-23">2. 静的プロパティ</h3>
<p>場面遷移クラスでは、多くのデータを静的プロパティで管理しています。</p>
<ul class="箇条書き1">
<li><span class="bold">レイヤー管理：</span>レイヤー（表示する層）を管理します。</li>
<li><span class="bold">スプライト管理：</span>スプライト（プログラム内の画像要素）を管理します。</li>
<li><span class="bold">場面情報管理：</span>複数の場面に対応するデータを保存します。</li>
<li><span class="bold">場面情報：</span>現在の場面のデータを保持します。</li>
<li><span class="bold">画像管理：</span>画像を取得したりするための機能を提供します。</li>
<li><span class="bold">メッセージウィンドウ &amp; コマンドウィンドウ：</span>メッセージや選択肢を表示するための管理要素です。</li>
</ul>
<h3 class="heading-23">3. 場面を開始する: 開始する メソッド</h3>
<p>このメソッドは、場面遷移の主要な処理を行います。</p>
<p><span class="bold">処理手順：</span></p>
<ol class="箇条書き1">
<li><span class="bold">初期化チェック：</span>場面情報 が設定されていない場合はエラー (throw new Error) を発生させます。</li>
<li><span class="bold">画像とメッセージの表示：</span>画像を表示する メソッドで画像を表示し、次に メッセージを表示する メソッドでメッセージを表示します。</li>
<li><span class="bold">場面遷移：</span>選択肢情報に基づいて次の場面を設定します。選択肢に名称がない場合は、自動的に次の場面に進みます。</li>
<li><span class="bold">選択肢の表示：</span>コマンドウィンドウを表示する メソッドで選択肢をユーザーに提示します。</li>
</ol>
<h3 class="heading-23">4. 画像を表示する: 画像を表示する メソッド</h3>
<p>画面に画像を表示するための処理を行います。</p>
<ul class="箇条書き1">
<li><span class="bold">画像情報の確認：</span>現在の場面情報に画像情報がない場合は何もしません。</li>
<li><span class="bold">スプライトの作成：</span>必要に応じて新しいスプライト（画像要素）を作成します。</li>
<li><span class="bold">表示メソッド：</span>画像を表示する際の方法（フェードインや移動など）に従って処理します。</li>
<li><span class="bold">非同期処理：</span>Promise.all を利用して画像表示の処理が完了するのを待ちます。</li>
</ul>
<h3 class="heading-23">5. スプライトの管理: スプライトを作成する メソッド</h3>
<p>スプライトは、画像を画面上に表示するための単位です。</p>
<ul class="箇条書き1">
<li><span class="bold">パラメータ：</span>画像要素、座標 (x1, y1, x2, y2) を指定してスプライトを作成します。</li>
<li><span class="bold">レイヤー設定：</span>スプライトを配置するレイヤーを管理します。</li>
</ul>
<h3 class="heading-23">6. 画像表示メソッドの適用: 表示メソッドに従って画像を表示する メソッド</h3>
<p>画像の表示方法を指定して実行します。</p>
<ul class="箇条書き1">
<li><span class="bold">フェードイン/フェードアウト：</span>画像を徐々に表示したり消したりします。</li>
<li><span class="bold">移動して表示：</span>画像を指定した位置に移動させながら表示します。</li>
<li><span class="bold">座標計算：</span>必要に応じて移動距離や座標を計算します。</li>
</ul>
<h3 class="heading-23">7. メッセージ表示: メッセージを表示する メソッド</h3>
<p>場面のメッセージを画面に表示します。</p>
<ul class="箇条書き1">
<li><span class="bold">メッセージウィンドウの表示：</span>メッセージウィンドウを表示します。</li>
<li><span class="bold">メッセージ内容の更新：</span>現在の場面のメッセージを設定して表示します。</li>
</ul>
<h3 class="heading-23">8. 選択肢の表示: コマンドウィンドウを表示する メソッド</h3>
<p>選択肢情報リストに基づいて選択肢を表示します。</p>
<ul class="箇条書き1">
<li><span class="bold">選択肢の取得：</span>ユーザーが選んだ選択肢のIDを取得します。</li>
<li><span class="bold">場面遷移：</span>選択肢に応じて次の場面情報を設定します。</li>
</ul>
<h2 class="heading-018">sample.js　-　サンプルクラス</h2>
<p>このプログラムでは、次のような流れで「場面」を管理します：</p>
<ol class="箇条書き1">
<li>必要な画像やレイヤー、ウィンドウを準備。</li>
<li>「場面」の情報（テキスト、画像、選択肢など）を管理する。</li>
<li>実際に選択肢を選びながら場面を遷移する仕組みを実現。</li>
</ol>
<pre class="code"><code>import { 画像管理クラス } from './imageManager.js'; // クラスをインポート
import { レイヤークラス } from './layer.js'; // クラスをインポート
import { ループ } from './loop.js'; // クラスをインポート
import { メッセージウィンドウクラス } from './messageWindow.js'; // クラスをインポート
import { コマンドウィンドウクラス } from './commandWindow.js'; // クラスをインポート
import { Data } from './data.js'; // クラスをインポート
import { 場面情報クラス } from './scene.js'; // クラスをインポート
import { 場面遷移 } from './sceneTransition.js'; // クラスをインポート

export class サンプル {
    static 遷移データリスト = [
        ["スタート", , [["町の広場へ行く",]],]
        , ["町の広場へ行く", "プレイヤーは町の広場に来た&lt;w&gt;10&lt;/w&gt;", [["町の広場",]], [["背景01", , , , , , , "フェードアウトする", 1, ,], ["背景01", "レイヤー1", "町", 0, 0, 640, 640, "フェードインする", 1, ,], ["人物01", , , , , , , "移動してフェードアウトする", -20, 0, 1], ["人物01", "レイヤー2", "プレイヤー", 0, 0, 640, 640, "移動してフェードインする", -20, 0, 1]]]
        , ["町の広場", "どうする？", [["話す", "話す"], ["持物を見る", "持物を見る"], ["移動する", "移動する"]],]
        , ["話す", "話が聞けそうな人は誰もいない&lt;w&gt;10&lt;/w&gt;", [["町の広場",]],]
        , ["持物を見る", "今のところ、何も持っていない&lt;w&gt;10&lt;/w&gt;", [["町の広場",]],]
        , ["移動する", "どこへ行く？", [["町の広場", "やめる"], ["武器屋へ行く", "武器屋へ行く"], ["防具屋へ行く", "防具屋へ行く"], ["道具屋へ行く", "道具屋へ行く"], ["宿屋へ行く", "宿屋へ行く"], ["町を出る", "町を出る"]],]
        , ["武器屋へ行く", "武器屋は開いていないようだ&lt;w&gt;10&lt;/w&gt;", [["町の広場",]],]
        , ["防具屋へ行く", "防具屋は開いていないようだ&lt;w&gt;10&lt;/w&gt;", [["町の広場",]],]
        , ["道具屋へ行く", "道具屋は開いていないようだ&lt;w&gt;10&lt;/w&gt;", [["町の広場",]],]
        , ["宿屋へ行く", "プレイヤーは宿屋に来た&lt;w&gt;10&lt;/w&gt;", [["宿屋01",]], [["背景01", , , , , , , "フェードアウトする", 1, ,], ["背景01", "レイヤー1", "宿屋", 0, 0, 640, 640, "フェードインする", 1, ,], ["人物01", , , , , , , "移動してフェードアウトする", 20, 0, 1]]]
        , ["宿屋01", "受付：&lt;br&gt;いらっしゃいませ&lt;br&gt;一泊100カーネですが&lt;br&gt;お泊りになりますか？", [["宿屋02", "泊まる"], ["宿屋05", "やめる"]], [["人物01", "レイヤー2", "受付", 0, 0, 640, 640, "移動してフェードインする", 20, 0, 1]]]
        , ["宿屋02", "受付：&lt;br&gt;それではお休みください&lt;w&gt;10&lt;/w&gt;", [["宿屋03",]],]
        , ["宿屋03", "プレイヤーはしばし眠りについた&lt;w&gt;10&lt;/w&gt;", [["宿屋04",]], [["背景01", , , , , , , "フェードアウトする", 1, ,], ["人物01", , , , , , , "移動してフェードアウトする", -20, 0, 1], ["人物01", "レイヤー2", "プレイヤー", 0, 0, 640, 640, "移動してフェードインする", -20, 0, 1]]]
        , ["宿屋04", "受付：&lt;br&gt;お早うございます&lt;br&gt;またのお越しをお待ちしております&lt;w&gt;10&lt;/w&gt;", [["町の広場へ行く",]], [["背景01", , , , , , , "フェードインする", 1, ,], ["人物01", , , , , , , "移動してフェードアウトする", 20, 0, 1], ["人物01", "レイヤー2", "受付", 0, 0, 640, 640, "移動してフェードインする", 20, 0, 1]]]
        , ["宿屋05", "受付：&lt;br&gt;やめるのですね&lt;br&gt;またのお越しをお待ちしております&lt;w&gt;10&lt;/w&gt;", [["町の広場へ行く",]],]
        , ["町を出る", "まだ装備が整っていない&lt;w&gt;10&lt;/w&gt;", [["町の広場",]],]];

    static async main() {
        await サンプル.使用する画像を読み込む();
        サンプル.ループ処理を作成する();
        サンプル.メッセージウィンドウを作成する();
        サンプル.コマンドウィンドウを作成する();
        サンプル.レイヤーを作成する();
        サンプル.場面情報管理を作成する();
        場面遷移.開始する();
    }

    static async 使用する画像を読み込む() {
        const 画像情報リスト = [
            { id: '町', src: 'img/bg02.jpg' },
            { id: '宿屋', src: 'img/bg03.jpg' },
            { id: 'プレイヤー', src: 'img/chara01.png' },
            { id: '受付', src: 'img/chara03.png' }
        ];
        場面遷移.画像管理 = new 画像管理クラス();
        await 場面遷移.画像管理.画像を読み込む(画像情報リスト);
    }

    static ループ処理を作成する() {
        ループ.初期化する();
        ループ.開始する();
    }

    static メッセージウィンドウを作成する() {
        場面遷移.メッセージウィンドウ = new メッセージウィンドウクラス(".スクリーン", ".メッセージウィンドウ");
        Data.オブジェクト管理["サンプル"] = サンプル;
    }

    static コマンドウィンドウを作成する() {
        場面遷移.コマンドウィンドウ = new コマンドウィンドウクラス(".スクリーン", ".コマンドウィンドウ");
    }

    static レイヤーを作成する() {
        場面遷移.レイヤー管理["レイヤー1"] = new レイヤークラス('canvas.レイヤー1'); // 背景用のレイヤ
        場面遷移.レイヤー管理.レイヤー1.描画処理をループ処理に追加する();
        場面遷移.レイヤー管理["レイヤー2"] = new レイヤークラス('canvas.レイヤー2'); // 前景用のレイヤ
        場面遷移.レイヤー管理.レイヤー2.描画処理をループ処理に追加する();
    }

    static 場面情報管理を作成する() {
        サンプル.遷移データリスト.forEach(x =&gt; 場面遷移.場面情報管理[x[0]] = new 場面情報クラス(x));
        場面遷移.場面情報 = 場面遷移.場面情報管理['スタート'];
    }
}

addEventListener('load', サンプル.main);
</code></pre>
<h3 class="heading-23">1. 必要なクラスのインポート</h3>
<p>最初に、import 文で外部ファイルに定義されたクラスを読み込んでいます。各クラスの役割は以下の通りです：</p>
<ul class="箇条書き1">
<li><span class="bold">画像管理クラス：</span>使用する画像を読み込み、管理する。</li>
<li><span class="bold">レイヤークラス：</span>背景やキャラクターなどの表示エリア（レイヤー）を作成する。</li>
<li><span class="bold">ループクラス：</span>処理を繰り返すための仕組み（主にアニメーション）。</li>
<li><span class="bold">メッセージウィンドウクラス：</span>メッセージを表示するウィンドウを制御。</li>
<li><span class="bold">コマンドウィンドウクラス：</span>選択肢（コマンド）を表示するウィンドウ。</li>
<li><span class="bold">場面情報クラス：</span>各場面のデータ（テキストや画像など）を管理。</li>
<li><span class="bold">場面遷移：</span>現在の場面を変更してストーリーを進める。</li>
</ul>
<h3 class="heading-23">2. サンプルクラスの役割</h3>
<p>サンプルクラスは、このプログラムのセットアップと管理を行います。</p>
<p><span class="bold">重要な静的プロパティ：</span></p>
<ul class="箇条書き1">
<li><span class="bold">遷移データリスト：</span>各場面の情報（テキスト、画像、選択肢）を定義した配列です。
<ul class="箇条書き2">
<li>例えば、"町の広場へ行く" という選択肢を選んだときのシーンが定義されています</li>
</ul>
</li>
</ul>
<h3 class="heading-23">3. サンプルクラスのメソッド</h3>
<h4 class="heading-33"><span>1. main メソッド</span></h4>
<p>プログラムの全体的な流れを準備する主なメソッドです。以下の処理を行います。</p>
<ul class="箇条書き1">
<li>画像の準備（使用する画像を読み込む）。</li>
<li>レイヤーやウィンドウの作成。</li>
<li>場面遷移.開始する を呼び出してプログラムを開始。</li>
</ul>
<h4 class="heading-33"><span>2. 使用する画像を読み込む メソッド</span></h4>
<p>必要な画像（背景やキャラクター）を読み込む処理。</p>
<pre class="code"><code>const 画像情報リスト = [
    { id: '町', src: 'img/bg02.jpg' },
    { id: '宿屋', src: 'img/bg03.jpg' },
    { id: 'プレイヤー', src: 'img/chara01.png' },
    { id: '受付', src: 'img/chara03.png' }
];
</code></pre>
<p>このように、画像の識別IDとファイルパスを指定して管理します</p>
<h4 class="heading-33"><span>3. ループ処理を作成する メソッド</span></h4>
<p>プログラム全体で利用する「繰り返し処理」を初期化し、開始します。</p>
<h4 class="heading-33"><span>4. メッセージウィンドウを作成する メソッド</span></h4>
<p>プレイヤーにメッセージを表示するためのウィンドウを用意します。</p>
<h4 class="heading-33"><span>5. コマンドウィンドウを作成する メソッド</span></h4>
<p>プレイヤーが選択肢を選べるウィンドウを作成します。</p>
<h4 class="heading-33"><span>6. レイヤーを作成する メソッド</span></h4>
<p>描画を行うための「レイヤー」を作成。画面の背景やキャラクターの表示を管理します。</p>
<h4 class="heading-33"><span>7. 場面情報管理を作成する メソッド</span></h4>
<p>遷移データリスト をもとに、各場面を管理するオブジェクトを作成します。</p>
<h3 class="heading-23">4. 各場面のデータ構造（遷移データリスト）</h3>
<p>遷移データリスト には各場面の情報が含まれています。</p>
<pre class="code"><code>["町の広場へ行く", "プレイヤーは町の広場に来た&lt;w&gt;10&lt;/w&gt;", [["町の広場",]], [["背景01", "レイヤー1", "町", 0, 0, 640, 640, "フェードインする", 1, ,]]]
</code></pre>
<p>これは、「町の広場へ行く」という選択肢を選んだときに表示する情報を表します。</p>
<ul class="箇条書き1">
<li><span class="bold">メッセージ：</span>プレイヤーは町の広場に来た。</li>
<li><span class="bold">選択肢情報：</span>次に選べる選択肢。</li>
<li><span class="bold">画像情報：</span>背景やキャラクターの画像をどのように表示するか（例えば「フェードイン」）。</li>
</ul>
<h3 class="heading-23">5. プログラムの開始</h3>
<p>プログラムは addEventListener('load', サンプル.main) でスタート。</p>
<ul class="箇条書き1">
<li>ページが読み込まれると、main が実行され、セットアップが行われます。</li>
</ul>
<!--shinobi1-->
<script type="text/javascript" src="//xa.shinobi.jp/ufo/191907708"></script>
<noscript><a href="//xa.shinobi.jp/bin/gg?191907708" target="_blank"><img src="//xa.shinobi.jp/bin/ll?191907708" border="0"></a><br><span style="font-size:9px"><img style="margin:0;vertical-align:text-bottom;" src="//img.shinobi.jp/tadaima/fj.gif" width="19" height="11"> </span></noscript><!--shinobi2--></div>]]></content:encoded>
    <dc:subject>JavaScript紹介</dc:subject>
    <dc:date>2025-04-07T00:21:30+09:00</dc:date>
    <dc:creator>No Name Ninja</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>No Name Ninja</dc:rights>
  </item>
  <item rdf:about="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95">
    <link>https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95</link>
    <title>選択肢を表示する方法</title>
    <description>
選択肢を表示する方法を記します。
以下の例では、選択肢をクリックすると該当するメッセージを表示します。

ファイル構成
ファイルとフォルダーを以下のような構成します。
※前回と同じファイル名でも内容が変わっている場合があります。
※背景と人物の画像はBing Image Creatorで生成してい...</description>
    <content:encoded><![CDATA[<div class="本文">
<p>選択肢を表示する方法を記します。<br />
以下の例では、選択肢をクリックすると該当するメッセージを表示します。</p>
<div class="iframe-container"><iframe width="670" height="930" style="border: 0;" src="https://cf033538.cloudfree.jp/Game/sample06/index.html"></iframe></div>
<h2 class="heading-018">ファイル構成</h2>
<p>ファイルとフォルダーを以下のような構成します。<br />
※前回と同じファイル名でも内容が変わっている場合があります。<br />
※背景と人物の画像はBing Image Creatorで生成しています（AI生成）。</p>
<div class="ファイル構成">
<ul class="list-13">
<li><span>sample05</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample06/index.html" target="_blank">index.html</a></li>
<li><span>js</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample06/js/sample.js" target="_blank">sample.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample06/js/messageWindow.js" target="_blank">messageWindow.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample06/js/data.js" target="_blank">data.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample06/js/com.js" target="_blank">com.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample06/js/imageManager.js" target="_blank">imageManager.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample06/js/sprite.js" target="_blank">sprite.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample06/js/layer.js" target="_blank">layer.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample06/js/loop.js" target="_blank">loop.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample06/js/commandWindow.js" target="_blank">commandWindow.js</a></li>
</ul>
</li>
<li><span>css</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample06/css/sample.css" target="_blank">sample.css</a></li>
</ul>
</li>
<li><span>img</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample06/img/bg02.jpg" target="_blank">bg02.jpg　※背景画像（1024x1024px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample06/img/chara01.png" target="_blank">chara01.png　※人物画像（1024x1024px）</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<h2 class="heading-018">index.html　-　HTML</h2>
<pre class="code"><code>&lt;!DOCTYPE html&gt;
&lt;html lang="ja"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=660,user-scalable=no,shrink-to-fit=yes"&gt;
    &lt;title&gt;選択肢を表示する方法&lt;/title&gt;
    &lt;link href="css/sample.css" rel="stylesheet" /&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;script type="module" src="js/sample.js"&gt;&lt;/script&gt;

    &lt;aside class="画面更新情報"&gt;
        &lt;p&gt;
            リフレッシュレート：&lt;span class="リフレッシュレート"&gt;0&lt;/span&gt;Hz
            ／フレームレート：&lt;span class="フレームレート"&gt;0&lt;/span&gt;fps
        &lt;/p&gt;
    &lt;/aside&gt;
    &lt;main class="スクリーン"&gt;
        &lt;canvas class="レイヤー1" width="640" height="640"&gt;&lt;/canvas&gt;
        &lt;canvas class="レイヤー2" width="640" height="640"&gt;&lt;/canvas&gt;
        &lt;article class="メッセージウィンドウ 消去 透明化"&gt;
            &lt;p class="メッセージエリア"&gt;
                &lt;span class="メッセージ"&gt;&lt;/span&gt;
                &lt;span class="カーソル 点滅 不可視化"&gt;■&lt;/span&gt;
            &lt;/p&gt;
        &lt;/article&gt;
        &lt;article class="コマンドウィンドウ 消去"&gt;
            &lt;button class="通常ボタン" value="0"&gt;
                &lt;span&gt;&lt;/span&gt;
            &lt;/button&gt;
            &lt;button class="通常ボタン" value="1"&gt;
                &lt;span&gt;&lt;/span&gt;
            &lt;/button&gt;
            &lt;button class="通常ボタン" value="2"&gt;
                &lt;span&gt;&lt;/span&gt;
            &lt;/button&gt;
            &lt;button class="通常ボタン" value="3"&gt;
                &lt;span&gt;&lt;/span&gt;
            &lt;/button&gt;
            &lt;button class="通常ボタン" value="4"&gt;
                &lt;span&gt;&lt;/span&gt;
            &lt;/button&gt;
            &lt;button class="通常ボタン" value="5"&gt;
                &lt;span&gt;&lt;/span&gt;
            &lt;/button&gt;
            &lt;button class="通常ボタン" value="6"&gt;
                &lt;span&gt;&lt;/span&gt;
            &lt;/button&gt;
            &lt;button class="通常ボタン" value="7"&gt;
                &lt;span&gt;&lt;/span&gt;
            &lt;/button&gt;
            &lt;button class="通常ボタン" value="8"&gt;
                &lt;span&gt;&lt;/span&gt;
            &lt;/button&gt;
            &lt;button class="通常ボタン" value="9"&gt;
                &lt;span&gt;&lt;/span&gt;
            &lt;/button&gt;
        &lt;/article&gt;
    &lt;/main&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<h3 class="heading-23">1. 全体の構造</h3>
<p>このHTMLは前回の「メッセージウィンドウを表示する方法」に「コマンドウィンドウ」クラスの要素を追加しており、それ以外はほぼ同じです。</p>
<h3 class="heading-23">2. コマンドウィンドウ</h3>
<pre class="code"><code>&lt;article class="コマンドウィンドウ 消去"&gt;
    &lt;button class="通常ボタン" value="0"&gt;&lt;span&gt;&lt;/span&gt;&lt;/button&gt;
    &lt;!-- 以下省略 --&gt;
&lt;/article&gt;
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">役割：</span>選択肢を表示するウィンドウ。</li>
<li><span class="bold">クラス設定：</span>
<ul class="箇条書き2">
<li><span class="bold">コマンドウィンドウ：</span>ウィンドウのスタイルを定義。</li>
<li><span class="bold">消去：</span>初期状態では非表示（CSSでdisplay: none）。</li>
</ul>
</li>
<li><span class="bold">動的要素：</span>
<ul class="箇条書き2">
<li><span class="bold">&lt;button&gt;：</span>各ボタンが選択肢を表し、value 属性でボタンの番号を指定。</li>
<li><span class="bold">&lt;span&gt;：</span>ボタン上に表示するテキストを動的に更新。</li>
</ul>
</li>
</ul>
<h2 class="heading-018">sample.css　-　CSS</h2>
<pre class="code"><code>:root {
    --通常文字サイズ: 26px;
    --通常文字行高さ: 38px;
    --小文字サイズ: 18px;
    --小文字行高さ: 24px;
    --黒い影: 1px 1px 1px #000, -1px -1px 1px #000, -1px 1px 1px #000, 1px -1px 1px #000, 2px 0px 1px #000, -2px -0px 1px #000, 0px 2px 1px #000, 0px -2px 1px #000;
    --トランジションスピード: 0.8s;
}

body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
    background-color: #f4f4f4;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
    overscroll-behavior-y: none;
}

.画面更新情報 {
    text-align: center;
    font-size: var(--小文字サイズ);
    line-height: var(--小文字行高さ);
    color: #333;
}

.スクリーン {
    width: 640px;
    height: 840px;
    margin: 20px auto;
    border: 2px solid #ccc;
    position: relative;
    background-color: black;
}

canvas {
    position: absolute;
    top: 200px;
}

.不可視化 {
    visibility: hidden;
}

.透明化 {
    opacity: 0;
}

.消去 {
    display: none;
}

.表示 {
    display: block;
}

@keyframes 点滅 {
    0% {
        opacity: 1;
    }

    50% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

.点滅 {
    animation: 点滅 1s ease-out infinite;
}

.メッセージウィンドウ {
    position: absolute;
    background-color: rgba(0, 0, 0, 0.7);
    border: solid 3px white;
    padding: 12px 17px;
    margin: 5px;
    transition: opacity var(--トランジションスピード) ease-out;
}

    .メッセージウィンドウ .メッセージエリア {
        padding: 3px;
        margin: 0px;
        font-size: var(--通常文字サイズ);
        line-height: var(--通常文字行高さ);
        color: white;
        text-shadow: var(--黒い影);
        width: 584px;
        height: 154px;
        overflow: scroll;
        -ms-overflow-style: none;
        scrollbar-width: none;
    }

        .メッセージウィンドウ .メッセージエリア::-webkit-scrollbar {
            display: none;
        }

    .メッセージウィンドウ .カーソル {
        transition: opacity var(--トランジションスピード) ease-in;
        font-size: var(--通常文字サイズ);
        display: inline-block;
        transform: translateY(-2px);
    }

.通常ボタン {
    font-size: var(--小文字サイズ);
    line-height: var(--小文字行高さ);
    color: white;
    text-shadow: var(--黒い影);
    background-color: rgba(250, 250, 250, 0.1);
    background-image: linear-gradient(to top left, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.4) 30%, rgba(255, 255, 255, 0.3));
    box-shadow: inset 2px 2px 3px rgba(255, 255, 255, 0.6), inset -2px -2px 3px rgba(0, 0, 0, 0.6);
    border: solid 1px black;
    border-radius: 5px;
    padding: 10px 20px;
    margin:1px 0;
}

    .通常ボタン:hover {
        background-color: rgb(255, 255, 45);
    }

    .通常ボタン:active {
        box-shadow: inset -2px -2px 3px rgba(255, 255, 255, 0.6), inset 2px 2px 3px rgba(0, 0, 0, 0.6);
    }

    .通常ボタン span {
        display: flex;
        align-items: center;
    }

.コマンドウィンドウ {
    position: absolute;
    padding: 12px 17px;
    margin: 5px;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -35%);
    text-align: center;
    max-height: 600px;
    overflow: scroll;
    -ms-overflow-style: none;
    scrollbar-width: none;
}

    .コマンドウィンドウ::-webkit-scrollbar {
        display: none;
    }

    .コマンドウィンドウ .通常ボタン span {
        justify-content: center;
        white-space: nowrap;
        min-width:250px;
    }
</code></pre>
<h3 class="heading-23">1. 全体の構造</h3>
<p>このCSSは前回の「メッセージウィンドウを表示する方法」に「コマンドウィンドウ」クラスと「通常ボタン」クラスを追加しており、それ以外はほぼ同じです。</p>
<h3 class="heading-23">2. コマンドウィンドウ</h3>
<pre class="code"><code>.コマンドウィンドウ {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -35%);
    text-align: center;
    ...
}
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">中央配置：</span>top: 50%; left: 50%; transform: translate(-50%, -35%); によって画面中央に配置。</li>
<li><span class="bold">最大高さ：</span>600px以内に設定し、オーバーフロー時はスクロール。</li>
</ul>
<h3 class="heading-23">2. ボタン（.通常ボタン）</h3>
<pre class="code"><code>.通常ボタン {
    font-size: var(--小文字サイズ);
    background-color: rgba(250, 250, 250, 0.1);
    border-radius: 5px;
    ...
}
</code></pre>
<ul class="箇条書き1">
<li>ボタンデザイン。
<ul class="箇条書き2">
<li><span class="bold">背景：</span>半透明の白と斜めのグラデーション。</li>
<li><span class="bold">角丸：</span>5pxの角を丸く。</li>
<li><span class="bold">ホバー効果：</span>ボタンにマウスを載せると黄色に変化。</li>
</ul>
</li>
</ul>
<h2 class="heading-018">commandWindow.js　-　コマンドウィンドウクラス</h2>
<p>このクラスの目的：</p>
<ul class="箇条書き1">
<li>コマンド（ボタンを介して実行される選択肢）を表示するウィンドウを作成。</li>
<li>選択肢をクリックすると適切な処理が実行される仕組みを提供。</li>
</ul>
<pre class="code"><code>export class コマンドウィンドウクラス {
    constructor(スクリーンセレクタ, コマンドウィンドウセレクタ) {
        this.スクリーン要素 = document.querySelector(スクリーンセレクタ);
        if (!this.スクリーン要素) throw new Error(`スクリーンセレクタ:'${スクリーンセレクタ}'が見つかりません`);

        this.コマンドウィンドウ要素 = this.スクリーン要素.querySelector(コマンドウィンドウセレクタ);
        if (!this.コマンドウィンドウ要素) throw new Error(`コマンドウィンドウセレクタ:'${コマンドウィンドウセレクタ}'が見つかりません`);

        this.ボタン要素リスト = this.コマンドウィンドウ要素.querySelectorAll('button');
        if (!this.ボタン要素リスト.length) throw new Error(`'${コマンドウィンドウセレクタ}'にbuttonタグが見つかりません`);

        this.名称要素リスト = this.コマンドウィンドウ要素.querySelectorAll('span');
        if (!this.名称要素リスト.length) throw new Error(`'${コマンドウィンドウセレクタ}'にspanタグが見つかりません`);

        this.ボタン要素リスト.forEach(x =&gt; x.onclick = this.ボタンをクリックする.bind(this));
    }

    async 表示する(コマンドリスト) {
        for (let i = 0; i &lt; this.名称要素リスト.length; i++) {
            if (コマンドリスト.length &lt;= i) {
                this.ボタン要素リスト[i].classList.toggle('消去', true);
                continue;
            }
            this.ボタン要素リスト[i].classList.toggle('消去', false);
            this.名称要素リスト[i].innerHTML = コマンドリスト[i].名称;
        }
        this.コマンドリスト = コマンドリスト;
        this.コマンドウィンドウ要素.classList.toggle('消去', false);
        this.以前のクリックハンドラ = this.スクリーン要素.onclick;
        this.スクリーン要素.onclick = this.ウィンドウ外をクリックする.bind(this);
        return new Promise(resolve =&gt; this.resolve = resolve);
    }

    async ウィンドウ外をクリックする() {
        this.コマンドウィンドウ要素.classList.toggle('消去');
    }

    async ボタンをクリックする(event) {
        this.コマンドウィンドウ要素.classList.toggle('消去', true);
        event.stopPropagation();
        this.スクリーン要素.onclick = this.以前のクリックハンドラ;
        this.resolve(this.コマンドリスト[Number(event.currentTarget.value)].id);
    }
}
</code></pre>
<h3 class="heading-23">1. constructor() コンストラクタ</h3>
<p>この部分は、クラスのインスタンスが作られるときに最初に呼び出されます。ウィンドウやボタンなどのHTML要素を取得し、操作できるようにします。</p>
<ul class="箇条書き1">
<li><span class="bold">スクリーンセレクタ：</span>コマンドウィンドウが配置される「画面」を示すセレクタ（CSSセレクタの指定）。</li>
<li><span class="bold">コマンドウィンドウセレクタ：</span>コマンドを表示する「ウィンドウ」のセレクタ。</li>
</ul>
<p><span class="bold">処理の流れ：</span></p>
<ol class="箇条書き1">
<li>this.スクリーン要素 に「画面」要素を取得。</li>
<li>this.コマンドウィンドウ要素 に「コマンドウィンドウ」を取得。</li>
<li>ウィンドウ内のボタンタグ（&lt;button&gt;）や名前を表示するスパンタグ（&lt;span&gt;）をリストとして取得。</li>
<li>各ボタンにクリックイベントを設定しておく（「this.ボタンをクリックする」を登録）。</li>
</ol>
<p><span class="bold">ポイント：</span>各ステップで、要素が見つからない場合はエラーとして処理を終了します（例：ボタンがない場合）</p>
<h3 class="heading-23">2. 表示する(コマンドリスト) メソッド</h3>
<p>このメソッドは、コマンドウィンドウにコマンドを表示し、選択肢をユーザーに提示します。</p>
<p><span class="bold">処理の流れ：</span></p>
<ol class="箇条書き1">
<li><span class="bold">コマンドリストを反映：</span>
<ul class="箇条書き2">
<li>入力されたコマンドリストに基づいて、ボタンと名前を表示。</li>
<li>リストの長さが不足している場合、そのボタンを隠す。</li>
</ul>
</li>
<li><span class="bold">ウィンドウを表示：</span>
<ul class="箇条書き2">
<li>コマンドウィンドウのCSSクラス消去（非表示状態）を削除。</li>
</ul>
</li>
<li><span class="bold">クリックハンドラの変更：</span>
<ul class="箇条書き2">
<li>ウィンドウ外（背景など）をクリックすると閉じる処理を登録。</li>
</ul>
</li>
<li><span class="bold">Promise：</span>
<ul class="箇条書き2">
<li>選択が完了したら、その結果（id）を返す仕組みになっています。</li>
</ul>
</li>
</ol>
<p><span class="bold">ポイント：</span>Promise は、非同期処理が完了するまで待つ仕組みを提供します</p>
<h3 class="heading-23">3. ウィンドウ外をクリックする() メソッド</h3>
<p>ウィンドウ外の画面部分がクリックされたとき、コマンドウィンドウを非表示にします。 （例：ユーザーが選択せずに閉じたいときの処理）</p>
<h3 class="heading-23">4. ボタンをクリックする(event) メソッド</h3>
<p>ボタンがクリックされたときの処理を担当します。</p>
<p><span class="bold">処理の流れ：</span></p>
<ol class="箇条書き1">
<li>ウィンドウを非表示に変更。</li>
<li>イベントを伝播しないようにevent.stopPropagation()を呼び出し。</li>
<li>前のクリックハンドラ（画面のクリックイベントなど）を復元。</li>
<li>選択されたボタンの値（id）をPromiseで返す。</li>
</ol>
<h2 class="heading-018">sample.js　-　サンプルクラス</h2>
<pre class="code"><code>import { 画像管理クラス } from './imageManager.js'; // クラスをインポート
import { レイヤークラス } from './layer.js'; // クラスをインポート
import { ループ } from './loop.js'; // クラスをインポート
import { メッセージウィンドウクラス } from './messageWindow.js'; // クラスをインポート
import { コマンドウィンドウクラス } from './commandWindow.js'; // クラスをインポート
import { Data } from './data.js'; // クラスをインポート
import { スプライトクラス } from './sprite.js'; // クラスをインポート

export class サンプル {
    static async main() {
        await サンプル.使用する画像を読み込む();
        サンプル.ループ処理を作成する();
        サンプル.メッセージウィンドウを作成する();
        サンプル.コマンドウィンドウを作成する();
        サンプル.レイヤーを作成する();
        サンプル.読み込んだ画像でスプライトを作成する();
        サンプル.作成した物を使って画面に表示する();
    }

    static async 使用する画像を読み込む() {
        const 画像情報リスト = [
            { id: '町', src: 'img/bg02.jpg' },
            { id: 'プレイヤー', src: 'img/chara01.png' }
        ];
        サンプル.画像管理 = new 画像管理クラス();
        await サンプル.画像管理.画像を読み込む(画像情報リスト);
    }

    static ループ処理を作成する() {
        ループ.初期化する();
        ループ.開始する();
    }

    static メッセージウィンドウを作成する() {
        サンプル.メッセージウィンドウ = new メッセージウィンドウクラス(".スクリーン", ".メッセージウィンドウ");
        Data.オブジェクト管理["サンプル"] = サンプル;
    }

    static コマンドウィンドウを作成する() {
        サンプル.コマンドウィンドウ = new コマンドウィンドウクラス(".スクリーン", ".コマンドウィンドウ");
    }

    static レイヤーを作成する() {
        サンプル.レイヤー1 = new レイヤークラス('canvas.レイヤー1'); // 背景用のレイヤ
        サンプル.レイヤー2 = new レイヤークラス('canvas.レイヤー2'); // 前景用のレイヤ
        サンプル.レイヤー2.描画処理をループ処理に追加する();
    }

    static 読み込んだ画像でスプライトを作成する() {
        サンプル.背景01 = new スプライトクラス(サンプル.レイヤー1, サンプル.画像管理.取得する('町'), 0, 0, 640, 640);
        サンプル.人物01 = new スプライトクラス(サンプル.レイヤー2, サンプル.画像管理.取得する('プレイヤー'), 0, 0, 640, 640);
        サンプル.人物01正位置 = { x: サンプル.人物01.x, y: サンプル.人物01.y };
        サンプル.人物01.座標を設定する(640, 0, 1280, 640); //初期表示位置を設定する
    }

    static async 作成した物を使って画面に表示する() {
        サンプル.背景01.描画する();
        await サンプル.人物01.移動してフェードインする(-10, 0, サンプル.人物01正位置.x, 0, 1);
        ループ.処理を削除する(サンプル.レイヤー2);
        await サンプル.メッセージウィンドウ.表示する();
        await サンプル.メッセージウィンドウ.メッセージを表示する("プレイヤーは町の広場に来た&lt;w&gt;10&lt;/w&gt;");

        let id = 0;
        while (1) {
            await サンプル.メッセージウィンドウ.メッセージを表示する("どうする？");
            id = await サンプル.コマンドウィンドウ.表示する([
                { id: 0, 名称: "話す" },
                { id: 1, 名称: "持物を見る" },
                { id: 2, 名称: "移動する" }
            ]);
            if (id == 0) {
                await サンプル.メッセージウィンドウ.メッセージを表示する("話が聞けそうな人は誰もいない&lt;w&gt;10&lt;/w&gt;");
                continue;
            } else if (id==1) {
                await サンプル.メッセージウィンドウ.メッセージを表示する("今のところ、何も持っていない&lt;w&gt;10&lt;/w&gt;");
                continue;
            }

            await サンプル.メッセージウィンドウ.メッセージを表示する("どこへ行く？");
            id = await サンプル.コマンドウィンドウ.表示する([
                { id: 0, 名称: "やめる" },
                { id: 1, 名称: "武器屋へ行く" },
                { id: 2, 名称: "防具屋へ行く" },
                { id: 3, 名称: "道具屋へ行く" },
                { id: 4, 名称: "宿屋へ行く" },
                { id: 5, 名称: "町を出る" }
            ]);
            if (id == 0) continue;
            else if (id == 1) {
                await サンプル.メッセージウィンドウ.メッセージを表示する("武器屋は開いていないようだ&lt;w&gt;10&lt;/w&gt;");
                continue;
            } else if (id == 2) {
                await サンプル.メッセージウィンドウ.メッセージを表示する("防具屋は開いていないようだ&lt;w&gt;10&lt;/w&gt;");
                continue;
            } else if (id == 3) {
                await サンプル.メッセージウィンドウ.メッセージを表示する("道具屋は開いていないようだ&lt;w&gt;10&lt;/w&gt;");
                continue;
            } else if (id == 4) {
                await サンプル.メッセージウィンドウ.メッセージを表示する("宿屋は開いていないようだ&lt;w&gt;10&lt;/w&gt;");
                continue;
            }
            await サンプル.メッセージウィンドウ.メッセージを表示する("まだ装備が整っていない&lt;w&gt;10&lt;/w&gt;");
        }
    }
}

addEventListener('load', サンプル.main);
</code></pre>
<h3 class="heading-23">1. プログラムの全体像</h3>
<p>このコードの目的は次の通り：</p>
<ul class="箇条書き1">
<li>必要な画像を読み込み、それを画面に表示する。</li>
<li>ユーザーが選択肢（コマンドウィンドウ）を選んで進行できる仕組みを提供する。</li>
<li>メッセージウィンドウを使って物語や状況を表示する。</li>
</ul>
<h3 class="heading-23">2. 必要なクラスのインポート</h3>
<ul class="箇条書き1">
<li>この部分で外部ファイル（モジュール）からクラスを読み込みます。
<pre class="code"><code>import { 画像管理クラス } from './imageManager.js';
import { レイヤークラス } from './layer.js';
</code></pre>
読み込まれたクラスは、このプログラムの中で使用されます。</li>
</ul>
<h3 class="heading-23">3. メイン処理 (main メソッド)</h3>
<ul class="箇条書き1">
<li>このプログラムのスタート地点です。</li>
<li>次の手順でゲームの準備を整えます：<ol class="箇条書き2">
<li>必要な画像をロードする。</li>
<li>ゲームループ（繰り返し処理）を開始する。</li>
<li>メッセージウィンドウやコマンドウィンドウを作成する。</li>
<li>読み込んだ画像を使ってスプライト（キャラクターや背景）を画面に描画する。</li>
<li>描画された画面に基づいてメッセージと選択肢を表示する。</li>
</ol></li>
</ul>
<h3 class="heading-23">4. 画像読み込み (使用する画像を読み込む メソッド)</h3>
<ul class="箇条書き1">
<li>使用する画像のリスト（例：「町」や「プレイヤー」）を準備し、それを読み込みます。</li>
<li>読み込まれた画像は 画像管理クラス に保存され、後から使うことができます。</li>
</ul>
<h3 class="heading-23">5. レイヤーの作成 (レイヤーを作成する メソッド)</h3>
<ul class="箇条書き1">
<li>レイヤーはゲーム画面の「背景」と「前景」を分けるために使います。</li>
<li>たとえば：
<ul class="箇条書き2">
<li>背景（レイヤー1）は町の画像を表示。</li>
<li>前景（レイヤー2）はキャラクターや移動する物を表示。</li>
</ul>
</li>
</ul>
<h3 class="heading-23">6. スプライトの作成 (読み込んだ画像でスプライトを作成する メソッド)</h3>
<ul class="箇条書き1">
<li>スプライトは画面に表示される画像（例：背景やキャラクター）のこと。</li>
<li>このメソッドでは以下を設定します：
<ul class="箇条書き2">
<li>背景スプライト：町の画像を表示。</li>
<li>キャラクタースプライト：「プレイヤー」の初期位置を設定。</li>
</ul>
</li>
</ul>
<h3 class="heading-23">7. メッセージウィンドウの作成</h3>
<ul class="箇条書き1">
<li>メッセージを表示するためのウィンドウ（吹き出しのようなもの）を作ります。</li>
<li>たとえば「プレイヤーは町の広場に来た」という物語を表示します。</li>
</ul>
<h3 class="heading-23">8. コマンドウィンドウの作成</h3>
<ul class="箇条書き1">
<li>画面に「話す」「持物を見る」「移動する」などの選択肢を表示するウィンドウを用意します。</li>
<li>プレイヤーが選択肢をクリックすると、それに対応する処理が実行されます。</li>
</ul>
<h3 class="heading-23">9. プログラムの流れ</h3>
<ol class="箇条書き1">
<li><span class="bold">背景とキャラクターを表示：</span>
<ul class="箇条書き2">
<li>画面に背景とキャラクター画像を描画します。</li>
<li>キャラクターはフェードイン（徐々に表示）します。</li>
</ul>
</li>
<li><span class="bold">メッセージを表示：</span>
<ul class="箇条書き2">
<li>メッセージウィンドウに「プレイヤーは町の広場に来た」などの文章を表示します。</li>
</ul>
</li>
<li><span class="bold">コマンドの選択：</span>
<ul class="箇条書き2">
<li>プレイヤーが選択肢をクリックし、次の行動を決めます。</li>
<li>たとえば、「話す」を選ぶと「話が聞けそうな人は誰もいない」と表示されます。</li>
</ul>
</li>
<li><span class="bold">繰り返し処理：</span>
<ul class="箇条書き2">
<li>どの選択肢を選んでも、また次の選択肢が表示されます。</li>
</ul>
</li>
</ol><!--shinobi1-->
<script type="text/javascript" src="//xa.shinobi.jp/ufo/191907707"></script>
<noscript><a href="//xa.shinobi.jp/bin/gg?191907707" target="_blank"><img src="//xa.shinobi.jp/bin/ll?191907707" border="0"></a><br><span style="font-size:9px"><img style="margin:0;vertical-align:text-bottom;" src="//img.shinobi.jp/tadaima/fj.gif" width="19" height="11"> </span></noscript><!--shinobi2--></div>]]></content:encoded>
    <dc:subject>JavaScript紹介</dc:subject>
    <dc:date>2025-04-06T14:28:06+09:00</dc:date>
    <dc:creator>No Name Ninja</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>No Name Ninja</dc:rights>
  </item>
  <item rdf:about="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95">
    <link>https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95</link>
    <title>メッセージウィンドウを表示する方法</title>
    <description>
以下のようなメッセージウィンドウを表示する方法を記します。

一定時間ごとに1文字づつ表示します。
メッセージを表示中に画面内をクリックすると一括で表示します。
メッセージ内に以下のような制御を入れることが出来ます。
改行：メッセージを途中で改行します。
クリア：メッセージを好きな箇所でクリアしま...</description>
    <content:encoded><![CDATA[<div class="本文">
<p>以下のようなメッセージウィンドウを表示する方法を記します。</p>
<ul class="箇条書き1">
<li>一定時間ごとに1文字づつ表示します。</li>
<li>メッセージを表示中に画面内をクリックすると一括で表示します。</li>
<li>メッセージ内に以下のような制御を入れることが出来ます。<ol class="箇条書き2">
<li><span class="bold">改行：</span>メッセージを途中で改行します。</li>
<li><span class="bold">クリア：</span>メッセージを好きな箇所でクリアします。</li>
<li><span class="bold">クリック待ち：</span>メッセージ表示をクリックされるか指定した時間まで停止します。</li>
<li><span class="bold">変数：</span>変数を埋め込むことで、メッセージを使いまわすことができます。サンプルでは時刻の表示に変数を使っています。</li>
</ol></li>
</ul>
<div class="iframe-container"><iframe width="670" height="730" style="border: 0;" src="https://cf033538.cloudfree.jp/Game/sample05/index.html"></iframe></div>
<h2 class="heading-018">ファイル構成</h2>
<p>ファイルとそれを入れるフォルダーを以下のような構成します。<br />
※前回と同じファイル名でも内容が変わっている場合があります。<br />
※背景と人物の画像はBing Image Creatorで生成しています（AI生成）。</p>
<div class="ファイル構成">
<ul class="list-13">
<li><span>sample05</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample05/index.html" target="_blank">index.html</a></li>
<li><span>js</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample05/js/sample.js" target="_blank">sample.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample05/js/messageWindow.js" target="_blank">messageWindow.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample05/js/data.js" target="_blank">data.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample05/js/com.js" target="_blank">com.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample05/js/imageManager.js" target="_blank">imageManager.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample05/js/sprite.js" target="_blank">sprite.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample05/js/layer.js" target="_blank">layer.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample05/js/loop.js" target="_blank">loop.js</a></li>
</ul>
</li>
<li><span>css</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample05/css/sample.css" target="_blank">sample.css</a></li>
</ul>
</li>
<li><span>img</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample05/img/bg02.jpg" target="_blank">bg02.jpg　※背景画像（1024x1024px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample05/img/chara01.png" target="_blank">chara01.png　※人物画像（1024x1024px）</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<h2 class="heading-018">index.html　-　HTML</h2>
<pre class="code"><code>&lt;!DOCTYPE html&gt;
&lt;html lang="ja"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=660,user-scalable=no,shrink-to-fit=yes"&gt;
    &lt;title&gt;メッセージウィンドウを作成する方法&lt;/title&gt;
    &lt;link href="css/sample.css" rel="stylesheet" /&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;script type="module" src="js/sample.js"&gt;&lt;/script&gt;

    &lt;aside class="画面更新情報"&gt;
        &lt;p&gt;
            リフレッシュレート：&lt;span class="リフレッシュレート"&gt;0&lt;/span&gt;Hz
            ／フレームレート：&lt;span class="フレームレート"&gt;0&lt;/span&gt;fps
        &lt;/p&gt;
    &lt;/aside&gt;
    &lt;main class="スクリーン"&gt;
        &lt;canvas class="レイヤー1" width="640" height="640" aria-label="グラフィックコンテンツ"&gt;&lt;/canvas&gt;
        &lt;article class="メッセージウィンドウ 消去 透明化"&gt;
            &lt;p class="メッセージエリア"&gt;
                &lt;span class="メッセージ"&gt;&lt;/span&gt;
                &lt;span class="カーソル 点滅 不可視化"&gt;■&lt;/span&gt;
            &lt;/p&gt;
        &lt;/article&gt;
    &lt;/main&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<h3 class="heading-23">1. &lt;head&gt; セクション</h3>
<pre class="code"><code>&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=660,user-scalable=no,shrink-to-fit=yes"&gt;
    &lt;title&gt;メッセージウィンドウを作成する方法&lt;/title&gt;
    &lt;link href="css/sample.css" rel="stylesheet" /&gt;
&lt;/head&gt;
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">&lt;meta charset="UTF-8"&gt; セクション：</span>日本語を含む多言語を正しく表示するためにUTF-8を使用しています。</li>
<li><span class="bold">&lt;meta name="viewport"&gt; セクション：</span>モバイル端末での表示を最適化するため、幅を660pxに固定し、ユーザーがズームできないよう設定しています。</li>
<li><span class="bold">&lt;title&gt; セクション：</span>ブラウザのタブに表示されるページタイトルです。</li>
<li><span class="bold">&lt;link href="css/sample.css" rel="stylesheet"&gt; セクション：</span>別ファイル（css/sample.css）からスタイル情報を読み込む設定です。</li>
</ul>
<h3 class="heading-23">2. &lt;body&gt; セクション</h3>
<pre class="code"><code>&lt;script type="module" src="js/sample.js"&gt;&lt;/script&gt;
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">type="module"：</span>モジュール化されたJavaScriptファイルを読み込みます。</li>
<li><span class="bold">src="js/sample.js"：</span>読み込む外部JavaScriptファイルを設定しています。このスクリプトにはメッセージウィンドウの動作等が定義されています。</li>
</ul>
<h3 class="heading-23">3. 画面の更新情報</h3>
<pre class="code"><code>&lt;aside class="画面更新情報"&gt;
    &lt;p&gt;
        リフレッシュレート：&lt;span class="リフレッシュレート"&gt;0&lt;/span&gt;Hz
        ／フレームレート：&lt;span class="フレームレート"&gt;0&lt;/span&gt;fps
    &lt;/p&gt;
&lt;/aside&gt;
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">役割：</span>ここでは、画面の更新状況（リフレッシュレートとフレームレート）を表示しています。</li>
<li><span class="bold">クラス名の設定：</span>
<ul>
<li><span class="bold">"画面更新情報"：</span>全体のコンテナのスタイリング（例：中央揃えやフォントサイズなど）に対応。</li>
<li><span class="bold">"リフレッシュレート" や "フレームレート"：</span>動的に数値が書き換えられる部分となります。</li>
</ul>
</li>
</ul>
<h3 class="heading-23">4. スクリーンエリア</h3>
<pre class="code"><code>&lt;main class="スクリーン"&gt;
    &lt;canvas class="レイヤー1" width="640" height="640" aria-label="グラフィックコンテンツ"&gt;&lt;/canvas&gt;
    &lt;article class="メッセージウィンドウ 消去 透明化"&gt;
        &lt;p class="メッセージエリア"&gt;
            &lt;span class="メッセージ"&gt;&lt;/span&gt;
            &lt;span class="カーソル 点滅 不可視化"&gt;■&lt;/span&gt;
        &lt;/p&gt;
    &lt;/article&gt;
&lt;/main&gt;
</code></pre>
<ol class="箇条書き1">
<li><span class="bold">Canvas要素：</span>
<pre class="code"><code>&lt;canvas class="レイヤー1" width="640" height="640" aria-label="グラフィックコンテンツ"&gt;&lt;/canvas&gt;
</code></pre>
<ul class="箇条書き2">
<li><span class="bold">Canvasタグ：</span>描画エリアを提供します。このコードでは画像やスプライトを表示する「レイヤー」として使われます。</li>
<li><span class="bold">属性：</span>
<ul class="箇条書き3">
<li><span class="bold">class="レイヤー1"：</span>CSSやJavaScriptで制御するためのクラス名。</li>
<li><span class="bold">width="640" height="640"：</span>Canvasの横幅と高さを指定。</li>
<li><span class="bold">aria-label="グラフィックコンテンツ"：</span>アクセシビリティのためにコンテンツの説明を付けています。</li>
</ul>
</li>
</ul>
</li>
<li><span class="bold">メッセージウィンドウ：</span>
<pre class="code"><code>&lt;article class="メッセージウィンドウ 消去 透明化"&gt;
    &lt;p class="メッセージエリア"&gt;
        &lt;span class="メッセージ"&gt;&lt;/span&gt;
        &lt;span class="カーソル 点滅 不可視化"&gt;■&lt;/span&gt;
    &lt;/p&gt;
&lt;/article&gt;
</code></pre>
<ul class="箇条書き2">
<li><span class="bold">&lt;article class="メッセージウィンドウ 消去 透明化"&gt;：</span>
<ul class="箇条書き3">
<li><span class="bold">「メッセージウィンドウ」クラス：</span>このクラスは、吹き出しやダイアログのように画面上にメッセージを表示するためのウィンドウのスタイルを定義しています。</li>
<li><span class="bold">「消去」クラス：</span>CSS では display: none; として定義され、初期状態ではウィンドウが存在しているものの画面には表示されません。</li>
<li><span class="bold">「透明化」クラス：</span>CSS では opacity: 0; の設定になっており、見た目を透明にして隠しています。 ※「消去」と「透明化」を組み合わせて、ウィンドウを非表示状態にセットしています。</li>
</ul>
</li>
<li><span class="bold">&lt;p class="メッセージエリア"&gt;：</span>メッセージテキストが表示される領域です。CSS によりスクロールなどの設定がされています。</li>
<li><span class="bold">&lt;span class="メッセージ"&gt;：</span>実際のメッセージテキストを 1 文字ずつ追加して表示していく部分です。</li>
<li><span class="bold">&lt;span class="カーソル 点滅 不可視化"&gt;：</span>
<ul class="箇条書き3">
<li><span class="bold">「カーソル」クラス：</span>メッセージ表示時に、クリック待ちを示すためのアイコン（ここでは■）の表示に使います。</li>
<li><span class="bold">「点滅」クラス：</span>CSS の @keyframes 点滅 や animation 設定を使って、「■」が点滅するアニメーションが適用されます。</li>
<li><span class="bold">「不可視化」クラス：</span>CSS では visibility: hidden; として定義され、初期状態でカーソル自体が見えないようにしています。</li>
</ul>
</li>
</ul>
</li>
</ol>
<h2 class="heading-018">sample.css　-　CSS</h2>
<pre class="code"><code>:root {
    --通常文字サイズ: 26px;
    --通常文字行高さ: 38px;
    --小文字サイズ: 18px;
    --小文字行高さ: 24px;
    --黒い影: 1px 1px 1px #000, -1px -1px 1px #000, -1px 1px 1px #000, 1px -1px 1px #000, 2px 0px 1px #000, -2px -0px 1px #000, 0px 2px 1px #000, 0px -2px 1px #000;
    --トランジションスピード: 0.8s;
}

body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
    background-color: #f4f4f4;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
    overscroll-behavior-y: none;
}

.画面更新情報 {
    text-align: center;
    font-size: var(--小文字サイズ);
    line-height: var(--小文字行高さ);
    color: #333;
}

.スクリーン {
    width: 640px;
    height: 640px;
    margin: 20px auto;
    border: 2px solid #ccc;
    position: relative;
    background-color: black;
}

canvas {
    position: absolute;
}

.不可視化 {
    visibility: hidden;
}

.透明化 {
    opacity: 0;
}

.消去 {
    display: none;
}

.表示 {
    display: block;
}

@keyframes 点滅 {
    0% {
        opacity: 1;
    }

    50% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

.点滅 {
    animation: 点滅 1s ease-out infinite;
}

.メッセージウィンドウ {
    position: absolute;
    background-color: rgba(0, 0, 0, 0.7);
    border: solid 3px white;
    padding: 12px 17px;
    margin: 5px;
    transition: opacity var(--トランジションスピード) ease-out;
}

    .メッセージウィンドウ .メッセージエリア {
        padding: 3px;
        margin: 0px;
        font-size: var(--通常文字サイズ);
        line-height: var(--通常文字行高さ);
        color: white;
        text-shadow: var(--黒い影);
        width: 584px;
        height: 154px;
        overflow: scroll;
        -ms-overflow-style: none;
        scrollbar-width: none;
    }

        .メッセージウィンドウ .メッセージエリア::-webkit-scrollbar {
            display: none;
        }

    .メッセージウィンドウ .カーソル {
        font-size: var(--通常文字サイズ);
        display: inline-block;
        transform: translateY(-2px);
    }
</code></pre>
<h3 class="heading-23">1. 変数（:rootセクター）</h3>
<pre class="code"><code>:root {
    --通常文字サイズ: 26px;
    --通常文字行高さ: 38px;
    --小文字サイズ: 18px;
    --小文字行高さ: 24px;
    --黒い影: 1px 1px 1px #000, -1px -1px 1px #000, -1px 1px 1px #000, 1px -1px 1px #000, 2px 0px 1px #000, -2px -0px 1px #000, 0px 2px 1px #000, 0px -2px 1px #000;
    --トランジションスピード: 0.8s;
}
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">目的：</span>ここでは CSS 変数を定義しています。たとえば、文章の基本サイズや行の高さ、テキストに付ける影、アニメーションの速さなど、後で何度も使う数値を 1か所で管理できるようにしています。</li>
<li><span class="bold">例：</span>
<ul class="箇条書き2">
<li>--通常文字サイズ は 26px に設定されており、通常のテキストサイズとして使用。</li>
<li>--黒い影 は、文字を際立たせるために複数の影を短いオフセットとともに定義しています。</li>
<li>--トランジションスピード はアニメーションや状態変化の際の速度（ここでは 0.8秒）を指定しています。</li>
</ul>
</li>
</ul>
<h3 class="heading-23">2. 全体の設定（bodyセレクター）</h3>
<pre class="code"><code>body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
    background-color: #f4f4f4;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
    overscroll-behavior-y: none;
}
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">目的：</span>ページ全体の基本となるスタイルを設定しています。</li>
<li><span class="bold">全体のデザイン：</span>
<ul class="箇条書き2">
<li><span class="bold">font-family：</span>フォントの種類を指定。Arialがメイン。</li>
<li><span class="bold">margin と padding：</span>0 にすることで、ブラウザの初期余白をリセット。</li>
<li><span class="bold">background-color：</span>薄いグレー（#f4f4f4）で全体の背景色に指定。</li>
</ul>
</li>
<li><span class="bold">特殊な設定：</span>
<ul class="箇条書き2">
<li><span class="bold">-webkit-tap-highlight-color：</span>スマホでタップしたときのハイライトを無効化。</li>
<li><span class="bold">overscroll-behavior-y：</span>スクロールの挙動を制御することで、特にスマートフォンなどでの意図しない操作を防いでいます。</li>
</ul>
</li>
</ul>
<h3 class="heading-23">3. 更新情報のスタイル（.画面更新情報）</h3>
<pre class="code"><code>.画面更新情報 {
    text-align: center;
    font-size: var(--小文字サイズ);
    line-height: var(--小文字行高さ);
    color: #333;
}
</code></pre>
<ul class="箇条書き1">
<li>更新情報（リフレッシュレートやフレームレート）の文字を中央揃えにし、小さなフォントサイズで表示しています。</li>
</ul>
<h3 class="heading-23">4. スクリーンエリアの設定（.スクリーン）</h3>
<pre class="code"><code>.スクリーン {
    width: 640px;
    height: 640px;
    margin: 20px auto;
    border: 2px solid #ccc;
    position: relative;
    background-color: black;
}
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">目的：</span>画面のメイン表示部分となるエリアのスタイル設定です。</li>
<li><span class="bold">ポイント：</span>
<ul class="箇条書き2">
<li><span class="bold">width &amp; height：</span>幅と高さを640pxずつ固定。</li>
<li><span class="bold">margin: 20px auto：</span>上下に20pxの余白を作り、中央に配置。</li>
<li><span class="bold">border：</span>灰色（#ccc）の2px枠線を追加。</li>
<li><span class="bold">background-color：</span>背景を黒に設定。</li>
<li><span class="bold">position: relative：</span>内部に配置する要素（たとえば canvas やメッセージウィンドウ）の絶対配置の基準となります。</li>
</ul>
</li>
</ul>
<h3 class="heading-23">5. Canvas（キャンバス）の設定</h3>
<pre class="code"><code>canvas {
    position: absolute;
}
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">目的：</span>描画領域として利用する canvas 要素を絶対配置にしています。</li>
<li><span class="bold">ポイント：</span>これにより、canvas は親要素（ここでは .スクリーン）の中で自由に配置できるようになります。</li>
</ul>
<h3 class="heading-23">6. 表示や非表示を制御するクラス</h3>
<pre class="code"><code>.不可視化 {
    visibility: hidden;
}

.透明化 {
    opacity: 0;
}

.消去 {
    display: none;
}

.表示 {
    display: block;
}
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">目的：</span>HTML 要素の表示状態を切り替えるための便利なクラスを定義しています。</li>
<li><span class="bold">違い：</span>
<ul class="箇条書き2">
<li><span class="bold">.不可視化：</span>visibility: hidden; は、その領域はレイアウトに残るが見えなくなる。</li>
<li><span class="bold">.透明化：</span>opacity: 0; は、要素が透明になり見えなくなるが、クリックなどのイベントは受ける場合もある。</li>
<li><span class="bold">.消去：</span>display: none; は、要素自体を完全に除去してレイアウトに影響を与えない。</li>
<li><span class="bold">.表示：</span>display: block; は、要素を改めてブロック表示させます。</li>
</ul>
</li>
</ul>
<h3 class="heading-23">7. 点滅アニメーションの定義</h3>
<h4 class="heading-33"><span>7.1 キーフレームの定義</span></h4>
<pre class="code"><code>@keyframes 点滅 {
    0% {
        opacity: 1;
    }
    50% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">目的：</span>点滅のアニメーションです。</li>
<li><span class="bold">ポイント：</span>
<ul class="箇条書き2">
<li>0%（開始時）と 100%（終了時）の時点で透明度 opacity が 1 ＝完全に表示</li>
<li>50% の時点で透明度が 0 ＝完全に消える</li>
<li>これにより、要素が周期的に現れたり消えたりします</li>
</ul>
</li>
</ul>
<h4 class="heading-33"><span>7.2 点滅クラスの適用</span></h4>
<pre class="code"><code>.点滅 {
    animation: 点滅 1s ease-out infinite;
}
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">目的：</span>このクラスを要素につけると、先ほど定義した点滅のアニメーションが適用されます。</li>
<li><span class="bold">ポイント：</span>
<ul class="箇条書き2">
<li><span class="bold">animation：</span>点滅 1s ease-out infinite;
<ul class="箇条書き3">
<li>アニメーション名は「点滅」</li>
<li>アニメーション期間は 1 秒</li>
<li>ease-out により、終了に向かってゆっくり変化する効果</li>
<li>infinite で繰り返し無限に実行</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 class="heading-23">8. メッセージウィンドウの設定</h3>
<pre class="code"><code>.メッセージウィンドウ {
    position: absolute;
    background-color: rgba(0, 0, 0, 0.7);
    border: solid 3px white;
    padding: 12px 17px;
    margin: 5px;
    transition: opacity var(--トランジションスピード) ease-out;
}
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">メッセージウィンドウ全体のデザイン：</span>
<ul class="箇条書き2">
<li><span class="bold">背景：</span>半透明の黒（rgba(0, 0, 0, 0.7)）。</li>
<li><span class="bold">枠線：</span>白色の3px枠線。</li>
<li><span class="bold">アニメーション：</span>transition により透明度（opacity）を滑らかに変化させる。</li>
</ul>
</li>
</ul>
<h4 class="heading-33"><span>8.1 メッセージエリア</span></h4>
<pre class="code"><code>.メッセージウィンドウ .メッセージエリア {
    padding: 3px;
    margin: 0px;
    font-size: var(--通常文字サイズ);
    line-height: var(--通常文字行高さ);
    color: white;
    text-shadow: var(--黒い影);
    width: 584px;
    height: 154px;
    overflow: scroll;
    -ms-overflow-style: none;
    scrollbar-width: none;
}

.メッセージウィンドウ .メッセージエリア::-webkit-scrollbar {
    display: none;
}
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">文字デザイン：</span>
<ul class="箇条書き2">
<li>font-size と line-height は設定済みの変数を使用。</li>
<li>白色の文字（color: white）に影（text-shadow）を追加。</li>
</ul>
</li>
<li><span class="bold">スクロールバー非表示：</span>
<ul class="箇条書き2">
<li>overflow: scroll; により、テキストがあふれる場合はスクロールできるように設定。ただし、IE と Firefox のスクロールバーは none で非表示にしています。</li>
<li>また、WebKit系ブラウザではスクロールバーを完全に非表示にする設定も追加。</li>
</ul>
</li>
</ul>
<h4 class="heading-33"><span>8.2 カーソル（■）の設定</span></h4>
<pre class="code"><code>.メッセージウィンドウ .カーソル {
    font-size: var(--通常文字サイズ);
    display: inline-block;
    transform: translateY(-2px);
}
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">目的：</span>メッセージウィンドウ内の「カーソル」要素（■）をスタイリングします。</li>
<li><span class="bold">ポイント：</span>
<ul class="箇条書き2">
<li>transform: translateY(-2px); は、カーソルがテキストの高さに合わせて少し位置調整されるための設定です。</li>
<li>先ほどの「点滅」クラスを付けると、点滅するカーソルとして動作させることができます。</li>
</ul>
</li>
</ul>
<h2 class="heading-018">com.js　-　共通処理クラス</h2>
<p>Com クラス は共通で使用できる処理をまとめています。<br />
一時停止と時間フォーマットの２つがあります。</p>
<pre class="code"><code>export class Com {
    static 一時停止(時間) {
        return new Promise(resolve =&gt; setTimeout(resolve, 時間 * 1000));
    }

    static シリアル値を時分秒に変換する(シリアル値) {
        // シリアル値をDateオブジェクトに変換
        const date = new Date(シリアル値);

        // 時間、分、秒を取得
        const hours = date.getHours();
        const minutes = date.getMinutes();
        const seconds = date.getSeconds();

        // フォーマットして返す
        return `${hours}時${minutes}分${seconds}秒`;
    }
}
</code></pre>
<h3 class="heading-23">1. 一時停止(時間) メソッド</h3>
<p><span class="bold">役割：</span>指定した時間だけプログラムを停止する機能を提供します。例えば、ゲームやタイマー機能で使われることがあります。</p>
<p><span class="bold">仕組み：</span></p>
<ul class="箇条書き1">
<li>setTimeout という JavaScriptの関数を利用して、一時停止を実現します。</li>
<li>setTimeout は、第2引数で指定した時間が経過した後に、第1引数で指定した関数をコールします。</li>
<li>Promise を使って、停止が終わった後に次の処理を続けられるようにしています。</li>
</ul>
<p><span class="bold">コードの流れ：</span></p>
<ol class="箇条書き1">
<li>setTimeout を使って指定した時間（秒&times;1000ミリ秒）だけ待ちます。</li>
<li>待ち時間が終わったら resolve で「再開していいよ」と合図します。</li>
</ol>
<h3 class="heading-23">2. シリアル値を時分秒に変換する(シリアル値) メソッド</h3>
<p><span class="bold">役割：</span>シリアル値（数値形式の時刻）を、「〇〇時〇〇分〇〇秒」という形に変換して表示します。</p>
<p><span class="bold">仕組み：</span></p>
<ul class="箇条書き1">
<li>JavaScript の Date オブジェクトを利用してシリアル値を時間に変換します。</li>
<li>変換された日時から「時」「分」「秒」を取り出します。</li>
<li>最後にフォーマットして使いやすい形（日本語の時刻表記）にします。</li>
</ul>
<p><span class="bold">コードの流れ：</span></p>
<ol class="箇条書き1">
<li>new Date(シリアル値) でシリアル値を日時オブジェクトに変換します。</li>
<li>getHours、getMinutes、getSeconds でそれぞれ「時」「分」「秒」を取得します。</li>
<li>フォーマットして、「〇〇時〇〇分〇〇秒」の形で返します。</li>
</ol>
<h2 class="heading-018">data.js　-　データ管理クラス</h2>
<p>この Data クラスは、文字列に埋め込まれた &lt;var&gt;変数名&lt;/var&gt; の形式で記述された変数を、事前に登録されたデータ（オブジェクト管理）から値を引き出して置き換えます。<br />
イメージとしては、テンプレートに変数名を埋め込んでおき、実行時にそれを動的に値へ変える仕組みです。</p>
<pre class="code"><code>export class Data {
    static オブジェクト管理 = {};

    static 文字列内の変数を値に変換する(文字列) {
        let 変換結果 = 文字列;
        const varList = 変換結果.match(/&lt;var&gt;[^&lt;]*&lt;\/var&gt;/g);
        if (!varList) return 変換結果; // 変数が無い場合は何もせずにそのまま返す

        varList.forEach(varTag =&gt; {
            const 変数名 = varTag.replace(/&lt;var&gt;([^&lt;]*)&lt;\/var&gt;/, "$1");
            const 値 = Data.変数の値を取得する(変数名);
            変換結果 = 変換結果.replace(varTag, 値); // &lt;var&gt;・・・&lt;/var&gt;を値に置き換える
        });
        return 変換結果;
    }

    static 変数の値を取得する(変数名) {
        const 名称リスト = 変数名.split(".");
        let 値 = Data.オブジェクト管理;

        for (const 名称 of 名称リスト) {
            値 = 値?.[名称];
            if (値 === undefined || 値 === null) return ""; // 値がない場合は空文字を使用
        }
        return 値;
    }
}
</code></pre>
<h3 class="heading-23">1. オブジェクト管理：静的プロパティ</h3>
<pre class="code"><code>static オブジェクト管理 = {};
</code></pre>
<ul class="箇条書き1">
<li>このプロパティは「変数名と値」を管理するための大元のデータ構造です。</li>
<li>登録されたデータを基に、変数名の値を検索します。</li>
</ul>
<p>例: もし オブジェクト管理 = { "user": { "name": "プレイヤー", "level": 25 } } となっている場合、user.name の値は "プレイヤー" となります。</p>
<h3 class="heading-23">2. 文字列内の変数を値に変換する：メソッド</h3>
<p><span class="bold">役割：</span></p>
<ul class="箇条書き1">
<li><span class="bold">入力：</span>変換対象の文字列（例: "こんにちは、&lt;var&gt;user.name&lt;/var&gt;さん！"）</li>
<li><span class="bold">出力：</span>変換結果の文字列（例: "こんにちは、プレイヤーさん！"）</li>
</ul>
<p><span class="bold">コードの流れ：</span></p>
<ol class="箇条書き1">
<li><span class="bold">変数タグを探す:</span>
<pre class="code"><code>const varList = 変換結果.match(/&lt;var&gt;[^&lt;]*&lt;\/var&gt;/g);
</code></pre>
この正規表現を使って &lt;var&gt;変数名&lt;/var&gt; の形を探し出します。例えば、&lt;var&gt;user.name&lt;/var&gt; が該当します。</li>
<li><span class="bold">変数名を取り出す:</span>
<pre class="code"><code>const 変数名 = varTag.replace(/&lt;var&gt;([^&lt;]*)&lt;\/var&gt;/, "$1");
</code></pre>
この処理で &lt;var&gt; と &lt;/var&gt; を取り除き、純粋な変数名（例: user.name）を取り出します。</li>
<li><span class="bold">値に置き換える:</span>
<pre class="code"><code>const 値 = Data.変数の値を取得する(変数名);
変換結果 = 変換結果.replace(varTag, 値);
</code></pre>
Data.変数の値を取得する メソッドで値を検索し、該当する場合は置き換えます。</li>
</ol>
<h3 class="heading-23">3. 変数の値を取得する：メソッド</h3>
<p>このメソッドは、「変数名の構造」を辿りながら オブジェクト管理 の中から適切な値を見つけ出します。</p>
<p><span class="bold">コードの流れ：</span></p>
<ol class="箇条書き1">
<li><span class="bold">変数名を分割:</span>
<pre class="code"><code>const 名称リスト = 変数名.split(".");
</code></pre>
例えば、user.name なら ["user", "name"] に分解されます。</li>
<li><span class="bold">値を辿る:</span>
<pre class="code"><code>値 = 値?.[名称];
</code></pre>
名前リストを順番に参照しながらネストされた構造を探索します。
<p><span class="bold">例：</span></p>
<ul class="箇条書き2">
<li>オブジェクト管理 = { "user": { "name": "プレイヤー" } }</li>
<li>変数名 = "user.name"</li>
<li>処理結果: "プレイヤー"</li>
</ul>
</li>
<li><span class="bold">値が存在しなければ空文字を返す:</span>
<pre class="code"><code>if (値 === undefined || 値 === null) return "";
</code></pre>
</li>
</ol>
<h3 class="heading-23">4. 全体の動作イメージ</h3>
<p>例えば、以下のように使われます：</p>
<pre class="code"><code>Data.オブジェクト管理 = {
    user: { name: "プレイヤー", level: 25 },
    system: { time: "12:00" }
};

const result = Data.文字列内の変数を値に変換する(
    'こんにちは、&lt;var&gt;user.name&lt;/var&gt;さん。現在の時刻は&lt;var&gt;system.time&lt;/var&gt;です。'
);

console.log(result);
// 結果: "こんにちは、プレイヤーさん。現在の時刻は12:00です。"
</code></pre>
<h2 class="heading-018">messageWindow.js　-　メッセージウィンドウクラス</h2>
<pre class="code"><code>import { Data } from './data.js'; // クラスをインポート
import { ループ } from './loop.js'; // クラスをインポート
import { Com } from './com.js'; // クラスをインポート

class 制御情報クラス {
    constructor(メッセージ, メッセージエリア要素) {
        this.メッセージ = メッセージ;
        this.表示位置 = 0;
        this.表示メッセージ = "";
        this.クリック待ちフラグ = false;
        this.表示フレームカウンタ = 0;
        this.クリック待ちフレームカウンタ = 0;
        this.スクロール高さ = メッセージエリア要素.scrollHeight;
        this.一括表示フラグ = false;
    }
}

export class メッセージウィンドウクラス {
    constructor(スクリーンセレクタ, メッセージウィンドウセレクタ, 出現時間 = 1.0
        , 表示フレーム間隔 = 2, クリック待ち時間 = 30) {
        this.スクリーン要素 = document.querySelector(スクリーンセレクタ);
        this.メッセージウィンドウ要素 = this.スクリーン要素.querySelector(メッセージウィンドウセレクタ);
        this.メッセージエリア要素 = this.メッセージウィンドウ要素.querySelector(".メッセージエリア");
        this.メッセージ要素 = this.メッセージエリア要素.querySelector(".メッセージ");
        this.カーソル要素 = this.メッセージエリア要素.querySelector(".カーソル");
        this.出現時間 = 出現時間;
        this.表示フレーム間隔 = 表示フレーム間隔;
        this.クリック待ちフレーム数 = this.基本クリック待ちフレーム数 = クリック待ち時間 &gt; 0 ? ループ.フレームレート * クリック待ち時間 : 0;
    }

    メッセージを表示する(メッセージ) {
        const 制御情報 = new 制御情報クラス(Data.文字列内の変数を値に変換する(メッセージ), this.メッセージエリア要素);
        this.スクリーン要素.onclick = this.メッセージ表示時にクリックする.bind(this, 制御情報);
        return new Promise(resolve =&gt; {
            ループ.処理を追加する(this, () =&gt; {
                if (this.クリック待ち時の処理を行う(制御情報)) return;

                // 表示フレーム間隔でメッセージを表示する
                if (0 &lt; 制御情報.表示フレームカウンタ--) return;
                制御情報.表示フレームカウンタ = this.表示フレーム間隔;

                // 指定されたメッセージを全て表示したら処理を終了する
                if (制御情報.表示位置 &gt;= 制御情報.メッセージ.length) {
                    ループ.処理を削除する(this);
                    this.スクリーン要素.onclick = null;
                    resolve();
                    return;
                }

                if (this.メッセージを一括で表示する(制御情報)) return;
                if (this.制御タグを取得する(制御情報)) return;
                this.指定した文字数のメッセージを表示する(制御情報, 1);
            });
        });
    }

    クリック待ち時の処理を行う(制御情報) {
        if (!制御情報.クリック待ちフラグ) return false;

        // クリック待ち時間（クリック待ちフレーム数）が0の場合は無限にクリックを待つ
        if (!this.クリック待ちフレーム数) return true;

        // クリック待ち時間までクリックを待つ
        if (this.クリック待ちフレーム数 &gt; 制御情報.クリック待ちフレームカウンタ++) return true;

        制御情報.クリック待ちフレームカウンタ = 0;
        this.クリック待ち時にクリックする(制御情報);
        return true;
    }

    メッセージを一括で表示する(制御情報) {
        if (!制御情報.一括表示フラグ) return false;

        // 制御タグまでの文字を一括で表示する
        let 表示文字数 = 制御情報.メッセージ.indexOf('&lt;', 制御情報.表示位置) - 制御情報.表示位置;
        if (表示文字数 == 0) return false; // 次の文字が制御タグだった場合
        if (表示文字数 &lt; 0) {
            // 制御タグが無い場合は最後まで表示する
            表示文字数 = 制御情報.メッセージ.length - 制御情報.表示位置;
        }
        this.指定した文字数のメッセージを表示する(制御情報, 表示文字数);
        return true;
    }

    指定した文字数のメッセージを表示する(制御情報, 文字数) {
        制御情報.表示メッセージ += 制御情報.メッセージ.substring(制御情報.表示位置, 制御情報.表示位置 + 文字数);
        制御情報.表示位置 += 文字数;
        this.メッセージ要素.innerHTML = 制御情報.表示メッセージ;
        if (制御情報.スクロール高さ == this.メッセージエリア要素.scrollHeight) return;
        this.メッセージエリア要素.scrollTop = 制御情報.スクロール高さ = this.メッセージエリア要素.scrollHeight;
        return;
    }

    制御タグを取得する(制御情報) {
        if (制御情報.メッセージ.charAt(制御情報.表示位置) != '&lt;') return false;
        if (this.制御タグの処理を行う(制御情報, '&lt;br&gt;', () =&gt; 制御情報.表示メッセージ += '&lt;br&gt;')) return true; // 改行する
        if (this.制御タグの処理を行う(制御情報, '&lt;c&gt;', () =&gt; 制御情報.表示メッセージ = '')) return true; // クリアする
        if (this.クリック待ちにする(制御情報)) return true;
        return false;
    }

    制御タグの処理を行う(制御情報, タグ名, 処理) {
        if (!制御情報.メッセージ.startsWith(タグ名, 制御情報.表示位置)) return false;
        制御情報.表示位置 += タグ名.length;
        処理();
        this.メッセージ要素.innerHTML = 制御情報.表示メッセージ;
        return true;
    }

    クリック待ちにする(制御情報) {
        const タグ名 = '&lt;w&gt;';
        if (!制御情報.メッセージ.startsWith(タグ名, 制御情報.表示位置)) return false;
        const 取得メッセージ = 制御情報.メッセージ.substring(制御情報.表示位置);
        const wList = 取得メッセージ.match(/^&lt;w&gt;\d*&lt;\/w&gt;/);
        if (wList) {
            const 待ち時間 = Number(wList[0].replace(/&lt;w&gt;(\d*)&lt;\/w&gt;/, "$1"));
            制御情報.表示位置 += wList[0].length;
            this.クリック待ちフレーム数 = 待ち時間 &gt; 0 ? ループ.フレームレート * 待ち時間 : 0;
        } else {
            制御情報.表示位置 += タグ名.length;
        }
        制御情報.クリック待ちフラグ = true;
        制御情報.一括表示フラグ = false;
        this.スクリーン要素.onclick = this.クリック待ち時にクリックする.bind(this, 制御情報);
        this.カーソル要素.classList.toggle('不可視化', false);
        return true;
    }

    クリック待ち時にクリックする(制御情報) {
        制御情報.クリック待ちフラグ = false;
        this.クリック待ちフレーム数 = this.基本クリック待ちフレーム数;
        this.カーソル要素.classList.toggle('不可視化' , true);
        this.スクリーン要素.onclick = this.メッセージ表示時にクリックする.bind(this, 制御情報);
    }

    メッセージ表示時にクリックする(制御情報) {
        制御情報.一括表示フラグ = true;
    }

    async 表示する() {
        this.メッセージウィンドウ要素.classList.replace('消去', '表示');
        await Com.一時停止(this.出現時間); // 少しずつ出現する時間
        this.メッセージウィンドウ要素.classList.toggle('透明化', false);
        await Com.一時停止(this.出現時間); // 出現した後に少し待つ
    }

    async 消去する() {
        this.メッセージウィンドウ要素.classList.toggle('透明化', true);
        this.メッセージウィンドウ要素.classList.replace('表示', '消去');
        this.メッセージ要素.innerHTML = "";
    }
}
</code></pre>
<h3 class="heading-23">1. 全体の流れ</h3>
<p>このコードは、以下の3つの主要なクラスを利用しています：</p>
<ul class="箇条書き1">
<li><span class="bold">Dataクラス：</span>文字列内に変数を埋め込んで値を変換します。</li>
<li><span class="bold">ループクラス：</span>アニメーションや継続的な処理を管理します。</li>
<li><span class="bold">Comクラス：</span>一時停止や時刻表示などの補助的な処理を提供します。</li>
</ul>
<p>さらに、以下の2つのクラスを新たに定義しています：</p>
<ul class="箇条書き1">
<li><span class="bold">制御情報クラス：</span>メッセージを管理する内部データ構造。</li>
<li><span class="bold">メッセージウィンドウクラス：</span>メッセージウィンドウの動作を管理します。</li>
</ul>
<h3 class="heading-23">2. 制御情報クラス</h3>
<p>このクラスは、文字表示の進捗状況を管理します。</p>
<p><span class="bold">プロパティの内容：</span></p>
<ul class="箇条書き1">
<li><span class="bold">メッセージ：</span>「表示する全文字列」。 ※ここには、変数の値に変換された後のテキストが格納されます。</li>
<li><span class="bold">表示位置：</span>現在、どこまで文字列を表示済みかのインデックスです。</li>
<li><span class="bold">表示メッセージ：</span>実際に画面上に表示中の文字列。</li>
<li><span class="bold">クリック待ちフラグ：</span>制御タグ（例えば &lt;w&gt;）でクリック待ち状態になったときに true となります。</li>
<li><span class="bold">表示フレームカウンタ：</span>１文字表示するまでのフレーム間隔を管理するためのカウンタ。</li>
<li><span class="bold">クリック待ちフレームカウンタ：</span>クリック待ちの時間（フレーム数）をカウントするためのもの。</li>
<li><span class="bold">スクロール高さ：</span>メッセージエリアのスクロール位置を更新する必要があるかどうかを判断するため、初期のスクロール高さを記録します。</li>
<li><span class="bold">一括表示フラグ：</span>ユーザーが画面（スクリーン）をクリックすると、通常の１文字ずつの表示ではなく「一括表示」に切り替えるためのフラグです。</li>
</ul>
<h3 class="heading-23">3. メッセージウィンドウクラス</h3>
<p><span class="bold">■ コンストラクタ</span></p>
<p>このクラスのコンストラクタでは、引数としてセレクタ（例えば、スクリーンおよびメッセージウィンドウの要素を指定する文字列）が渡されます。また、出現時間、１文字ずつ表示する際のフレーム間隔、クリック待ち時間（フレーム換算）を受け取ります。 処理の流れは以下のとおり：</p>
<ol class="箇条書き1">
<li><span class="bold">DOM要素の取得：</span>
<ul class="箇条書き2">
<li>画面全体を示す「スクリーン要素」</li>
<li>その中の「メッセージウィンドウ要素」</li>
<li>ウィンドウ内の「メッセージエリア」および「メッセージ」要素</li>
<li>最後に、カーソル（点滅させる対象）の要素を取得</li>
</ul>
</li>
<li><span class="bold">各種パラメータの保持：</span>出現時間や表示フレーム間隔、そしてクリック待ちフレーム数（ループのフレームレート&times;待ち時間）を設定しています。</li>
</ol>
<h3 class="heading-23">4. メッセージの表示処理</h3>
<p><span class="bold">■ メッセージを表示する：メソッド</span></p>
<ol class="箇条書き1">
<li><span class="bold">初期設定：</span>
<ul class="箇条書き2">
<li>渡されたメッセージ（変数の置換済みのテキスト）とメッセージエリア要素の情報をもとに、新しい 制御情報クラス のインスタンスを作成します。</li>
</ul>
</li>
<li><span class="bold">クリックイベントの設定：</span>
<ul class="箇条書き2">
<li>画面（スクリーン要素）をクリックすると、メッセージ表示時にクリックする メソッド（後述）で処理が走るようにします。</li>
</ul>
</li>
<li><span class="bold">ループ処理の追加：</span>
<ul class="箇条書き2">
<li>外部のループ管理（requestAnimationFrame を利用している ループ クラス）に対して、このメッセージ表示処理関数を登録します。</li>
</ul>
</li>
<li><span class="bold">各フレームでの動作：</span>
<ul class="箇条書き2">
<li>クリック待ちの場合は、クリックされるか指定した時間が経過するまで待機します。</li>
<li>それ以外の場合、設定されたフレーム間隔ごとに表示する文字数を更新します。</li>
<li>もし全メッセージが表示されていれば、ループ処理を削除して Promise を解決（終了）します。</li>
</ul>
</li>
<li><span class="bold">一括表示の確認：</span>
<ul class="箇条書き2">
<li>ユーザーのクリックによって一括表示フラグが true になっている場合は、通常の１文字ずつの表示ではなく、次の制御タグ（&lt; で始まる部分）までのテキストを一気に表示します。</li>
</ul>
</li>
<li><span class="bold">制御タグの処理：</span>
<ul class="箇条書き2">
<li>現在の位置が &lt; なら、制御タグを取得する でタグ内容を処理します（たとえば &lt;br&gt; なら改行、&lt;c&gt; ならメッセージクリア、&lt;w&gt; ならクリック待ち）。</li>
</ul>
</li>
<li><span class="bold">最後は１文字ずつ表示：</span>
<ul class="箇条書き2">
<li>上記いずれにも該当しなければ、指定した文字数のメッセージを表示する メソッドで１文字だけ追加して表示します。</li>
</ul>
</li>
</ol>
<h3 class="heading-23">5. 制御タグの処理</h3>
<p><span class="bold">■ 制御タグの例</span></p>
<ul class="箇条書き1">
<li><span class="bold">&lt;br&gt;：</span>改行を挿入するタグ。
<ul class="箇条書き2">
<li>処理関数により、表示中のメッセージに &lt;br&gt; を追加します。</li>
</ul>
</li>
<li><span class="bold">&lt;c&gt;：</span>表示中のメッセージをクリアするタグ。
<ul class="箇条書き2">
<li>このタグを検出すると、表示文字列を空文字にリセットします。</li>
</ul>
</li>
<li><span class="bold">&lt;w&gt;数字&lt;/w&gt;：</span>クリック待ちタグ。
<ul class="箇条書き2">
<li>ここではタグ内の数字を読み取り、その秒数分（ループのフレームレート&times;秒数）のクリック待ち状態にします。</li>
<li>同時に「クリック待ちフラグ」が true になり、カーソルの表示も切り替えられます（不可視を無効にする）。</li>
</ul>
</li>
</ul>
<h3 class="heading-23">6. ユーザークリックでの一括表示</h3>
<p><span class="bold">■ メッセージ表示時にクリックする：メソッド</span></p>
<ul class="箇条書き1">
<li>ユーザーが画面（スクリーン）をクリックすると、通常は１文字ずつ表示されるところを、一括表示フラグを true に設定します。</li>
<li>次のループ処理時に、メッセージを一括で表示する が呼ばれ、次の制御タグまでのテキストをまとめて表示します。</li>
</ul>
<h3 class="heading-23">7. 表示・消去の演出</h3>
<p><span class="bold">■ 表示する：メソッド</span></p>
<ul class="箇条書き1">
<li>メッセージウィンドウを出現させる際に、CSS クラスを切り替えます。<ol class="箇条書き2">
<li>初めは非表示状態（たとえば、消去 クラスが付いている）から、表示 クラスに切り替えます。</li>
<li>その後、指定した出現時間だけ一時停止（Com.一時停止 を使用）し、さらに透明状態を解除（透明化 クラスの切替）して、ふわっと表示されるようにします。</li>
</ol></li>
</ul>
<p><span class="bold">■ 消去する：メソッド</span></p>
<ul class="箇条書き1">
<li>表示されたメッセージウィンドウを非表示にするため、透明度を下げ、表示 クラスを 消去 に変更し、メッセージ内容をクリアします。</li>
</ul>
<h2 class="heading-018">sample.js　-　サンプルクラス</h2>
<p>このプログラムは次のような処理を行います：</p>
<ol class="箇条書き1">
<li>必要なクラスをインポートします。</li>
<li>メイン処理 (main) を実行します。</li>
<li>ループ処理や画面描画を初期化します。</li>
<li>画像を読み込み、それを基にスプライトを作成します。</li>
<li>作成したスプライトやメッセージウィンドウを表示します。</li>
</ol>
<pre class="code"><code>import { 画像管理クラス } from './imageManager.js'; // クラスをインポート
import { スプライトクラス } from './sprite.js'; // クラスをインポート
import { レイヤークラス } from './layer.js'; // クラスをインポート
import { ループ } from './loop.js'; // クラスをインポート
import { メッセージウィンドウクラス } from './messageWindow.js'; // クラスをインポート
import { Data } from './data.js'; // クラスをインポート
import { Com } from './com.js'; // クラスをインポート

class サンプル {
    static async main() {
        サンプル.ループ処理を作成する();
        サンプル.メッセージウィンドウを作成する();
        サンプル.レイヤーを作成する();
        if (!await サンプル.使用する画像を読み込む()) return;
        サンプル.読み込んだ画像でスプライトを作成する();
        サンプル.作成した物を使って画面に表示する();
    }

    static ループ処理を作成する() {
        ループ.初期化する();
        ループ.開始する();
    }

    static メッセージウィンドウを作成する() {
        サンプル.メッセージウィンドウ = new メッセージウィンドウクラス(".スクリーン", ".メッセージウィンドウ");
        Data.オブジェクト管理["サンプル"] = サンプル;
    }

    static レイヤーを作成する() {
        サンプル.レイヤー = new レイヤークラス('canvas.レイヤー1');
        ループ.処理を追加する(サンプル.レイヤー, サンプル.レイヤー.描画する.bind(サンプル.レイヤー));
    }

    static async 使用する画像を読み込む() {
        const 画像情報リスト = [
            { id: '町01', src: 'img/bg02.jpg' },
            { id: '人物01', src: 'img/chara01.png' }
        ];
        サンプル.画像管理 = new 画像管理クラス();
        return await サンプル.画像管理.画像を読み込む(画像情報リスト);
    }

    static 読み込んだ画像でスプライトを作成する() {
        サンプル.背景01 = new スプライトクラス(サンプル.レイヤー, サンプル.画像管理.取得する('町01'), 0, 0, 640, 640);
        サンプル.レイヤー.処理を追加する(サンプル.背景01, サンプル.背景01.描画する.bind(サンプル.背景01));
        サンプル.人物01 = new スプライトクラス(サンプル.レイヤー, サンプル.画像管理.取得する('人物01'), 0, 150, 640, 640);
        サンプル.人物01正位置 = { x: サンプル.人物01.x, y: サンプル.人物01.y };
        サンプル.人物01.座標を設定する(640, 150, 1280, 640); //初期表示位置を設定する
    }

    static async 作成した物を使って画面に表示する() {
        サンプル.主人公名 = "プレイヤー";
        サンプル.現時刻 = Com.シリアル値を時分秒に変換する(Date.now());

        await サンプル.人物01.移動してフェードインする(-10, 0, サンプル.人物01正位置.x, 0, 1);
        ループ.処理を削除する(サンプル.レイヤー);

        await サンプル.メッセージウィンドウ.表示する();
        await サンプル.メッセージウィンドウ.メッセージを表示する(
    "&lt;var&gt;サンプル.主人公名&lt;/var&gt;は町を訪れた&lt;w&gt;5&lt;/w&gt;&lt;br&gt;&lt;c&gt;&lt;var&gt;サンプル.主人公名&lt;/var&gt;はとりあえず町の人に今何時か聞いてみた&lt;w&gt;&lt;br&gt;すると「&lt;var&gt;サンプル.現時刻&lt;/var&gt;」だと教えてくれた&lt;w&gt;"
        );
        await サンプル.メッセージウィンドウ.消去する();

        while (1) {
            サンプル.現時刻 = Com.シリアル値を時分秒に変換する(Date.now());

            await サンプル.メッセージウィンドウ.表示する();
            await サンプル.メッセージウィンドウ.メッセージを表示する(
    "暫くして、&lt;var&gt;サンプル.主人公名&lt;/var&gt;はまた何時なのか気になった&lt;w&gt;2&lt;/w&gt;&lt;br&gt;辺りの人に聞いてみると「&lt;var&gt;サンプル.現時刻&lt;/var&gt;」だと教えてくれた&lt;w&gt;"
            );
            await サンプル.メッセージウィンドウ.消去する();
        }
    }
}

addEventListener('load', サンプル.main);
</code></pre>
<h3 class="heading-23">1. クラスをインポート</h3>
<pre class="code"><code>import { 画像管理クラス } from './imageManager.js'; // 画像管理に関する機能を提供
import { スプライトクラス } from './sprite.js'; // スプライト（画像）管理に関する機能
import { レイヤークラス } from './layer.js'; // レイヤー（描画画面）管理
import { ループ } from './loop.js'; // 繰り返し処理管理
import { メッセージウィンドウクラス } from './messageWindow.js'; // メッセージ表示管理
import { Data } from './data.js'; // データ管理
import { Com } from './com.js'; // 共通処理管理
</code></pre>
<p>これらのインポートにより、各機能を効率的に使うことができます。例えば、画像管理やスプライト表示、ループ処理などのモジュールが含まれています。</p>
<h3 class="heading-23">2. メイン処理</h3>
<p>サンプル.main() は全体の流れを管理するメイン処理です。これにより以下の手順が実行されます：</p>
<ol class="箇条書き1">
<li>ループ処理を設定。</li>
<li>メッセージウィンドウを作成。</li>
<li>画像を読み込んでスプライトを作成。</li>
<li>画面にスプライトやメッセージを表示。</li>
</ol>
<h3 class="heading-23">3. 画像を使用する流れ</h3>
<ul class="箇条書き1">
<li><span class="bold">画像読み込み処理：</span>
<pre class="code"><code>const 画像情報リスト = [
    { id: '町01', src: 'img/bg02.jpg' }, // 背景画像
    { id: '人物01', src: 'img/chara01.png' } // キャラクター画像
];
サンプル.画像管理 = new 画像管理クラス();
</code></pre>
画像情報リストを定義し、それらを読み込みます。</li>
<li><span class="bold">スプライト作成処理：</span>
<pre class="code"><code>サンプル.背景01 = new スプライトクラス(サンプル.レイヤー, サンプル.画像管理.取得する('町01'), 0, 0, 640, 640);
サンプル.人物01 = new スプライトクラス(サンプル.レイヤー, サンプル.画像管理.取得する('人物01'), 0, 150, 640, 640);
</code></pre>
背景やキャラクターなどをスプライトとして設定し、画面上に表示できるようにします。</li>
</ul>
<h3 class="heading-23">4. メッセージウィンドウの流れ</h3>
<ul class="箇条書き1">
<li><span class="bold">メッセージウィンドウを使ってテキストを表示します。例えば：</span>
<pre class="code"><code>await サンプル.メッセージウィンドウ.メッセージを表示する("プレイヤーは町を訪れた...");
</code></pre>
このコードで、メッセージウィンドウにテキストを表示できます。</li>
</ul>
<h3 class="heading-23">5. 繰り返し処理</h3>
<pre class="code"><code>while (1) {
    サンプル.現時刻 = Com.シリアル値を時分秒に変換する(Date.now());
    await サンプル.メッセージウィンドウ.メッセージを表示する("現在時刻は" + サンプル.現時刻);
}
</code></pre>
<p>ここでは永遠ループを使って、時間の変化を表示しています。</p>
<!--shinobi1-->
<script type="text/javascript" src="//xa.shinobi.jp/ufo/191907706"></script>
<noscript><a href="//xa.shinobi.jp/bin/gg?191907706" target="_blank"><img src="//xa.shinobi.jp/bin/ll?191907706" border="0"></a><br><span style="font-size:9px"><img style="margin:0;vertical-align:text-bottom;" src="//img.shinobi.jp/tadaima/fj.gif" width="19" height="11"> </span></noscript><!--shinobi2--></div>]]></content:encoded>
    <dc:subject>JavaScript紹介</dc:subject>
    <dc:date>2025-03-27T16:08:03+09:00</dc:date>
    <dc:creator>No Name Ninja</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>No Name Ninja</dc:rights>
  </item>
  <item rdf:about="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E7%A7%BB%E5%8B%95%E3%81%97%E3%81%AA%E3%81%8C%E3%82%89%E3%83%95%E3%82%A7%E3%83%BC%E3%83%89%E3%82%A4%E3%83%B3%EF%BC%8F%E3%82%A2%E3%82%A6%E3%83%88%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95">
    <link>https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E7%A7%BB%E5%8B%95%E3%81%97%E3%81%AA%E3%81%8C%E3%82%89%E3%83%95%E3%82%A7%E3%83%BC%E3%83%89%E3%82%A4%E3%83%B3%EF%BC%8F%E3%82%A2%E3%82%A6%E3%83%88%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95</link>
    <title>移動しながらフェードイン／アウトする方法</title>
    <description>
前回までに画像を移動する方法とフェードイン、フェードアウトする方法を記したので、今度はそれらを合わせて、移動しながらフェードイン、フェードアウトする方法を記します。

01　ファイル構成
ファイルとそれを入れるフォルダーを以下のような構成します。
前回の「フェードイン／アウトする方法」と同じです。...</description>
    <content:encoded><![CDATA[<div class="本文">
<p>前回までに画像を移動する方法とフェードイン、フェードアウトする方法を記したので、今度はそれらを合わせて、移動しながらフェードイン、フェードアウトする方法を記します。</p>
<div class="iframe-container"><iframe width="670" height="730" style="border: 0;" src="https://cf033538.cloudfree.jp/Game/sample04/sample.html"></iframe></div>
<h2 class="heading-018">01　ファイル構成</h2>
<p>ファイルとそれを入れるフォルダーを以下のような構成します。<br />
前回の「フェードイン／アウトする方法」と同じです。</p>
<div class="ファイル構成">
<ul class="list-13">
<li><span>sample04</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample04/sample.html" target="_blank">sample.html</a></li>
<li><span>js</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample04/js/sample.js" target="_blank">sample.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample04/js/imageManager.js" target="_blank">imageManager.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample04/js/sprite.js" target="_blank">sprite.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample04/js/layer.js" target="_blank">layer.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample04/js/loop.js" target="_blank">loop.js</a></li>
</ul>
</li>
<li><span>img</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample04/img/bg01.jpg" target="_blank">bg01.jpg　※背景画像（720x720px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample04/img/chara01.png" target="_blank">chara01.png　※人物画像（1024x1024px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample04/img/mon01.png" target="_blank">mon01.png　※モンスター画像（1024x1024px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample04/img/mon02.png" target="_blank">mon02.png　※モンスター画像（1024x1024px）</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<h2 class="heading-018">02　ファイル全体の流れ</h2>
<p>今回のコードは前回の「フェードイン／アウトする方法」に、移動しながらフェードインする処理と、移動しながらフェードアウトする処理を追加しています。</p>
<h2 class="heading-018">03　各部分の詳細解説</h2>
<p>変更を行った「sample.js」と「sprite.js」のファイルについて解説していきます。</p>
<h3 class="heading-23">a.　sprite.js - スプライトクラス</h3>
<pre class="code"><code>export class スプライトクラス {
    constructor(レイヤー, 画像要素, x1, y1, x2, y2) {
        this.レイヤー = レイヤー;
        this.ctx = レイヤー.ctx;
        this.画像要素 = 画像要素;
        this.座標を設定する(x1, y1, x2, y2);
    }

    座標を設定する(x1, y1, x2, y2) {
        const 画像要素 = this.画像要素;
        const 表示幅 = x2 - x1;
        const 表示高さ = y2 - y1;

        const 画像縦横比 = 画像要素.width / 画像要素.height;
        const 表示縦横比 = 表示幅 / 表示高さ;

        let 描画幅, 描画高さ, 位置調整x, 位置調整y;

        if (画像縦横比 &gt; 表示縦横比) {
            描画幅 = 表示幅;
            描画高さ = 表示幅 / 画像縦横比;
            位置調整x = 0;
            位置調整y = (表示高さ - 描画高さ) / 2; // 垂直中央揃え
        } else {
            描画高さ = 表示高さ;
            描画幅 = 表示高さ * 画像縦横比;
            位置調整x = (表示幅 - 描画幅) / 2; // 水平中央揃え
            位置調整y = 0;
        }

        this.x = x1 + 位置調整x;
        this.y = y1 + 位置調整y;
        this.幅 = 描画幅;
        this.高さ = 描画高さ;
    }

    描画する() {
        this.ctx.drawImage(this.画像要素, this.x, this.y, this.幅, this.高さ); // 画像を描画
    }

    移動して描画する(移動幅x, 移動幅y, 停止位置x, 停止位置y) {
        const 制御情報 = { 状態フラグ: 1 }; // 状態フラグ = 1(移動フラグオン)
        return new Promise(resolve =&gt; {
            this.レイヤー.処理を追加する(this, () =&gt; {
                this.移動する(制御情報, 移動幅x, 移動幅y, 停止位置x, 停止位置y);
                this.描画する();
                if (制御情報.状態フラグ) return;

                // 停止位置に来たら描画だけの処理に切替える
                this.レイヤー.処理を追加する(this, this.描画する.bind(this));
                resolve();
            });
        })
    }

    フェードインする(フェード時間 = 1) {
        const 増減値 = 1 / (60 * フェード時間); // フェード時間は秒単位とする
        const 制御情報 = { 状態フラグ: 2, 不透明度: 0.0 }; // 状態フラグ = 2(フェードフラグオン)
        return new Promise(resolve =&gt; {
            this.レイヤー.処理を追加する(this, () =&gt; {
                this.描画してフェードする(制御情報, 増減値);
                if (制御情報.状態フラグ) return;

                // 不透明度が100%になったら描画だけの処理に切替える
                this.レイヤー.処理を追加する(this, this.描画する.bind(this));
                resolve();
            });
        })
    }

    フェードアウトする(フェード時間 = 1) {
        const 増減値 = -1 / (60 * フェード時間); // フェード時間は秒単位とする
        const 制御情報 = { 状態フラグ: 2, 不透明度: 1.0 }; // 状態フラグ = 2(フェードフラグオン)
        return new Promise(resolve =&gt; {
            this.レイヤー.処理を追加する(this, () =&gt; {
                this.描画してフェードする(制御情報, 増減値);
                if (制御情報.状態フラグ) return;

                // 不透明度が0%になったら描画処理を削除する
                this.レイヤー.処理を削除する(this);
                resolve();
            });
        })
    }

    移動してフェードインする(移動幅x, 移動幅y, 停止位置x, 停止位置y, フェード時間 = 1) {
        const 増減値 = 1 / (60 * フェード時間); // フェード時間は秒単位とする
        const 制御情報 = { 状態フラグ: 3, 不透明度: 0.0 }; // 状態フラグ = 1(移動フラグオン) + 2(フェードフラグオン)
        return new Promise(resolve =&gt; {
            this.レイヤー.処理を追加する(this, () =&gt; {
                this.移動する(制御情報, 移動幅x, 移動幅y, 停止位置x, 停止位置y);
                this.描画してフェードする(制御情報, 増減値);
                if (制御情報.状態フラグ) return;

                // 停止位置に来て、尚かつ不透明度が100%なったら描画だけの処理に切替える
                this.レイヤー.処理を追加する(this, this.描画する.bind(this));
                resolve();
            });
        })
    }

    移動してフェードアウトする(移動幅x, 移動幅y, 停止位置x, 停止位置y, フェード時間 = 1) {
        const 増減値 = -1 / (60 * フェード時間); // フェード時間は秒単位とする
        const 制御情報 = { 状態フラグ: 3, 不透明度: 1.0 }; // 状態フラグ = 1(移動フラグオン) + 2(フェードフラグオン)
        return new Promise(resolve =&gt; {
            this.レイヤー.処理を追加する(this, () =&gt; {
                this.移動する(制御情報, 移動幅x, 移動幅y, 停止位置x, 停止位置y);
                this.描画してフェードする(制御情報, 増減値);
                if (制御情報.状態フラグ) return;

                // 停止位置に来て、尚かつ不透明度が0%なったら描画処理を削除する
                this.レイヤー.処理を削除する(this);
                resolve();
            });
        })
    }

    移動する(制御情報, 移動幅x, 移動幅y, 停止位置x, 停止位置y) {
        if ((制御情報.状態フラグ &amp; 1) ^ 1) return; // 移動フラグがオフなら移動しない

        if (移動幅x) {
            this.x += 移動幅x;
            if (移動幅x &gt; 0) {
                if (this.x &gt;= 停止位置x) 制御情報.状態フラグ &amp;= ~1; // 移動フラグをオフにする
            } else {
                if (this.x &lt;= 停止位置x) 制御情報.状態フラグ &amp;= ~1; // 移動フラグをオフにする
            }
        }
        if (移動幅y) {
            this.y += 移動幅y;
            if (移動幅y &gt; 0) {
                if (this.y &gt;= 停止位置y) 制御情報.状態フラグ &amp;= ~1; // 移動フラグをオフにする
            } else {
                if (this.y &lt;= 停止位置y) 制御情報.状態フラグ &amp;= ~1; // 移動フラグをオフにする
            }
        }
    }

    描画してフェードする(制御情報, 増減値) {
        this.ctx.save(); // 現在の描画状態を保存
        this.ctx.globalAlpha = 制御情報.不透明度;
        this.描画する();
        this.ctx.restore(); // 元の描画状態を復元

        if ((制御情報.状態フラグ &amp; 2) ^ 2) return; // フェードフラグがオフならフェードしない

        制御情報.不透明度 += 増減値;
        if (制御情報.不透明度 &gt; 0 &amp;&amp; 制御情報.不透明度 &lt; 1) return;

        // 不透明度が下限値または上限値を超えたら、フェードフラグをオフにする
        制御情報.状態フラグ &amp;= ~2;

        // 不透明度が下限値と上限値を超えないようにする
        制御情報.不透明度 = Math.max(0, Math.min(1, 制御情報.不透明度));
    }
}
</code></pre>
<h4 class="heading-33"><span>移動しながらフェードイン</span></h4>
<pre class="code"><code>    移動してフェードインする(移動幅x, 移動幅y, 停止位置x, 停止位置y, フェード時間 = 1) {
        const 増減値 = 1 / (60 * フェード時間); // フェード時間は秒単位とする
        const 制御情報 = { 状態フラグ: 3, 不透明度: 0.0 }; // 状態フラグ = 1(移動フラグオン) + 2(フェードフラグオン)
        return new Promise(resolve =&gt; {
            this.レイヤー.処理を追加する(this, () =&gt; {
                this.移動する(制御情報, 移動幅x, 移動幅y, 停止位置x, 停止位置y);
                this.描画してフェードする(制御情報, 増減値);
                if (制御情報.状態フラグ) return;

                // 停止位置に来て、尚かつ不透明度が100%なったら描画だけの処理に切替える
                this.レイヤー.処理を追加する(this, this.描画する.bind(this));
                resolve();
            });
        })
    }
</code></pre>
<ul class="箇条書き1">
<li>移動処理（移動する）と透明度変更処理（描画してフェードインする）を同時に行います。</li>
</ul>
<h4 class="heading-33"><span>移動しながらフェードアウト</span></h4>
<pre class="code"><code>    移動してフェードアウトする(移動幅x, 移動幅y, 停止位置x, 停止位置y, フェード時間 = 1) {
        const 増減値 = -1 / (60 * フェード時間); // フェード時間は秒単位とする
        const 制御情報 = { 状態フラグ: 3, 不透明度: 1.0 }; // 状態フラグ = 1(移動フラグオン) + 2(フェードフラグオン)
        return new Promise(resolve =&gt; {
            this.レイヤー.処理を追加する(this, () =&gt; {
                this.移動する(制御情報, 移動幅x, 移動幅y, 停止位置x, 停止位置y);
                this.描画してフェードする(制御情報, 増減値);
                if (制御情報.状態フラグ) return;

                // 停止位置に来て、尚かつ不透明度が0%なったら描画処理を削除する
                this.レイヤー.処理を削除する(this);
                resolve();
            });
        })
    }
</code></pre>
<ul class="箇条書き1">
<li>移動処理（移動する）と透明度変更処理（描画してフェードアウトする）を同時に行います。</li>
</ul>
<h4 class="heading-33"><span>状態管理 (フラグの活用)</span></h4>
<p>このコードでは「状態フラグ」を使ってスプライトの状態を管理しています。</p>
<pre class="code"><code>const 制御情報 = { 状態フラグ: 3, 不透明度: 0.0 };
</code></pre>
<ul class="箇条書き1">
<li><span class="bold">状態フラグ：</span>スプライトが「移動中」か「フェード中」かを判定します。
<ul class="箇条書き2">
<li>0:処理完了</li>
<li>1:移動中（移動フラグ）</li>
<li>2:フェード中（フェードフラグ）</li>
<li>3:移動中＋フェード中</li>
</ul>
</li>
<li>移動処理が完了すると状態フラグの移動フラグ（1）をオフにします。</li>
<li>透明度変更処理が完了すると状態フラグのフェードフラグ（2）をオフにします。</li>
<li>移動処理と透明度変更処理の両方が完了すると状態フラグは処理完了（0）になります。</li>
</ul>
<h3 class="heading-23">b.　sample.js - サンプルクラス</h3>
<pre class="code"><code>import { 画像管理クラス } from './imageManager.js'; // クラスをインポート
import { スプライトクラス } from './sprite.js'; // クラスをインポート
import { レイヤークラス } from './layer.js'; // クラスをインポート
import { ループ } from './loop.js'; // クラスをインポート

class サンプル {
    static async main() {
        const レイヤー = new レイヤークラス('canvas.レイヤー1');
        const 画像管理 = new 画像管理クラス();
        ループ.初期化する(1000/60);
        ループ.開始する();

        // 事前に読み込む画像の配列
        const 画像情報リスト = [
            { id: '草原', src: 'img/bg01.jpg' },
            { id: '人物01', src: 'img/chara01.png' },
            { id: '炎竜', src: 'img/mon01.png' },
            { id: 'デビル', src: 'img/mon02.png' }
        ];

        // ページ初期化時に画像をプリロード
        if (!await 画像管理.画像を読み込む(画像情報リスト)) return;

        // 画像の描画位置を設定
        const 背景01 = new スプライトクラス(レイヤー, 画像管理.取得する('草原'), 0, 0, 640, 640);

        const 人物01 = new スプライトクラス(レイヤー, 画像管理.取得する('人物01'), 0, 100, 640, 640);
        const 人物01正位置 = { x: 人物01.x, y: 人物01.y };
        人物01.座標を設定する(640, 100, 1280, 640); //初期表示位置を設定する

        const モンスター01 = new スプライトクラス(レイヤー, 画像管理.取得する('炎竜'), 0, 0, 640, 540);
        const モンスター01正位置 = { x: モンスター01.x, y: モンスター01.y };
        モンスター01.座標を設定する(-640, 0, 0, 540); //初期表示位置を設定する

        const モンスター02 = new スプライトクラス(レイヤー, 画像管理.取得する('デビル'), 0, 320, 320, 640);
        const モンスター02正位置 = { x: モンスター02.x, y: モンスター02.y };
        モンスター02.座標を設定する(640, -640, 960, 320); //初期表示位置を設定する

        const モンスター03 = new スプライトクラス(レイヤー, 画像管理.取得する('デビル'), 320, 320, 640, 640);

        ループ.処理を追加する(レイヤー, レイヤー.描画する.bind(レイヤー));
        背景01.レイヤー.処理を追加する(背景01, 背景01.描画する.bind(背景01));

        let プロミスリスト;
        while (1) {
            await 人物01.移動してフェードインする(-10, 0, 人物01正位置.x, 0, 1);
            await サンプル.一時停止(2000);

            プロミスリスト = [];
            プロミスリスト.push(人物01.移動してフェードアウトする(5, 0, 640, 0, 0.5));
            プロミスリスト.push(モンスター01.移動して描画する(5, 0, モンスター01正位置.x, 0));
            プロミスリスト.push(モンスター02.移動してフェードインする(-10, 10, モンスター02正位置.x, モンスター02正位置.y, 1.5));
            プロミスリスト.push(モンスター03.フェードインする(0.5));
            await Promise.all(プロミスリスト);
            await サンプル.一時停止(2000);

            プロミスリスト = [];
            プロミスリスト.push(モンスター01.移動して描画する(0, 10, 0, 640));
            プロミスリスト.push(モンスター02.移動してフェードアウトする(0, 5, 0, 640,0.5));
            プロミスリスト.push(モンスター03.フェードアウトする(3));
            await Promise.all(プロミスリスト);
            await サンプル.一時停止(2000);

            モンスター01.座標を設定する(-640, 0, 0, 540); //初期表示位置を設定する
            モンスター02.座標を設定する(640, -640, 960, 320); //初期表示位置を設定する
        }
    }

    static 一時停止(時間) {
        return new Promise(resolve =&gt; setTimeout(resolve, 時間));
    }
}

addEventListener('load', サンプル.main);
</code></pre>
<h4 class="heading-33"><span>このコードの全体の流れ</span></h4>
<ol class="箇条書き1">
<li><span class="bold">画像を読み込む:</span><br />

<ul class="箇条書き2">
<li>必要な画像を事前にメモリへロードします（画像管理クラスを使用）。</li>
<li>ロード後に各画像をスプライトクラスとして設定し、描画を準備します。</li>
</ul>
</li>
<li><span class="bold">アニメーションの管理:</span><br />

<ul class="箇条書き2">
<li>ループを使って、画面内の描画やアニメーション（フェードイン/アウト）を繰り返します。</li>
</ul>
</li>
<li><span class="bold">移動しながらフェード処理を実行:</span><br />

<ul class="箇条書き2">
<li>人物 や モンスター 画像を移動しながらフェードインまたはフェードアウトさせ、アニメーションを構成します。</li>
</ul>
</li>
<li><span class="bold">一時停止（待機）:</span><br />

<ul class="箇条書き2">
<li>指定時間だけ処理を止めることで、画面切り替えのタイミングを調整します。</li>
</ul>
</li>
</ol>
<h4 class="heading-33"><span>主要なポイントの解説</span></h4>
<ol class="箇条書き1">
<li><span class="bold">移動しながらフェードイン処理：</span>
<pre class="code"><code>人物01.移動してフェードインする(-10, 0, 人物01正位置.x, 0, 1);
</code></pre>
<ul class="箇条書き2">
<li><span class="bold">移動速度：</span>上記の例では、1フレームごとに10ピクセル左に移動します。</li>
<li><span class="bold">フェードイン：</span>上記の例では、1秒以内に透明度が上がり（0&rArr;1）、完全に表示されます。</li>
</ul>
</li>
<li><span class="bold">移動しながらフェードアウト処理：</span>
<pre class="code"><code>人物01.移動してフェードアウトする(5, 0, 640, 0, 0.5);
</code></pre>
<ul class="箇条書き2">
<li><span class="bold">移動速度：</span>上記の例では、1フレームごとに5ピクセル右に移動します。</li>
<li><span class="bold">フェードイン：</span>上記の例では、0.5秒以内に透明度が下がり（1&rArr;0）、完全に非表示になります。</li>
</ul>
</li>
</ol></div>
<!--shinobi1-->
<script type="text/javascript" src="//xa.shinobi.jp/ufo/191907703"></script>
<noscript><a href="//xa.shinobi.jp/bin/gg?191907703" target="_blank"><img src="//xa.shinobi.jp/bin/ll?191907703" border="0"></a><br><span style="font-size:9px"><img style="margin:0;vertical-align:text-bottom;" src="//img.shinobi.jp/tadaima/fj.gif" width="19" height="11"> </span></noscript><!--shinobi2-->]]></content:encoded>
    <dc:subject>JavaScript紹介</dc:subject>
    <dc:date>2025-03-23T03:17:26+09:00</dc:date>
    <dc:creator>No Name Ninja</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>No Name Ninja</dc:rights>
  </item>
  <item rdf:about="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E3%83%95%E3%82%A7%E3%83%BC%E3%83%89%E3%82%A4%E3%83%B3%EF%BC%8F%E3%82%A2%E3%82%A6%E3%83%88%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95">
    <link>https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E3%83%95%E3%82%A7%E3%83%BC%E3%83%89%E3%82%A4%E3%83%B3%EF%BC%8F%E3%82%A2%E3%82%A6%E3%83%88%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95</link>
    <title>フェードイン／アウトする方法</title>
    <description>

今回は画像をフェードイン、フェードアウトする方法を記します。
フェードインとフェードアウトとは？

フェードイン: 画像やオブジェクトが徐々に現れ、不透明になる効果のこと。
フェードアウト: 画像やオブジェクトが徐々に透明になり、消えるような効果のこと。

この2つは、滑らかなトランジションを表...</description>
    <content:encoded><![CDATA[<div class="本文">
<div class="本文">
<p>今回は画像をフェードイン、フェードアウトする方法を記します。</p>
<p class="bold">フェードインとフェードアウトとは？</p>
<ul class="箇条書き1">
<li><span class="bold">フェードイン:</span> 画像やオブジェクトが徐々に現れ、不透明になる効果のこと。</li>
<li><span class="bold">フェードアウト:</span> 画像やオブジェクトが徐々に透明になり、消えるような効果のこと。</li>
</ul>
<p>この2つは、滑らかなトランジションを表現するために、ゲームやアニメーション、スライドショーなどでよく使われます。</p>
</div>
<div class="iframe-container"><iframe width="670" height="730" style="border: 0;" src="https://cf033538.cloudfree.jp/Game/sample03/sample.html"></iframe></div>
<h2 class="heading-018">01　ファイル構成</h2>
<div class="本文">
<p>ファイルとそれを入れるフォルダーを以下のような構成します。<br />
前回の「画像を移動する方法」と同じです。</p>
</div>
<div class="ファイル構成">
<ul class="list-13">
<li><span>sample03</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample03/sample.html" target="_blank">sample.html</a></li>
<li><span>js</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample03/js/sample.js" target="_blank">sample.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample03/js/imageManager.js" target="_blank">imageManager.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample03/js/sprite.js" target="_blank">sprite.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample03/js/layer.js" target="_blank">layer.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample03/js/loop.js" target="_blank">loop.js</a></li>
</ul>
</li>
<li><span>img</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample02/img/bg01.jpg" target="_blank">bg01.jpg　※背景画像（720x720px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample02/img/chara01.png" target="_blank">chara01.png　※人物画像（1024x1024px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample02/img/mon01.png" target="_blank">mon01.png　※モンスター画像（1024x1024px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample02/img/mon02.png" target="_blank">mon02.png　※モンスター画像（1024x1024px）</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<h2 class="heading-018">02　ファイル全体の流れ</h2>
<div class="本文">
<p>今回のコードは全体的に前回の「画像を移動する方法」と同じです。<br />
そのため、変更を行ったフェードイン、フェードアウトの処理について記したいと思います。</p>
<p class="bold">どのように動くのか：</p>
<p>フェードの効果を実現するには、不透明度（透明度の逆）を段階的に変化させる必要があります。</p>
<ol class="箇条書き1">
<li>不透明度（Alpha値） は 1.0 で完全に見える状態を表します。</li>
<li>0.0 は完全に透明な状態を表します。</li>
<li>フェードアウトでは、1.0 &rarr; 0.0 へ徐々に値を下げます。</li>
<li>フェードインでは、0.0 &rarr; 1.0 へ徐々に値を上げます。</li>
</ol></div>
<h2 class="heading-018">03　各部分の詳細解説</h2>
<div class="本文">
<p>変更を行った「sample.js」と「sprite.js」のファイルについて解説していきます。</p>
</div>
<h3 class="heading-23">a.　sprite.js - スプライトクラス</h3>
<pre class="code"><code>export class スプライトクラス {
    constructor(レイヤー, 画像要素, x1, y1, x2, y2) {
        this.レイヤー = レイヤー;
        this.ctx = レイヤー.ctx;
        this.画像要素 = 画像要素;
        this.座標を設定する(x1, y1, x2, y2);
    }

    座標を設定する(x1, y1, x2, y2) {
        const 画像要素 = this.画像要素;
        const 表示幅 = x2 - x1;
        const 表示高さ = y2 - y1;

        const 画像縦横比 = 画像要素.width / 画像要素.height;
        const 表示縦横比 = 表示幅 / 表示高さ;

        let 描画幅, 描画高さ, 位置調整x, 位置調整y;

        if (画像縦横比 &gt; 表示縦横比) {
            描画幅 = 表示幅;
            描画高さ = 表示幅 / 画像縦横比;
            位置調整x = 0;
            位置調整y = (表示高さ - 描画高さ) / 2; // 垂直中央揃え
        } else {
            描画高さ = 表示高さ;
            描画幅 = 表示高さ * 画像縦横比;
            位置調整x = (表示幅 - 描画幅) / 2; // 水平中央揃え
            位置調整y = 0;
        }

        this.x = x1 + 位置調整x;
        this.y = y1 + 位置調整y;
        this.幅 = 描画幅;
        this.高さ = 描画高さ;
    }

    描画する() {
        this.ctx.drawImage(this.画像要素, this.x, this.y, this.幅, this.高さ); // 画像を描画
    }

    移動して描画する(移動幅x, 移動幅y, 停止位置x, 停止位置y) {
        return new Promise(resolve =&gt; {
            this.レイヤー.処理を追加する(this, () =&gt; {
                if (移動幅x) this.x += 移動幅x;
                if (移動幅y) this.y += 移動幅y;
                this.描画する();

                let 停止フラグ = false;
                if (移動幅x) {
                    if (移動幅x &gt; 0) {
                        if (this.x &gt;= 停止位置x) 停止フラグ = true;
                    } else if (移動幅x &lt; 0) {
                        if (this.x &lt;= 停止位置x) 停止フラグ = true;
                    }
                }
                if (移動幅y) {
                    if (移動幅y &gt; 0) {
                        if (this.y &gt;= 停止位置y) 停止フラグ = true;
                    } else if (移動幅y &lt; 0) {
                        if (this.y &lt;= 停止位置y) 停止フラグ = true;
                    }
                }
                if (!停止フラグ) return;

                // 停止位置に来たら描画だけの処理に切替える
                this.レイヤー.処理を追加する(this, this.描画する.bind(this));
                resolve();
            });
        })
    }

    フェードアウトする(フェード時間 = 1) {
        const 減少値 = 1 / (60 * フェード時間); // フェード時間は秒単位とする
        let 不透明度 = 1.0;
        return new Promise(resolve =&gt; {
            this.レイヤー.処理を追加する(this, () =&gt; {
                this.ctx.save(); // 現在の描画状態を保存
                this.ctx.globalAlpha = 不透明度;
                this.描画する();
                this.ctx.restore(); // 元の描画状態を復元
                不透明度 -= 減少値;
                if (不透明度 &gt; 0) return;

                // 不透明度が0%になったら描画処理を削除する
                this.レイヤー.処理を削除する(this);
                resolve();
            });
        })
    }

    フェードインする(フェード時間 = 1) {
        const 増加値 = 1 / (60 * フェード時間); // フェード時間は秒単位とする
        let 不透明度 = 0.0;
        return new Promise(resolve =&gt; {
            this.レイヤー.処理を追加する(this, () =&gt; {
                this.ctx.save(); // 現在の描画状態を保存
                this.ctx.globalAlpha = 不透明度;
                this.描画する();
                this.ctx.restore(); // 元の描画状態を復元
                不透明度 += 増加値;
                if (不透明度 &lt; 1) return;

                // 不透明度が100%になったら描画だけの処理に切替える
                this.レイヤー.処理を追加する(this, this.描画する.bind(this));
                resolve();
            });
        })
    }
}
</code></pre>
<h4 class="heading-33"><span>追加したコードについて</span></h4>
<div class="本文">
<p class="bold">フェードアウト：</p>
<pre class="code"><code>    フェードアウトする(フェード時間 = 1) {
        const 減少値 = 1 / (60 * フェード時間); // フェード時間は秒単位とする
        let 不透明度 = 1.0;
        return new Promise(resolve =&gt; {
            this.レイヤー.処理を追加する(this, () =&gt; {
                this.ctx.save(); // 現在の描画状態を保存
                this.ctx.globalAlpha = 不透明度;
                this.描画する();
                this.ctx.restore(); // 元の描画状態を復元
                不透明度 -= 減少値;
                if (不透明度 &gt; 0) return;

                // 不透明度が0%になったら描画処理を削除する
                this.レイヤー.処理を削除する(this);
                resolve();
            });
        })
    }
</code></pre>
<ol class="箇条書き1">
<li><span class="bold">処理の流れ:</span>
<ul class="箇条書き1">
<li>最初は画像が完全に表示されています（不透明度 = 1.0）。</li>
<li>徐々に 不透明度 を減少（1フレームごとに少しずつ）させます。</li>
<li>完全に透明になったら処理を終了します。</li>
</ul>
</li>
<li><span class="bold">ポイント:</span>
<ul class="箇条書き1">
<li>ctx.globalAlpha を使って、描画時の透明度を設定しています。</li>
<li>this.ctx.save() と this.ctx.restore() を使用することで、他の描画操作に影響が出ないようにしています。</li>
</ul>
</li>
</ol>
<p class="bold">フェードイン：</p>
<pre class="code"><code>    フェードインする(フェード時間 = 1) {
        const 増加値 = 1 / (60 * フェード時間); // フェード時間は秒単位とする
        let 不透明度 = 0.0;
        return new Promise(resolve =&gt; {
            this.レイヤー.処理を追加する(this, () =&gt; {
                this.ctx.save(); // 現在の描画状態を保存
                this.ctx.globalAlpha = 不透明度;
                this.描画する();
                this.ctx.restore(); // 元の描画状態を復元
                不透明度 += 増加値;
                if (不透明度 &lt; 1) return;

                // 不透明度が100%になったら描画だけの処理に切替える
                this.レイヤー.処理を追加する(this, this.描画する.bind(this));
                resolve();
            });
        })
    }
</code></pre>
<ol class="箇条書き1">
<li><span class="bold">処理の流れ：</span>
<ul class="箇条書き1">
<li>最初は画像が完全に透明な状態から始まります（不透明度 = 0.0）。</li>
<li>徐々に 不透明度 を増加させ、見える状態にしていきます。</li>
<li>不透明度が 1.0 になったら処理を終了します。</li>
</ul>
</li>
<li><span class="bold">ポイント：</span>
<ul class="箇条書き1">
<li>フェードアウトと同様に、ctx.globalAlpha を使用して不透明度を段階的に変更しています。</li>
</ul>
</li>
</ol></div>
<h4 class="heading-33"><span>初心者向けのポイント</span></h4>
<ol class="箇条書き1">
<li><span class="bold">不透明度は時間でコントロール：</span>
<ul class="箇条書き1">
<li>フェード効果は、「何秒以内に透明度を変える」といった具合に、秒で指定できるようにしています（小数点も可）。</li>
<li>1フレーム（このコードでは、約1/60秒）ごとに透明度を少しずつ調整しています。</li>
</ul>
</li>
<li><span class="bold">非同期処理：</span>
<ul class="箇条書き1">
<li>フェード効果を非同期で行う仕組み（Promise）を使うことで、他の処理と平行して行えるようになっています。</li>
</ul>
</li>
</ol>
<h3 class="heading-23">b.　sample.js - サンプルクラス</h3>
<pre class="code"><code>import { 画像管理クラス } from './imageManager.js'; // クラスをインポート
import { スプライトクラス } from './sprite.js'; // クラスをインポート
import { レイヤークラス } from './layer.js'; // クラスをインポート
import { ループ } from './loop.js'; // クラスをインポート

class サンプル {
    static async main() {
        const レイヤー = new レイヤークラス('canvas.レイヤー1');
        const 画像管理 = new 画像管理クラス();
        ループ.初期化する(1000/60);
        ループ.開始する();

        // 事前に読み込む画像の配列
        const 画像情報リスト = [
            { id: '草原', src: 'img/bg01.jpg' },
            { id: '人物01', src: 'img/chara01.png' },
            { id: '炎竜', src: 'img/mon01.png' },
            { id: 'デビル', src: 'img/mon02.png' }
        ];

        // ページ初期化時に画像をプリロード
        if (!await 画像管理.画像を読み込む(画像情報リスト)) return;

        // 画像の描画位置を設定
        const 背景01 = new スプライトクラス(レイヤー, 画像管理.取得する('草原'), 0, 0, 640, 640);
        const 人物01 = new スプライトクラス(レイヤー, 画像管理.取得する('人物01'), 0, 100, 640, 640);
        const モンスター01 = new スプライトクラス(レイヤー, 画像管理.取得する('炎竜'), 0, 0, 640, 540);
        const モンスター02 = new スプライトクラス(レイヤー, 画像管理.取得する('デビル'), 0, 320, 320, 640);
        const モンスター03 = new スプライトクラス(レイヤー, 画像管理.取得する('デビル'), 320, 320, 640, 640);

        ループ.処理を追加する(レイヤー, レイヤー.描画する.bind(レイヤー));
        背景01.レイヤー.処理を追加する(背景01, 背景01.描画する.bind(背景01));

        let プロミスリスト;
        while (1) {
            await 人物01.フェードインする();
            await サンプル.一時停止(2000);

            プロミスリスト = [];
            プロミスリスト.push(人物01.フェードアウトする(2.5));
            プロミスリスト.push(モンスター01.フェードインする(4));
            プロミスリスト.push(モンスター02.フェードインする(3));
            プロミスリスト.push(モンスター03.フェードインする(1.5));
            await Promise.all(プロミスリスト);
            await サンプル.一時停止(2000);

            await モンスター02.フェードアウトする();
            await サンプル.一時停止(2000);

            プロミスリスト = [];
            プロミスリスト.push(モンスター01.フェードアウトする(1.5));
            プロミスリスト.push(モンスター03.フェードアウトする(3));
            await Promise.all(プロミスリスト);
            await サンプル.一時停止(2000);
        }
    }

    static 一時停止(時間) {
        return new Promise(resolve =&gt; setTimeout(resolve, 時間));
    }
}

addEventListener('load', サンプル.main);
</code></pre>
<h4 class="heading-33"><span>このコードの全体の流れ</span></h4>
<div class="本文"><ol class="箇条書き1">
<li><span class="bold">画像を読み込む：</span>
<ul class="箇条書き1">
<li>必要な画像を事前にメモリへロードします（画像管理クラスを使用）。</li>
<li>ロード後に各画像をスプライトクラスとして設定し、描画を準備します。</li>
</ul>
</li>
<li><span class="bold">アニメーションの管理：</span>
<ul class="箇条書き1">
<li>ループを使って、画面内の描画やアニメーション（フェードイン/アウト）を繰り返します。</li>
</ul>
</li>
<li><span class="bold">フェード処理を実行：</span>
<ul class="箇条書き1">
<li>人物 や モンスター 画像をフェードインまたはフェードアウトさせ、アニメーションを構成します。</li>
</ul>
</li>
<li><span class="bold">一時停止（待機）：</span>
<ul class="箇条書き1">
<li>指定時間だけ処理を止めることで、画面切り替えのタイミングを調整します。</li>
</ul>
</li>
</ol></div>
<h4 class="heading-33"><span>主要なポイントの解説</span></h4>
<div class="本文"><ol class="箇条書き1">
<li><span class="bold">画像のプリロード：</span>
<ul class="箇条書き1">
<li><span class="bold">目的：</span>画面をスムーズに表示するため、使用する画像を事前に読み込みます。
<pre class="code"><code>const 画像情報リスト = [
    { id: '草原', src: 'img/bg01.jpg' },
    { id: '人物01', src: 'img/chara01.png' },
    { id: '炎竜', src: 'img/mon01.png' },
    { id: 'デビル', src: 'img/mon02.png' }
];
await 画像管理.画像を読み込む(画像情報リスト);
</code></pre>
</li>
<li><span class="bold">ポイント：</span>
<ul class="箇条書き1">
<li>src は画像ファイルのパス、id はその画像を区別するための名前です。</li>
<li>この処理が完了するまで次の処理には進みません（await の利用）。</li>
</ul>
</li>
</ul>
</li>
<li><span class="bold">画像の描画と配置：</span>
<ul class="箇条書き1">
<li><span class="bold">目的：</span>画像の表示サイズや位置を設定します。
<pre class="code"><code>const 背景01 = new スプライトクラス(レイヤー, 画像管理.取得する('草原'), 0, 0, 640, 640);
const 人物01 = new スプライトクラス(レイヤー, 画像管理.取得する('人物01'), 0, 100, 640, 640);
</code></pre>
</li>
<li><span class="bold">ポイント：</span>
<ul class="箇条書き1">
<li>スプライトクラス は画像をキャンバス上に描画するためのクラスです。</li>
<li>x1, y1, x2, y2 は画像を配置する位置とサイズを指定しています。</li>
</ul>
</li>
</ul>
</li>
<li><span class="bold">フェード処理：</span>
<ul class="箇条書き1">
<li><span class="bold">目的：</span>画像の表示サイズや位置を設定します。
<pre class="code"><code>await 人物01.フェードインする();
</code></pre>
</li>
<li><span class="bold">ポイント：</span>
<ul class="箇条書き1">
<li>await を使うことで、フェードインが完全に終わるまで待機します。</li>
<li>フェードアウトも同様の構文で実現できます。</li>
</ul>
</li>
</ul>
</li>
<li><span class="bold">同時処理の実行：</span>
<ul class="箇条書き1">
<li><span class="bold">目的：</span>複数の画像が同時にフェードするアニメーションを作ります。
<pre class="code"><code>プロミスリスト = [];
プロミスリスト.push(人物01.フェードアウトする(2.5));
プロミスリスト.push(モンスター01.フェードインする(4));
プロミスリスト.push(モンスター02.フェードインする(3));
プロミスリスト.push(モンスター03.フェードインする(1.5));
await Promise.all(プロミスリスト);
</code></pre>
</li>
<li><span class="bold">ポイント：</span>
<ul class="箇条書き1">
<li>Promise.all を使うことで、すべてのフェード処理を並行して実行します。</li>
<li>フェードの時間はそれぞれ異なります（例: 2.5秒 や 4秒）。</li>
</ul>
</li>
</ul>
</li>
<li><span class="bold">一時停止：</span>
<ul class="箇条書き1">
<li><span class="bold">目的：</span>動作の切り替わりが分かるように、少しだけ一時停止しています。
<pre class="code"><code>await サンプル.一時停止(2000);
</code></pre>
</li>
<li><span class="bold">ポイント：</span>
<ul class="箇条書き1">
<li>単純に指定したミリ秒（2000ミリ秒 = 2秒）待機するだけの処理です。</li>
</ul>
</li>
</ul>
</li>
</ol></div>
<!--shinobi1-->
<script type="text/javascript" src="//xa.shinobi.jp/ufo/191907702"></script>
<noscript><a href="//xa.shinobi.jp/bin/gg?191907702" target="_blank"><img src="//xa.shinobi.jp/bin/ll?191907702" border="0"></a><br><span style="font-size:9px"><img style="margin:0;vertical-align:text-bottom;" src="//img.shinobi.jp/tadaima/fj.gif" width="19" height="11"> </span></noscript><!--shinobi2--></div>]]></content:encoded>
    <dc:subject>JavaScript紹介</dc:subject>
    <dc:date>2025-03-20T07:02:30+09:00</dc:date>
    <dc:creator>No Name Ninja</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>No Name Ninja</dc:rights>
  </item>
  <item rdf:about="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E7%94%BB%E5%83%8F%E3%82%92%E7%A7%BB%E5%8B%95%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95">
    <link>https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E7%94%BB%E5%83%8F%E3%82%92%E7%A7%BB%E5%8B%95%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95</link>
    <title>画像を移動する方法</title>
    <description>


次は画像を移動する方法を記します。
人物やモンスターの画像を上下左右斜め方向に移動して描画しています。
前回の「画像を表示する方法」を元に、少し変更を加えています。



01　ファイル構成

それでは処理を見ていきます。
先ずはファイル構成です。
ファイルとそれを入れるフォルダーを以下のよう...</description>
    <content:encoded><![CDATA[<div class="本文">
<div class="本文">
<ul class="箇条書き1">
<li>次は画像を移動する方法を記します。</li>
<li>人物やモンスターの画像を上下左右斜め方向に移動して描画しています。</li>
<li>前回の「画像を表示する方法」を元に、少し変更を加えています。</li>
</ul>
</div>
<div class="iframe-container"><iframe width="670" height="730" style="border: 0;" src="https://cf033538.cloudfree.jp/Game/sample02/sample.html"></iframe></div>
<h2 class="heading-018">01　ファイル構成</h2>
<div class="本文">
<p>それでは処理を見ていきます。<br />
先ずはファイル構成です。<br />
ファイルとそれを入れるフォルダーを以下のような構成します。</p>
</div>
<div class="ファイル構成">
<ul class="list-13">
<li><span>sample02</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample02/sample.html" target="_blank">sample.html</a></li>
<li><span>js</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample02/js/sample.js" target="_blank">sample.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample02/js/imageManager.js" target="_blank">imageManager.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample02/js/sprite.js" target="_blank">sprite.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample02/js/layer.js" target="_blank">layer.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample02/js/loop.js" target="_blank">loop.js</a></li>
</ul>
</li>
<li><span>img</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample02/img/bg01.jpg" target="_blank">bg01.jpg　※背景画像（720x720px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample02/img/chara01.png" target="_blank">chara01.png　※人物画像（1024x1024px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample02/img/mon01.png" target="_blank">mon01.png　※モンスター画像（1024x1024px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample02/img/mon02.png" target="_blank">mon02.png　※モンスター画像（1024x1024px）</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<h2 class="heading-018">02　ファイル全体の流れ</h2>
<div class="本文">
<p>コード全体で行おうとしていることは以下の通りです。</p>
<ol class="箇条書き1">
<li>HTMLファイルに埋め込まれた &lt;canvas&gt; 要素に対して、JavaScriptを使って画像を描画します。</li>
<li>画像管理クラス を使って画像をあらかじめ読み込みます（プリロード処理）。</li>
<li>読み込んだ画像を スプライトクラス を使って座標を移動して描画します。</li>
<li>レイヤークラス は &lt;canvas&gt; 要素をクリアしてから スプライトクラス の描画処理を実行します。</li>
<li>ループクラス はフレームレートのタイミングで レイヤークラス の描画処理を繰り返し実行します。</li>
</ol>
<p>これにより、スプライトクラス の描画処理が繰り返し実行され、移動し続ける画像を表示できるようになります。</p>
</div>
<h2 class="heading-018">03　各部分の詳細解説</h2>
<div class="本文">
<p>次は各ファイル毎に解説していきます。<br />
尚、「imageManager.js」については、前回の「画像を表示する方法」から変更がないので割愛します。</p>
</div>
<h3 class="heading-23">a.　sample.html - HTMLファイル</h3>
<pre class="code"><code>&lt;!DOCTYPE html&gt;
&lt;html lang="ja"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=660,user-scalable=no,shrink-to-fit=yes"&gt;
    &lt;title&gt;画像を移動する方法&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;style&gt;
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            margin: 0;
            padding: 0;
            background-color: #f4f4f4;
        }
    
        canvas {
            display: block;
            margin: 20px auto;
            border: 1px solid #ccc;
        }
    
        p {
            font-size: 18px;
            color: #333;
        }
    &lt;/style&gt;
    
    &lt;p&gt;
        リフレッシュレート：&lt;span class="リフレッシュレート"&gt;0&lt;/span&gt;Hz
        ／フレームレート：&lt;span class="フレームレート"&gt;0&lt;/span&gt;fps
    &lt;/p&gt;
    &lt;canvas class="レイヤー1" width="640" height="640"&gt;&lt;/canvas&gt;
    &lt;script type="module" src="js/sample.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<div class="本文">
<p>このファイルでは、以下のことを行っています。</p>
<ul class="箇条書き1">
<li><span class="bold">リフレッシュレートとフレームレートの表示：</span>ウェブページに描画処理のパフォーマンス（Hzやfps）を表示するためのテキスト。</li>
<li><span class="bold">キャンバスの作成：</span>&lt;canvas&gt;タグを使って、図形や画像を描画する領域を作成しています。ここでは、幅640px、高さ640pxのキャンバスを作っています。</li>
<li><span class="bold">JavaScriptの読み込み：</span>&lt;script type="module" src="js/sample.js"&gt;&lt;/script&gt;で外部のJavaScriptコード（sample.js）を読み込んでいます。</li>
</ul>
<p class="bold">初心者向けのポイント：</p>
<ul class="箇条書き1">
<li>キャンバスは画面上に見える「お絵かきエリア」みたいなものです。</li>
<li>JavaScriptを使うことで、動的に画像を描画したり、動かしたりできます。</li>
</ul>
</div>
<h3 class="heading-23">b.　layer.js - レイヤークラス</h3>
<pre class="code"><code>export class レイヤークラス {
    constructor(セレクター) {
        this.canvas = document.querySelector(セレクター);
        this.ctx = this.canvas.getContext('2d');
        this.処理リスト = [];
    }

    描画する() {
        this.クリアする();

        // ループ中に処理リストの処理が削除されてもいいように逆順でループします
        for (let i = this.処理リスト.length - 1; i &gt;= 0; i--) {
            this.処理リスト[i].処理();
        }
    }

    クリアする() {
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    }

    処理を追加する(id, 処理) {
        const 既存処理 = this.処理リスト.find(x =&gt; x.id == id);
        if (既存処理) {
            既存処理.処理 = 処理; // 既にある場合は差し替える
            return;
        }

        this.処理リスト.unshift({ id, 処理 });
    }

    処理を削除する(id) {
        this.処理リスト = this.処理リスト.filter(x =&gt; x.id != id);
    }
}
</code></pre>
<div class="本文">
<p>レイヤークラスは、Canvas要素（キャンバス）で画像や図形を描画するための管理クラスです。</p>
</div>
<div class="本文">
<p class="bold">主な機能：</p>
<ul class="箇条書き1">
<li><span class="bold">キャンバスの初期化：</span>指定されたセレクター（例: .レイヤー1）からキャンバス要素を取得し、2D描画コンテキスト（ctx）を準備します。</li>
<li><span class="bold">描画処理：</span>登録された処理（処理リスト）を順番に実行して、キャンバスに描画します。</li>
<li><span class="bold">キャンバスをクリアする：</span>クリアするメソッドでキャンバスの中身を消去します。</li>
</ul>
</div>
<pre class="code"><code>const レイヤー = new レイヤークラス('.レイヤー1'); 
// 上記はキャンバス（.レイヤー1）を管理する新しいレイヤーを作成します。
</code></pre>
<h3 class="heading-23">c.　sprite.js - スプライトクラス</h3>
<pre class="code"><code>export class スプライトクラス {
    constructor(レイヤー, 画像要素, x1, y1, x2, y2) {
        this.レイヤー = レイヤー;
        this.ctx = レイヤー.ctx;
        this.画像要素 = 画像要素;
        this.レイヤー.処理を追加する(this, this.描画する.bind(this));
        this.座標を設定する(x1, y1, x2, y2);
    }

    座標を設定する(x1, y1, x2, y2) {
        const 画像要素 = this.画像要素;
        const 表示幅 = x2 - x1;
        const 表示高さ = y2 - y1;

        const 画像縦横比 = 画像要素.width / 画像要素.height;
        const 表示縦横比 = 表示幅 / 表示高さ;

        let 描画幅, 描画高さ, 位置調整X, 位置調整Y;

        if (画像縦横比 &gt; 表示縦横比) {
            描画幅 = 表示幅;
            描画高さ = 表示幅 / 画像縦横比;
            位置調整X = 0;
            位置調整Y = (表示高さ - 描画高さ) / 2; // 垂直中央揃え
        } else {
            描画高さ = 表示高さ;
            描画幅 = 表示高さ * 画像縦横比;
            位置調整X = (表示幅 - 描画幅) / 2; // 水平中央揃え
            位置調整Y = 0;
        }

        this.x = x1 + 位置調整X;
        this.y = y1 + 位置調整Y;
        this.幅 = 描画幅;
        this.高さ = 描画高さ;
    }

    描画する() {
        this.ctx.drawImage(this.画像要素, this.x, this.y, this.幅, this.高さ); // 画像を描画
    }

    移動して描画する(移動幅x, 移動幅y, 停止位置x, 停止位置y) {
        return new Promise(resolve =&gt; {
            this.レイヤー.処理を追加する(this, () =&gt; {
                if (移動幅x) this.x += 移動幅x;
                if (移動幅y) this.y += 移動幅y;
                this.描画する();

                let 停止フラグ = false;
                if (移動幅x) {
                    if (移動幅x &gt; 0) {
                        if (this.x &gt;= 停止位置x) 停止フラグ = true;
                    } else if (移動幅x &lt; 0) {
                        if (this.x &lt;= 停止位置x) 停止フラグ = true;
                    }
                }
                if (移動幅y) {
                    if (移動幅y &gt; 0) {
                        if (this.y &gt;= 停止位置y) 停止フラグ = true;
                    } else if (移動幅y &lt; 0) {
                        if (this.y &lt;= 停止位置y) 停止フラグ = true;
                    }
                }
                if (!停止フラグ) return;

                // 停止位置に来たら描画だけの処理に切替える
                this.レイヤー.処理を追加する(this, this.描画する.bind(this));
                resolve();
            });
        })
    }
}
</code></pre>
<div class="本文">
<p>スプライトクラスは、画面上の画像（スプライト）を管理するためのクラスです。たとえば、キャラクターや背景画像を表示したり動かしたりする処理を提供します。</p>
</div>
<div class="本文">
<p class="bold">主な機能：</p>
<ul class="箇条書き1">
<li><span class="bold">座標を設定：</span>画像の位置（x, y）やサイズ（幅、高さ）を設定します。</li>
<li><span class="bold">描画：</span>キャンバス上に画像を描画します。</li>
<li><span class="bold">移動アニメーション：</span>指定した速さや方向に画像を移動しながら描画します。</li>
</ul>
</div>
<pre class="code"><code>const 人物01 = new スプライトクラス(レイヤー, 画像, x1, y1, x2, y2);
// 人物01というスプライトを作成し、レイヤー上に表示します。
</code></pre>
<h3 class="heading-23">d.　loop.js - ループクラス</h3>
<pre class="code"><code>export class ループ {
    static 初期化する(フレームレート) {
        ループ.処理リスト = [];
        ループ.リフレッシュ時刻;
        ループ.処理時刻;
        ループ.リフレッシュカウンタ = 0;
        ループ.処理カウンタ = 0;
        ループ.フレームレート = フレームレート | 1000 / 60;
        ループ.リフレッシュレート要素 = document.querySelector(".リフレッシュレート");
        ループ.フレームレート要素 = document.querySelector(".フレームレート");
    }

    static 開始する() {
        ループ.処理時刻 = ループ.リフレッシュ時刻 = Date.now();
        ループ.する();
    }

    static する() {
        ループ.処理を実行する();
        requestAnimationFrame(ループ.する);
    }

    static 処理を実行する() {
        const 現時刻 = Date.now();
        if (現時刻 - ループ.リフレッシュ時刻 &lt; 1000) {
            ループ.リフレッシュカウンタ++;
        } else {
            ループ.リフレッシュ時刻 = 現時刻;
            ループ.リフレッシュレート要素.innerHTML = ループ.リフレッシュカウンタ;
            ループ.フレームレート要素.innerHTML = ループ.処理カウンタ;
            ループ.リフレッシュカウンタ = 0;
            ループ.処理カウンタ = 0;
        }

        if (現時刻 - ループ.処理時刻 &lt; ループ.フレームレート) return;
        ループ.処理時刻 += ループ.フレームレート;
        ループ.処理カウンタ++;

        // ループ中に処理リストの処理が削除されてもいいように逆順でループします
        for (let i = ループ.処理リスト.length - 1; i &gt;= 0; i--) {
            ループ.処理リスト[i].処理();
        }
    }

    static 処理を追加する(id, 処理) {
        const 既存処理 = ループ.処理リスト.find(x =&gt; x.id == id);
        if (既存処理) {
            既存処理.処理 = 処理; // 既にある場合は差し替える
            return;
        }

        ループ.処理リスト.push({ id, 処理 });
    }

    static 処理を削除する(id) {
        ループ.処理リスト = ループ.処理リスト.filter(x =&gt; x.id != id);
    }
}
</code></pre>
<div class="本文">
<p>ループクラスは、アニメーションを管理するためのメインループを提供します。アニメーションとは、画像を動かしたり、複数の処理を一定の時間間隔で繰り返すことを指します。</p>
</div>
<div class="本文">
<p class="bold">主な機能：</p>
<ul class="箇条書き1">
<li><span class="bold">処理を管理：</span>アニメーションに必要な複数の処理をリストとして登録し、順番に実行します。</li>
<li><span class="bold">一定のフレームレートで実行：</span>滑らかな動きを実現するために、1秒間に60回（または指定のレート）処理を呼び出します。</li>
</ul>
</div>
<pre class="code"><code>ループ.初期化する();
ループ.開始する();
ループ.処理を追加する(レイヤー, レイヤー.描画する.bind(レイヤー));
// アニメーションを開始し、レイヤーの描画をループ内で実行します。
</code></pre>
<h3 class="heading-23">e.　sample.js - サンプルクラス</h3>
<pre class="code"><code>import { 画像管理クラス } from './imageManager.js'; // クラスをインポート
import { スプライトクラス } from './sprite.js'; // クラスをインポート
import { レイヤークラス } from './layer.js'; // クラスをインポート
import { ループ } from './loop.js'; // クラスをインポート

class サンプル {
    static async main() {
        const レイヤー = new レイヤークラス('canvas.レイヤー1');
        const 画像管理 = new 画像管理クラス();
        ループ.初期化する(1000/60);
        ループ.開始する();

        // 事前に読み込む画像の配列
        const 画像情報リスト = [
            { id: '草原', src: 'img/bg01.jpg' },
            { id: '人物01', src: 'img/chara01.png' },
            { id: '炎竜', src: 'img/mon01.png' },
            { id: 'デビル', src: 'img/mon02.png' }
        ];

        // ページ初期化時に画像をプリロード
        if (!await 画像管理.画像を読み込む(画像情報リスト)) return;

        // 画像の描画位置を設定
        const 背景01 = new スプライトクラス(レイヤー, 画像管理.取得する('草原'), 0, 0, 640, 640);

        const 人物01 = new スプライトクラス(レイヤー, 画像管理.取得する('人物01'), 0, 100, 640, 640);
        const 人物01正位置 = { x: 人物01.x, y: 人物01.y };
        人物01.座標を設定する(640, 100, 1280, 640); //初期表示位置を設定する

        const モンスター01 = new スプライトクラス(レイヤー, 画像管理.取得する('炎竜'), 0, 0, 640, 540);
        const モンスター01正位置 = { x: モンスター01.x, y: モンスター01.y };
        モンスター01.座標を設定する(-640, 0, 0, 540); //初期表示位置を設定する

        const モンスター02 = new スプライトクラス(レイヤー, 画像管理.取得する('デビル'), 0, 320, 320, 640);
        const モンスター02正位置 = { x: モンスター02.x, y: モンスター02.y };
        モンスター02.座標を設定する(640, -640, 960, 320); //初期表示位置を設定する

        const モンスター03 = new スプライトクラス(レイヤー, 画像管理.取得する('デビル'), 320, 320, 640, 640);
        const モンスター03正位置 = { x: モンスター03.x, y: モンスター03.y };
        モンスター03.座標を設定する(-320, -640, 0, 320); //初期表示位置を設定する

        ループ.処理を追加する(レイヤー, レイヤー.描画する.bind(レイヤー));

        let プロミスリスト;
        while (1) {
            await 人物01.移動して描画する(-40, 0, 人物01正位置.x, 0);
            await サンプル.一時停止(2000);

            プロミスリスト = [];
            プロミスリスト.push(人物01.移動して描画する(40, 0, 640, 0));
            プロミスリスト.push(モンスター01.移動して描画する(5, 0, モンスター01正位置.x, 0));
            プロミスリスト.push(モンスター02.移動して描画する(-20, 20, モンスター02正位置.x, モンスター02正位置.y));
            プロミスリスト.push(モンスター03.移動して描画する(10, 10, モンスター03正位置.x, モンスター03正位置.y));
            await Promise.all(プロミスリスト);
            await サンプル.一時停止(2000);

            プロミスリスト = [];
            プロミスリスト.push(モンスター01.移動して描画する(0, 10, 0, 640));
            プロミスリスト.push(モンスター02.移動して描画する(0, 5, 0, 640));
            プロミスリスト.push(モンスター03.移動して描画する(0, 20, 0, 640));
            await Promise.all(プロミスリスト);
            await サンプル.一時停止(2000);

            モンスター01.座標を設定する(-640, 0, 0, 540); //初期表示位置を設定する
            モンスター02.座標を設定する(640, -640, 960, 320); //初期表示位置を設定する
            モンスター03.座標を設定する(-320, -640, 0, 320); //初期表示位置を設定する
        }
    }

    static 一時停止(時間) {
        return new Promise(resolve =&gt; setTimeout(resolve, 時間));
    }
}

addEventListener('load', サンプル.main);
</code></pre>
<div class="本文">
<p>サンプルクラスは、これらのクラスを組み合わせて具体的な処理（ゲームやアニメーション）を実現する部分です。</p>
</div>
<div class="本文">
<p class="bold">主な処理：</p>
<ul class="箇条書き1">
<li><span class="bold">画像のプリロード：</span>画像を事前に読み込むことで、スムーズな描画を実現します。</li>
<li><span class="bold">スプライトの作成とアニメーション：</span>スプライトをレイヤーに追加し、一定の方向に動かすアニメーションを行います。</li>
<li><span class="bold">一時停止と再開：</span>awaitを使用して、一定時間停止した後に次のアニメーションを実行します。</li>
</ul>
</div>
<pre class="code"><code>await サンプル.一時停止(2000); 
// 2000ミリ秒（2秒）待ってから次の処理を実行します。
</code></pre>
<h3 class="heading-23">f.　初心者向けまとめ</h3>
<ul class="箇条書き1">
<li>キャンバスは「描画用の黒板」のようなものです。</li>
<li>レイヤーは「黒板を管理する管理人」で、黒板消しを持っています。</li>
<li>スプライトは「黒板の上を動くキャラクターや背景」で、黒板消しは持っていないため、他のスプライトが描いたものに上書きすることはあっても、消すことはありません。</li>
<li>ループは「描画を永遠に繰り返す仕組み」です。</li>
<li>サンプルクラスで全てをつなぎ、画像の移動や停止、再開をコントロールします。</li>
</ul>
<!--shinobi1-->
<script type="text/javascript" src="//xa.shinobi.jp/ufo/191907701"></script>
<noscript><a href="//xa.shinobi.jp/bin/gg?191907701" target="_blank"><img src="//xa.shinobi.jp/bin/ll?191907701" border="0"></a><br><span style="font-size:9px"><img style="margin:0;vertical-align:text-bottom;" src="//img.shinobi.jp/tadaima/fj.gif" width="19" height="11"> </span></noscript><!--shinobi2--></div>]]></content:encoded>
    <dc:subject>JavaScript紹介</dc:subject>
    <dc:date>2025-03-19T01:15:03+09:00</dc:date>
    <dc:creator>No Name Ninja</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>No Name Ninja</dc:rights>
  </item>
  <item rdf:about="https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E7%94%BB%E5%83%8F%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95">
    <link>https://cript.game-ss.com/javascript%E7%B4%B9%E4%BB%8B/%E7%94%BB%E5%83%8F%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95</link>
    <title>画像を表示する方法</title>
    <description>


Webブラウザのゲームを作る上で重要になる処理として、画像を表示する方法を記します。
以下の画像は背景と人物の2枚の画像を重ねて表示しています。
背景画像のサイズは480x480pxですが、640x640pxの領域に拡大して表示しています。
人物画像は1024x1024pxですが、少し横長の6...</description>
    <content:encoded><![CDATA[<div class="本文">
<div class="本文">
<ul class="箇条書き1">
<li>Webブラウザのゲームを作る上で重要になる処理として、画像を表示する方法を記します。</li>
<li>以下の画像は背景と人物の2枚の画像を重ねて表示しています。</li>
<li>背景画像のサイズは480x480pxですが、640x640pxの領域に拡大して表示しています。</li>
<li>人物画像は1024x1024pxですが、少し横長の640x540pxの領域に縮小かつ中央にして表示しています。</li>
<li>このように、これから記す方法は画像を指定した領域に拡大したり、または縮小して表示することができます。</li>
<li>また、JavaScriptで行っているのでゲーム内の好きなタイミングで表示したり、別の画像に差し替えたり出来ます。</li>
</ul>
</div>
<div class="iframe-container"><iframe width="656" height="663" style="border: 0;" src="https://cf033538.cloudfree.jp/Game/sample01/sample.html"></iframe></div>
<h2 class="heading-018">01　ファイル構成</h2>
<div class="本文">
<p>それでは実際に処理を見ていきます。<br />
先ずはファイル構成です。<br />
ファイルとそれを入れるフォルダーを以下のような構成します。</p>
</div>
<div class="ファイル構成">
<ul class="list-13">
<li><span>sample01</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample01/sample.html" target="_blank">sample.html</a></li>
<li><span>js</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample01/js/sample.js" target="_blank">sample.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample01/js/imageManager.js" target="_blank">imageManager.js</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample01/js/sprite.js" target="_blank">sprite.js</a></li>
</ul>
</li>
<li><span>img</span>
<ul>
<li><a href="https://cf033538.cloudfree.jp/Game/sample01/img/statue.jpg" target="_blank">statue.jpg　※背景画像（480x480px）</a></li>
<li><a href="https://cf033538.cloudfree.jp/Game/sample01/img/chara_L.png" target="_blank">chara_L.png　※人物画像（1024x1024px）</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<h2 class="heading-018">02　ファイル全体の流れ</h2>
<div class="本文">
<p>コード全体で行おうとしていることは以下の通りです。</p>
<ol class="箇条書き1">
<li>HTMLファイルに埋め込まれた &lt;canvas&gt; 要素に対して、JavaScriptを使って画像を描画します。</li>
<li>画像管理クラス を使って画像をあらかじめ読み込みます（プリロード処理）。</li>
<li>読み込んだ画像を スプライトクラス を使って描画します。</li>
</ol>
<p>これにより、動的にゲーム画面やイラストを操作する仕組みが出来上がります。</p>
</div>
<h2 class="heading-018">03　各部分の詳細解説</h2>
<h3 class="heading-23">a.　sample.html - HTMLファイル</h3>
<pre class="code"><code>&lt;!DOCTYPE html&gt;
&lt;html lang="ja"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    &lt;title&gt;画像を表示する方法&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;canvas class="レイヤー1" width="640" height="640"&gt;&lt;/canvas&gt;
    &lt;script type="module" src="js/sample.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<div class="本文">
<p>HTMLファイルは、 &lt;canvas&gt; という描画領域を作るための要素を用意しています：</p>
</div>
<pre class="code"><code>&lt;canvas class="レイヤー1" width="640" height="640"&gt;&lt;/canvas&gt;
</code></pre>
<div class="本文">
<ul class="箇条書き1">
<li>&lt;canvas&gt;の役割<br />

<ul class="箇条書き2">
<li>画面上に「絵を描くためのキャンバス」です。</li>
<li>ここに画像を描画していきます。</li>
</ul>
</li>
</ul>
</div>
<h3 class="heading-23">b.　imageManager.js - 画像管理</h3>
<div class="本文">
<p>このファイルは、「画像を読み込んで管理するためのクラス」を定義しています。</p>
</div>
<pre class="code"><code>export class 画像管理クラス {
    constructor() {
        this.画像キャッシュ = new Map();
    }

    async 画像を読み込む(画像情報リスト) {
        const プロミスリスト = 画像情報リスト.map(画像情報 =&gt; {
            return new Promise((resolve, reject) =&gt; {
                const 画像要素 = new Image();
                画像要素.src = 画像情報.src;

                画像要素.onload = () =&gt; {
                    this.画像キャッシュ.set(画像情報.id, 画像要素);
                    resolve();
                };

                画像要素.onerror = () =&gt; {
                    console.error(`画像が読み込めませんでした：${画像情報.src}`);
                    reject();
                };
            });
        });

        try {
            // 全ての画像が読み込まれるのを待つ
            await Promise.all(プロミスリスト);
            return true;
        } catch {
            return false;// 一つでも読み込めなかった場合
        }
    }

    取得する(id) {
        const 画像要素 = this.画像キャッシュ.get(id);
        if (!画像要素) console.error(`画像キャッシュにありません：${id}`);
        return 画像要素;
    }
}
</code></pre>
<h4 class="heading-33"><span>1. クラスの宣言</span></h4>
<pre class="code"><code>export class 画像管理クラス {
    constructor() {
        this.画像キャッシュ = new Map();
    }
}
</code></pre>
<div class="本文">
<ul class="箇条書き1">
<li>export: このクラスを他のJavaScriptのファイルからも使えるようにしています。</li>
<li>constructor: この部分は、クラスが作られたときに呼ばれる特別な関数です。</li>
<li>this.画像キャッシュ: Mapオブジェクトを使って、画像を保存しておきます。Mapは「キー」と「値」をペアで管理する便利なデータ構造です。</li>
</ul>
</div>
<h4 class="heading-33"><span>2. 画像を読み込む() 関数</span></h4>
<pre class="code"><code>async 画像を読み込む(画像情報リスト) {
    const プロミスリスト = 画像情報リスト.map(画像情報 =&gt; {
        return new Promise((resolve, reject) =&gt; {
            const 画像要素 = new Image();
            画像要素.src = 画像情報.src;
            画像要素.onload = () =&gt; {
                this.画像キャッシュ.set(画像情報.id, 画像要素);
                resolve();
            };
            画像要素.onerror = () =&gt; {
                console.error(`画像が読み込めませんでした：${画像情報.src}`);
                reject();
            };
        });
    });

    try {
        await Promise.all(プロミスリスト);
        return true;
    } catch {
        return false;
    }
}
</code></pre>
<div class="本文">
<ul class="箇条書き1">
<li>この関数の役割:<br />

<ul class="箇条書き2">
<li>複数の画像を「並列処理」で読み込みます。これにより、全ての画像を同時に効率よく読み込むことができます。</li>
<li>画像は読み込み完了後に「画像キャッシュ」に保存されます。</li>
</ul>
</li>
<li>細かい説明:<br />
<ol class="箇条書き2">
<li>画像情報リスト.map():<br />

<ul class="箇条書き3">
<li>画像情報リストの各画像について1つずつPromiseを作ります。</li>
<li>Promiseは「画像の読み込み完了を待たずに進む」という非同期処理を行います。</li>
</ul>
</li>
<li>Promise の内容:<br />

<ul class="箇条書き3">
<li>読み込みたい画像ファイルのパスを指定し、画像要素という新しいImageオブジェクトを作ります。</li>
<li>画像が正常に読み込まれた場合、resolve()を呼び出して成功として動作します。</li>
<li>エラーがあった場合は、reject()を呼び出してエラーとして動作します。</li>
</ul>
</li>
<li>Promise.all():<br />

<ul class="箇条書き3">
<li>全てのPromiseの処理結果を受け取る仕組みです。</li>
<li>どれか1つでもエラーがあれば、全体が失敗として扱われます。</li>
<li>この関数にawaitをつけて、かつ「画像を読み込む()」関数にasyncをつけることで、全てのPromiseの処理結果を待つようになります。</li>
</ul>
</li>
</ol></li>
</ul>
</div>
<h4 class="heading-33"><span>3. 取得する() 関数</span></h4>
<pre class="code"><code>取得する(id) {
    const 画像要素 = this.画像キャッシュ.get(id);
    if (!画像要素) console.error(`画像キャッシュにありません：${id}`);
    return 画像要素;
}
</code></pre>
<div class="本文">
<ul class="箇条書き1">
<li>この関数の役割:<br />

<ul class="箇条書き2">
<li>引数で渡された id を使って、画像キャッシュから特定の画像を取り出します。</li>
<li>見つからない場合はエラーを表示します。</li>
</ul>
</li>
<li>動き方:<br />
<ol class="箇条書き2">
<li>this.画像キャッシュ.get(id) でキャッシュを確認します。</li>
<li>画像があればそれを返し、なければエラーを表示します。</li>
</ol></li>
</ul>
</div>
<h4 class="heading-33"><span>4. 初心者向けのポイント</span></h4>
<div class="本文">
<ul class="箇条書き1">
<li>非同期処理を同期させる (async と await):<br />

<ul class="箇条書き2">
<li>時間がかかる処理（例: サーバーから画像データを取得する処理）を非同期で行っている場合に、その処理を待つために使います。</li>
<li>これにより、非同期の処理を順番どおり（同期的）に実行できるようになります。</li>
</ul>
</li>
<li>Mapオブジェクト:<br />

<ul class="箇条書き2">
<li>キー（ここでは id）を使ってデータを管理できます。</li>
<li>例えば、「キーが "背景画像" のときはこの画像を取り出す」といった処理が簡単に行えます。</li>
</ul>
</li>
</ul>
</div>
<h3 class="heading-23">c.　sprite.js - 描画処理</h3>
<div class="本文">
<p>このファイルは、「画像をキャンバス上の指定した位置に表示するためのクラス」を定義しています。</p>
</div>
<pre class="code"><code>export class スプライトクラス {
    constructor(canvas) {
        this.ctx = canvas.getContext('2d');
    }

    描画する(画像要素, x1, y1, x2, y2) {
        const 表示幅 = x2 - x1;
        const 表示高さ = y2 - y1;

        const 画像縦横比 = 画像要素.width / 画像要素.height;
        const 表示縦横比 = 表示幅 / 表示高さ;

        let 描画幅, 描画高さ, 位置調整X, 位置調整Y;

        if (画像縦横比 &gt; 表示縦横比) {
            描画幅 = 表示幅;
            描画高さ = 表示幅 / 画像縦横比;
            位置調整X = 0;
            位置調整Y = (表示高さ - 描画高さ) / 2; // 垂直中央揃え
        } else {
            描画高さ = 表示高さ;
            描画幅 = 表示高さ * 画像縦横比;
            位置調整X = (表示幅 - 描画幅) / 2; // 水平中央揃え
            位置調整Y = 0;
        }

        this.ctx.drawImage(画像要素, x1 + 位置調整X, y1 + 位置調整Y, 描画幅, 描画高さ); // 画像を描画
    }
}
</code></pre>
<h4 class="heading-33"><span>1. 縦横比を維持して画像を中央揃えにする処理</span></h4>
<pre class="code"><code>if (画像縦横比 &gt; 表示縦横比) {
    // 横長画像の場合
    描画幅 = 表示幅;
    描画高さ = 表示幅 / 画像縦横比;
    位置調整Y = (表示高さ - 描画高さ) / 2; // 垂直中央
} else {
    // 縦長画像の場合
    描画高さ = 表示高さ;
    描画幅 = 表示高さ * 画像縦横比;
    位置調整X = (表示幅 - 描画幅) / 2; // 水平中央
}
</code></pre>
<div class="本文">
<ul class="箇条書き1">
<li>縦横比の計算:<br />

<ul class="箇条書き2">
<li>画像の元々の縦横比を計算し、それを使って適切なサイズに縮小または拡大します。</li>
</ul>
</li>
<li>中央揃え:<br />

<ul class="箇条書き2">
<li>画像の描画位置を調整して、表示領域の中央に配置します。</li>
</ul>
</li>
</ul>
</div>
<h4 class="heading-33"><span>2. 画像を描画する</span></h4>
<pre class="code"><code>this.ctx.drawImage(画像要素, x1 + 位置調整X, y1 + 位置調整Y, 描画幅, 描画高さ);
</code></pre>
<div class="本文">
<ul class="箇条書き1">
<li>drawImage メソッド: 指定した位置（表示したい領域の左上の座標）とサイズ（幅と高さ）に画像を描画します。</li>
</ul>
</div>
<h3 class="heading-23">d.　sample.js - メインの処理</h3>
<pre class="code"><code>import { 画像管理クラス } from './imageManager.js'; // クラスをインポート
import { スプライトクラス } from './sprite.js'; // クラスをインポート

class サンプル {
    static async main() {
        const canvas = document.querySelector('canvas.レイヤー1');
        const スプライト = new スプライトクラス(canvas);
        const 画像管理 = new 画像管理クラス();

        // 事前に読み込む画像の配列
        const 画像情報リスト = [
            { id: '像の背景', src: 'img/statue.jpg' },
            { id: '人物01', src: 'img/chara_L.png' }
        ];

        // ページ初期化時に画像をプリロード
        if (!await 画像管理.画像を読み込む(画像情報リスト)) return;

        // プリロード完了後に画像を描画
        スプライト.描画する(画像管理.取得する('像の背景'), 0, 0, 640, 640);
        スプライト.描画する(画像管理.取得する('人物01'), 0, 100, 640, 640);
    }
}

addEventListener('load', サンプル.main);
</code></pre>
<div class="本文">
<p>以下の流れでコードが進みます：</p>
</div>
<h4 class="heading-33"><span>1. キャンバスと描画に必要なクラスを準備</span></h4>
<pre class="code"><code>const canvas = document.querySelector('canvas.レイヤー1');
const スプライト = new スプライトクラス(canvas);
const 画像管理 = new 画像管理クラス();
</code></pre>
<div class="本文">
<ul class="箇条書き1">
<li>document.querySelector(): HTML内の特定の要素（ここでは &lt;canvas&gt;）を取得します。</li>
<li>スプライトクラス: 画像を描画する役割を持つクラスです。</li>
<li>画像管理クラス: 画像を管理・読み込みするクラスです。</li>
</ul>
</div>
<h4 class="heading-33"><span>2. 画像のプリロード処理</span></h4>
<pre class="code"><code>const 画像情報リスト = [
    { id: '像の背景', src: 'img/statue.jpg' },
    { id: '人物01', src: 'img/chara_L.png' }
];
if (!await 画像管理.画像を読み込む(画像情報リスト)) return;
</code></pre>
<div class="本文">
<ul class="箇条書き1">
<li>画像情報リスト: 読み込む画像のファイル名を指定します。</li>
<li>await 画像管理.画像を読み込む(): すべての画像が読み込まれるまで処理を待ちます。</li>
</ul>
</div>
<h4 class="heading-33"><span>3. 画像の描画処理</span></h4>
<pre class="code"><code>スプライト.描画する(画像管理.取得する('像の背景'), 0, 0, 640, 640);
スプライト.描画する(画像管理.取得する('人物01'), 0, 100, 640, 640);
</code></pre>
<div class="本文">
<ul class="箇条書き1">
<li>スプライト.描画する(): 指定した座標（左上と右下の座標を指定）に画像を描画します。</li>
<li>画像管理.取得する(): 画像キャッシュから指定した画像を取得します。</li>
</ul>
</div>
<!--shinobi1-->
<script type="text/javascript" src="//xa.shinobi.jp/ufo/191907700"></script>
<noscript><a href="//xa.shinobi.jp/bin/gg?191907700" target="_blank"><img src="//xa.shinobi.jp/bin/ll?191907700" border="0"></a><br><span style="font-size:9px"><img style="margin:0;vertical-align:text-bottom;" src="//img.shinobi.jp/tadaima/fj.gif" width="19" height="11"> </span></noscript><!--shinobi2--></div>]]></content:encoded>
    <dc:subject>JavaScript紹介</dc:subject>
    <dc:date>2025-03-16T04:02:04+09:00</dc:date>
    <dc:creator>No Name Ninja</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>No Name Ninja</dc:rights>
  </item>
</rdf:RDF>
