アフィリエイト広告を利用しています

2024年04月22日

アニメーションを表示する方法

以下の3パターンでエフェクト画像のアニメーションを表示します。
1)メイン画面の全体に画像を拡大して中央に表示します(青い光のエフェクト)
2)表示領域を指定して、その表示領域内にそのままの画像サイズで中央に表示します(黄色い光のエフェクト)
3)表示領域を指定して、その表示領域内に収まるように画像を縮小して中央に表示します(雷のエフェクト)

黒い領域をクリックするとエフェクトのアニメーションを表示します。

※エフェクトの画像は「ぴぽや」様(https://pipoya.net/)よりお借りしています。

エフェクト1 エフェクト2 エフェクト3

フォルダー構成

以下の構成でフォルダーを作成し、その下にファイルを置きます。

    Sample03
    • Sample03.html

    • css
      • Sample03.css

    • js
      • Sprite.js ※前頁の「画像を表示する方法」で作成したものと同じ

      • Anime.js

      • Canvas.js

      • Sample03.js

    • img

HTML

Sample03.html

<!DOCTYPE HTML>
<html lang='ja'>
<head>
    <meta charset='utf-8'>
    <meta name="viewport" content="width=device-width" />
    <title>アニメーションを表示する方法</title>
    <link rel="stylesheet" href="css/sample03.css" type="text/css" />
    <script src="js/Canvas.js"></script>
    <script src="js/Sprite.js"></script>
    <script src="js/Anime.js"></script>
    <script src="js/sample03.js"></script>
</head>
<body>
    <div class="sample03">
        <div class="メイン画面">
            <canvas class="レイヤー1" width="640" height="640"></canvas>
        </div>
        <div class="画像">
            <img src="img/pipo-btleffect109f.png" alt="エフェクト1" />
            <img src="img/pipo-btleffect033.png" alt="エフェクト2" />
            <img src="img/pipo-btleffect003.png" alt="エフェクト3" />
        </div>
    </div>
</body>
</html>

19〜21行目で表示する3つの画像ファイルを読み込んでいます。

CSS

Sample03.css

body,div,p,td,th {
    margin: 0;
    padding: 0;
}

.メイン画面 {
    position: relative;
    width: 640px;
    height: 640px;
    background-color: rgba(0, 0, 0);
    margin: 20px auto;
}

canvas {
    position: absolute;
}

.画像 {
    display: none;
}

ファイル名が変わっているだけで、内容は前頁の「画像を表示する方法」で作成したものと同じです。

JavaScript

Anime.js

class アニメーション extends スプライト {
    constructor(canvas) {
        super(canvas);
        this.フレーム終了時関数 = null;
        this.終了フラグ = false;
    }

    画像を設定する(img, 画像の横幅, 画像の縦幅, x1, y1, x2, y2, 拡大フラグ) {
        this.img = img; // 表示する画像のimg要素
        this.imgWidth = 画像の横幅;
        this.imgHeight = 画像の縦幅;
        this.終了フラグ = false;
        this.コマ画像の座標を設定する();
        this.表示座標を設定する(x1, y1, x2, y2, 拡大フラグ);
    }

    コマ画像の座標を設定する() {
        this.フレーム数 = 0;
        this.フレームカウンタ = 0;
        this.imgXList = [];
        this.imgYList = [];
        const 横フレーム数 = Math.floor(this.img.width / this.imgWidth);
        const 縦フレーム数 = Math.floor(this.img.height / this.imgHeight);
        for (let i = 0; i < 縦フレーム数; i++) {
            for (let j = 0; j < 横フレーム数; j++) {
                this.imgXList.push(j * this.imgWidth);
                this.imgYList.push(i * this.imgHeight);
                this.フレーム数++;
            }
        }
    }

    更新する() {
        if (this.終了フラグ) return;

        if (this.フレームカウンタ >= this.フレーム数) {
            this.終了フラグ = true;
            if (this.フレーム終了時関数) {
                this.フレーム終了時関数();
            }
            return;
        }

        this.imgX = this.imgXList[this.フレームカウンタ];
        this.imgY = this.imgYList[this.フレームカウンタ];
        this.フレームカウンタ++;

        // コマ画像をコンテクストの座標に表示する
        this.ctx.drawImage(this.img, this.imgX, this.imgY, this.imgWidth, this.imgHeight, this.ctxX, this.ctxY, this.ctxWidth, this.ctxHeight);
    }
}

1行目でわかるとおり、アニメーションクラスは前頁で作成したスプライトクラスから派生しています。
スプライトクラスには画像を表示させる座標の設定を行う処理はありますが、画像のどの部分を表示させるかを設定する処理はありません。
そのため、アニメーションクラスではその処理を追加します。

13行目で、コマ画像(アニメーションの1コマの画像)の座標を設定する関数をコールしています。
その関数では、1コマの画像の横幅と縦幅からフレーム数を計算して、各コマ画像の座標を設定しています。

36行目で、最後のコマ画像を表示し終えている場合は、終了フラグをtrueにして、以降は何も表示しないようにします。
38行目で、フレーム終了時関数(コールバック関数)が指定されている場合は、その関数をコールします。
44〜45行目で、フレームカウンタに対応したコマ画像の座標を設定します。
49行目でコマ画像を表示座標に表示します。

Canvas.js

class Canvas {
    constructor(canvas, 更新間隔 = 0) {
        this.canvas = document.querySelector(canvas);
        this.ctx = this.canvas.getContext('2d');
        this.更新間隔 = 更新間隔;
        this.更新カウンタ = 0;
        this.更新関数リスト = [];
        this.更新停止フラグ = true;
        this.クリック時コールバック関数 = null;
        this.canvas.onclick = this.クリック時関数.bind(this);
    }

    更新関数を追加する(関数) {
        this.更新関数リスト.push(関数);
    }

    更新する() {
        if (this.更新停止フラグ) return;
        if (this.更新カウンタ++ > 0) {
            if (this.更新カウンタ >= this.更新間隔) {
                this.更新カウンタ = 0;
            }
            return;
        }

        this.クリアする();
        for (let i = 0; i < this.更新関数リスト.length; i++) {
            this.更新関数リスト[i]();
        }
    }

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

    更新を開始する() {
        this.更新停止フラグ = false;
        this.更新カウンタ = 0;
    }

    更新を停止する() {
        this.更新停止フラグ = true;
    }

    クリック時関数(evt) {
        if (this.クリック時コールバック関数) {
            this.クリック時コールバック関数(evt);
        }
    }
}

Canvasクラスは、更新間隔ごとにコンテクストをクリアして、コンテクストに描画する関数をコールします。
アニメーションのオブジェクトを更新する処理はこのクラスのオブジェクトからコールします。

14行目で、アニメーションのオブジェクトを更新する処理を更新関数リストに追加しています。

26行目で、コンテクストをクリアし、27〜29行目でアニメーションのオブジェクトを更新する処理を全てコールします。

45行目の関数は、canvas要素をクリックした時にコールされます。
クリック時コールバック関数が指定してあれば、その関数をコールします。

Sample03.js

class Sample03 {
    static main() {
        Sample03.画像リスト = document.querySelectorAll('.sample03 .画像 img');
        Sample03.レイヤー1 = new Canvas(".sample03 .レイヤー1", 5);
        Sample03.レイヤー1.クリック時コールバック関数 = Sample03.アニメーションを開始する;

        Sample03.エフェクト画像 = new アニメーション(Sample03.レイヤー1.canvas);
        Sample03.レイヤー1.更新関数を追加する(Sample03.エフェクト画像.更新する.bind(Sample03.エフェクト画像));

        Sample03.更新する();
    }

    static 更新する() {
        Sample03.レイヤー1.更新する();
        requestAnimationFrame(Sample03.更新する);
    }

    static アニメーションを開始する(evt) {
        Sample03.アニメーション1を設定する();
        Sample03.レイヤー1.更新を開始する();
    }

    static アニメーション1を設定する() {
        Sample03.エフェクト画像.画像を設定する(Sample03.画像リスト[0], 120, 120, 0, 0, 640, 640, true);
        Sample03.エフェクト画像.フレーム終了時関数 = Sample03.アニメーション2を設定する;
    }

    static アニメーション2を設定する() {
        Sample03.エフェクト画像.画像を設定する(Sample03.画像リスト[2], 240, 240, 0, 0, 480, 480);
        Sample03.エフェクト画像.フレーム終了時関数 = Sample03.アニメーション3を設定する;
    }

    static アニメーション3を設定する() {
        Sample03.エフェクト画像.画像を設定する(Sample03.画像リスト[1], 640, 240, 0, 0, 500, 640);
        Sample03.エフェクト画像.フレーム終了時関数 = Sample03.レイヤー1.更新を停止する;
    }
}

addEventListener('load', Sample03.main);

4行目で、Canvasクラスのオブジェクトを作成します。
この時、更新間隔は5フレームごとにします。
5行目で、Canvas要素がクリックされた場合は、「アニメーションを開始する」関数をコールするように設定します。
7〜8行目でアニメーションのオブジェクトを作成します。
Canvasオブジェクトにアニメーションオブジェクトの更新関数を追加します。
これにより、Canvasオブジェクトの更新処理を行うタイミングでアニメーションオブジェクトの更新がコールされるようになります。
10行目で、Canvasオブジェクトを更新する関数をコールします。

18行目で、Canvas要素をクリックすると、アニメーションオブジェクトにエフェクト画像を設定し、Canvasオブジェクトの更新を開始します。
これにより、アニメーションオブジェクトの更新関数が更新間隔ごとにコールされるようになります。

25行目で、アニメーションオブジェクトのアニメーションが終了すると、次のエフェクト画像を設定します。

30行目で、アニメーションオブジェクトのアニメーションが終了すると、更に次のエフェクト画像を設定します。

35行目で、アニメーションオブジェクトのアニメーションが終了すると、Canvasオブジェクト更新を終了します。
これにより、アニメーションオブジェクトの更新関数がコールされなくなります。

【このカテゴリーの最新記事】
カテゴリーアーカイブ