2
2

More than 1 year has passed since last update.

【PixiJS 覚書】第三回 PIXI.Sprite、PIXI.Text(とPIXI.Loaderのほんのさわりだけ)

Last updated at Posted at 2021-12-10

これまでのあらすじ

第一回 PIXI.ApplicationとPIXI.Container
第二回 PIXI.Graphics(と、PIXI.DisplayObjectの掘り下げ)

第一回でPixiJSの描画の基本構造をざっくり掴み、
第二回でPIXI.Graphicsの使い方を通して描画の仕組みや機能に慣れてもらいました。

この第三回ではいよいよスプライトを扱います。ようやくゲームっぽい表現ができるよ!
そしてPIXI.Spriteの派生クラスであるPIXI.Textもついでに紹介します。
また、「画像を読み込む」必要が発生しますので、データ読み込みの機能であるPIXI.Loaderにも軽く触れます。

サンプルコード

sample_code
//(前略)

app.loader.baseUrl = 'https://pixijs.io/examples/examples/assets/';

const resourceList = [{name: 'bunny', fileName: 'bunny.png'},
                    {name: 'flowerTop', fileName: 'flowerTop.png'},
                    {name: 'eggHead', fileName: 'eggHead.png'}];

for(let i = 0; i < resourceList.length; i++) {
    const {name, fileName} = resourceList[i];
    app.loader.add(name, fileName);
}

app.loader.load(startup);


function startup()
{
    for(let i = 0; i < resourceList.length; i++) {
        const { name } = resourceList[i];

        const sprite = new PIXI.Sprite(app.loader.resources[name].texture);
        sprite.anchor.set(0.5);
        sprite.x = 140 + 160 * i;
        sprite.y = 180;

        const text = new PIXI.Text(name, {fontFamily : 'Arial', fontSize: 24, fill : 0x101010, align : 'center'});
        text.anchor.set(0.5);
        text.x = 140 + 160 * i;
        text.y = 300;

        app.stage.addChild(sprite);
        app.stage.addChild(text);
    }
}

実行結果

Playgroundで実行するとこうなります。
読み込んでいる画像はPixiJS Examplesのサンプル画像です。いいセンスしてる。
sprite_others.png

PIXI.Loader

第一回の振り返り。
PIXI.Applicationには以下の7つの機能が用意されており、第一回では上の3つviewstagescreenプロパティの持っている機能について確認しました。

名前 機能 クラス
view 実際に画面に表示されるcanvas要素 HTMLCanvasElement
stage viewに表示される描画オブジェクトのコンテナ PIXI.Container
screen viewの大きさなどの情報を持ったRectangle PIXI.Rectangle
ticker 描画物のupdateループを担う PIXI.Ticker
loader ファイル読み込みと管理 PIXI.Loader
renderer WebGLのレンダラ PIXI.Renderer
resizeTo viewの自動リサイズの
基準となるHTML要素
Windowまたは
HTMLElement

今回はloaderプロパティの機能について見ていきます。

バージョンの違いに注意

第一回にも書きました、間が空いたのでもう一度。
「本記事はv5に基づいて記述しています」
なぜ改めてこれを強調するかというと、PIXI.Loaderの使い方がv4とv5で変わっているからです。

v4ではPIXIモジュールに静的に実装された機能であり、以下のように使用していました。

v4
PIXI.loader.add('ファイルパス');

v5ではインスタンス化されたアプリケーションを介して利用します。

v5
app.loader.add('ファイルパス');

繰り返しになりますが、本記事ではv5でいきます。

おおまかな流れ

PIXI.Loaderによるファイル読み込みの大まかな流れは以下となります。

  1. addメソッドで読み込みキューへ追加
  2. loadメソッドで読み込み開始
  3. 読み込み完了後にresourcesプロパティを参照

addメソッド

for(let i = 0; i < resourceList.length; i++) {
    const {name, fileName} = resourceList[i];
    app.loader.add(name, fileName);
}

ではサンプルコードを追っていきましょう。
一行目のbaseUrlプロパティやパス情報の配列はひとまず後回しにして、先にaddメソッドから解説します。

このメソッドが便利であり同時に厄介な点は、読み込み元のパスの渡し方が柔軟で多岐にわたる点です。
実際にどのような渡し方があるかはリファレンスにサンプルの記載があるのでそちらを参照していただくとして、ここでは最も初歩的な渡し方を紹介します。

・add('path');
または
・add('key', 'path');

PIXI.Loaderによって読み込まれたリソースはそれぞれ名前が付けられ、連想配列として管理されます。

ファイルパスを単体で渡すだけの場合、それによって読み込まれたリソースの名前はファイルパスがそのまま名前になります。

本記事のサンプルコードではパスだけでなくkeyも一緒に渡す二つ目の方法を取っており、その場合は'key'が連想配列のkeyとなります。
add.png
なお、ここでは使いませんでしたが、パスの後にはオプションパラメータとして該当リソース読み込み完了後に呼び出されるコールバック関数を渡せます。
リソースの読み込みが一つ完了する毎にカウンタを増やす関数を渡してプログレスメーターを実装したりできそうですね。

baseUrlプロパティ

app.loader.baseUrl = 'https://pixijs.io/examples/examples/assets/';

const resourceList = [{name: 'bunny', fileName: 'bunny.png'},
                    {name: 'flowerTop', fileName: 'flowerTop.png'},
                    {name: 'eggHead', fileName: 'eggHead.png'}];

順番前後しましたが、baseUrlプロパティを利用することで、ベースとなるパスを予め設定しておけます。まんまですね。
その結果、リソース情報を管理している配列resourceList内ではフルパスを記述せずにファイル名だけで済んでいます。

loadメソッド

さて、addメソッドで読み込みたいリソースのパスをキューに登録できました。
次はこの読み込みキューを開始します。

app.loader.load(startup);

・load(callback)
キューに詰め込まれたリソースの読み込みを開始します。
読み込みは非同期で行われます。
だいじなことなのでもう一度言います。読み込みは非同期です。
リソース読み込みが完了する前に次の処理に進んでしまうとまずエラーになるので、読み込み完了に応じて次の処理をトリガーする必要があり、引数にはそのコールバック関数を渡します。

ちなみにaddメソッド、loadメソッドのどちらも戻り値としてloader自身(this)を返すので、リソースが一つだけでaddとloadを続けて行う場合には以下のようにメソッドチェーンで記述できます。

app.loader.add('bunny', 'bunny.png').load(startup);

resourcesプロパティ

function startup()
{
    for(let i = 0; i < resourceList.length; i++) {
        const { name } = resourceList[i];

        const sprite = new PIXI.Sprite(app.loader.resources[name].texture);
    //(後略)
    }
}

loadメソッドによるリソースの読み込みが完了し、startupが呼び出されました。
上述のように、読み込まれた各リソースは名前が付けられて連想配列としてresourcesプロパティに格納されます。
そのため、リソースにアクセスするための名前をまず用意し、resources[name]として該当リソースを参照しています。

さて、ここまで何度も「リソースを読み込む」と表現してきましたが、読み込んだデータは具体的にどのような状態で保存されているのでしょうか。
その答えはPIXI.LoaderResourceクラスのインスタンスです。
PIXI.Loaderは読み込んだリソースの種類に応じて、このPIXI.LoaderResourceインスタンスの中身をイイ感じに作りこんでくれるのです。

・・・すみません、今「イイ感じに」というふわっとした表現に逃げました。

というのも、どの種類のファイルの場合にどういうデータとプロパティを持ったインスタンスが仕上がってくるのかは、各ファイルの種類や通信形式、DOM等の深い理解が必要なようで、これを詳細に紐解くのは現時点の私にはどうにも手に余りそうです。 ∩(´・ω・`)∩ 降参
画像だけでなく音やjson、動画、text、xmlファイルなどを読み込んで扱えるようです。
(とはいえ、PixiJSは描画ライブラリなので音の再生機能はないですが。)

ともかく、いまスプライトを利用する上で必要になる部分だけは以下にまとめておこうと思います。

【スプライトに利用する上でのresourceプロパティの要点】
1. PIXI.Loaderは読み込むリソースの種類を拡張子から判別しており、対応している形式のファイルであれば自動的に下処理をしてくれる。
2. 取り扱えるデータの種類は →こちら
3. 今回のpngファイルのようなイメージ画像の場合、読み込んだデータから自動的にPIXI.Textureインスタンスを作り出し、textureプロパティに格納してくれる
4. また、読み込んだデータそのものはimg要素としてdataプロパティに格納される。

スプライトを利用する上では「3.」のテクスチャが重要となります。
とりあえず必要なデータは読み込みました!
これ以上の深入りは避けてスプライトの話に移ります!

PIXI.Sprite

PIXI.Loaderの話が長くなりましたが、ここからようやくスプライトに触れていきます。

PIXI.SpriteとPIXI.Texture

        const sprite = new PIXI.Sprite(app.loader.resources[name].texture);
        sprite.anchor.set(0.5);
        sprite.x = 140 + 160 * i;
        sprite.y = 180;

リファレンス:PIXI.Sprite

コンストラクタにテクスチャを渡してインスタンスを生成しています。
「テクスチャ」をより正確に言うとPIXI.Textureクラスのインスタンスです。

リファレンス:PIXI.Texture

さて、このPIXI.TextureはPIXI.DisplayObjectの派生クラスではありません
そのため、コンテナに直接addChildすることはできず、主にスプライトに持たせる情報として使用します。

これでテクスチャという画像情報を持ったスプライトが生成されました。

anchorプロパティ

PIXI.Spriteにはanchorという使い勝手が良く利用頻度の高いプロパティが用意されています。
第二回で扱ったPIXI.DisplayObjectのpivotプロパティと良く似た働きをし、回転における基準軸やコンテナへaddChildする際の基準位置となる点は同じです。
ただしpivotがピクセル座標で指定するのに対し、anchorは画像の大きさに合わせた割合で指定します。
範囲は画像の左上を0、右下を1とし、割合で表します。つまり中央は「0.5」です。
大きさがまちまちで数が多いことが予想されるスプライトに対して、一々その画像のwidth、heightから中央位置を計算しなくて良いわけです。

//たとえばBunny.pngのスプライトの場合、width:26、height:37なので
//pivotだと画像の大きさに応じて中央位置を算出する必要がある
sprite.pivot.set(13, 18);

//anchorであれば画像の大きさに関係なく以下で中央を指定できる
sprite.anchor.set(0.5);

//(補足)setメソッドは引数を一つだけ渡すとx,y両方にセットしてくれます

これで画像の中央位置を指定できました。
あとはx座標、y座標を指定してスプライトの準備は完了です。

おまけ

スプライトはコンストラクタにテクスチャを渡してインスタンス生成、と説明してきましたが、それ以外に画像を直に読みに行くお手軽メソッドも用意されていたりします。

PIXI.Sprite.from('https://pixijs.io/examples/examples/assets/bunny.png');

リファレンス
指定先のファイルからテクスチャを作成してスプライトまで仕上げてくれます。

PIXI.Text

最後は文字を表示させるPIXI.Textを扱います。
とは言っても、PIXI.TextはPIXI.Spriteの派生クラスであり、扱い方もほぼ同様です。

インスタンス生成

        const text = new PIXI.Text(name, {fontFamily : 'Arial', fontSize: 24, fill : 0x101010, align : 'center'});
        text.anchor.set(0.5);
        text.x = 140 + 160 * i;
        text.y = 300;

リファレンス:PIXI.Text

コンストラクタの引数は (text, style, canvas)の3つで、
・text:表示させたい文字列
・style:フォントのスタイルを指定するオブジェクト
・canvas:描画先となるcanvas要素
です。
最後のcanvasは今は忘れていいです。基本レベルにおいては描画先キャンバスはまずviewなので。
というわけで、サンプルコードでは
fontFamily(フォントの種類)を 'Arial'に、
fontSize(フォントの大きさ)を 24px に、
fill(塗り色)を 0x101010(ほぼ黒)に
align(文字揃え)を 'center'に
してみました。
ちなみにalignは今回のように一行だけの場合は特に意味がありません。
テキストに改行が含まれて複数行になっていた場合に各行を'left'(左揃え)、'center'(中央揃え)、'right'(右揃え)にしてくれます。

テキストスタイルに他にどのような設定が可能であるかは リファレンス を参照してみてください。

あとはスプライトと同様にanchorとxy座標をセットして準備完了です。

addChild

        app.stage.addChild(sprite);
        app.stage.addChild(text);

忘れずに。

まとめ

[PIXI.Loader]
・PIXI.Loaderはv4とv5で使い方が違う。
・v5ではPIXI.Applicationインスタンスのloaderプロパティからアクセスする。
・基本手順:「add」して「load」して「resources」から参照
・pngその他のイメージファイルの場合、読み込んだ画像は自動的にリソースオブジェクトのtextureプロパティにPIXI.Textureインスタンスとしてセットされる。

[PIXI.SpriteとPIXI.Texture]
・PIXI.Spriteインスタンスは画像情報としてPIXI.Textureインスタンスを持つ。
 コンストラクタで生成する場合、テクスチャを引数として渡す。
・スプライトの基準位置指定はanchorプロパティが便利。画像の大きさによらず「0~1」の範囲で指定できる。

[PIXI.Text]
・PIXI.TextはPIXI.Spriteの派生クラス。なので使い方も良く似ている。
・コンストラクターの引数にはテキストとフォントスタイルを渡す。


今回はここまで!

次回、スプライトを動かすよ!やっと動く!

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2