LoginSignup

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 5 years have passed since last update.

ImageManager周辺とGame_Pictureの仕組み

Last updated at Posted at 2017-11-20

こんにちわ。アドベントカレンダー用に初めて投稿いたします、剣崎宗二と申します。
普段はツクールでプラグインを投稿してたりUnity関係の調整をしてたりしてます。

さて、今回のお題は、ゲームにとって重要な…画像周辺についてです。

ImageManagerについて

ImageManager周辺仕様解説

ImageManagerは、主に画像をファイルからメモリ内にロードするのを担当しています。
仕組みとしましては、各種load系function(loadAnimation, loadPicture等)がファイルがロードされるフォルダを決定し、そのフォルダとファイル名からloadBitmaploadNormalBitmapと繋がります。
(ファイル名を空白にすれば空白のbitmapを作る事も可能です。loadEmptyBitmap

これは

rpg_manager.js
bitmap.addLoadListener(function() {
   bitmap.rotateHue(hue);
});

の通り、asynchronous(非同期型)ロードとなっており、ロード待ちのの間に他の処理が進みます。
非同期型であるのは、恐らくはウェブページの特性(ロードに時間が掛かる&メモリに制約有り)を考慮しての話かと。

ロードが終了したbitmapはcacheに格納され、再度ロードされる際はここから直接取り出されます。なので2度目以降のロードはほぼ即時です。

ロードの完了を確認する/待つ

画像を扱う多くのプラグイン作者さんが恐らく経験した事があるのが「非同期型故に、使う直前でロードを掛けても画像が表示されない」と言う問題かと。
これは上で言ったように非同期型ロード故にロードが完了される前に次の行が実行される事に起因します。
回避するには、以下の方法が考えられます。(上であるほどお勧めです)

1.Spriteを使う

Spriteのイメージとしては、画像を格納しておける「箱」のような物だと取って頂いて構いません。
箱なので、箱ごと移動させるのも消去するのも楽ですし、何よりSpriteにbitmapをロードしておけば

rpg_sprite.js
Sprite_Enemy.prototype.loadBitmap = function(name, hue) {
    if ($gameSystem.isSideView()) {
        this.bitmap = ImageManager.loadSvEnemy(name, hue);
    } else {
        this.bitmap = ImageManager.loadEnemy(name, hue);
    }
};

等、各種loadBitmapにより毎フレーム自動で再更新されます。
個人的には一番扱いやすい方法です。

2.ゲーム開始時にロードしておく

ゲーム開始時(Scene_Boot等)で先にImageManager.reserveBitmapを使ってロードを始めて置く方法です。
ツクール自体が推奨している方法だと思われますし、一番安定していると考えますが…

・「直前までロードする画像名が分からない場合」(HP割合によって表情が変わる等)
・そもそもScene_Boot自体の中で画像を使いたい

この類の状況には適さないのが問題ですね。

3.setIntervalで次の処理を待たせる

私が以前「ツクマテ」に投稿した方法です。

sample.js
   ImageManager.loadPicture("me")
   var waiter = setInterval(function(){ //定期的に繰り返されるIntervalイベント登録
     if (ImageManager.isReady())
     {
       $gameScreen.showPicture(10, "me", 0, 0, 0, 100, 100, 255, 0); //実際に描画するコマンド。ご自分の使用している物に合わせてお使いください(this.content.blt等)     
       clearInterval(waiter);  //executeDrawFaceがtrueを返した場合、Interval消去
     }
   }, 100); //0.1秒間隔

ImageManager.isReady()で現在ロード中の画像があるかを確認し、ない場合(=全てロード完了時)のみ実描画を実行すると言う仕組みです。(各bitmapレベルでもisReady()が発動できると言う話を聞いた事がありますが試した事はないです)
Spriteが使えない上にファイル名が動的で使用直前まで判明しない、と言う状況の際に使う方法ですが、ややコードが難解ですので初心者にはお勧めできないです・・・

Game_Picture

Game_Pictureの仕組み

一見した所、rpg_object.jsにあるこのGame_Pictureオブジェクトが「ピクチャの表示」を行った際に画面に表示される画像の実体に見えるかもしれませんが、そうではありません。
本当の実体はrpg_sprite.jsにあるSprite_Pictureです。
Game_Pictureは画像についての「データ」(座標など)を保持しており、それをupdate毎に

rpg_sprite.js
Sprite_Picture.prototype.picture = function() {
    return $gameScreen.picture(this._pictureId);
};

で取り込んで、Sprite自体の画像や座標データを更新しているのがその正体となります。

Game_Pictureはどこにあるの?

Game_Screenに連結されています。

rpg_object.js
Game_Screen.prototype.clearPictures = function() {
    this._pictures = [];
};

Sprite_Pictureはどこにあるの?

画面上では以下で生成されています。

rpg_sprite.js
Spriteset_Base.prototype.createPictures = function() {
    var width = Graphics.boxWidth;
    var height = Graphics.boxHeight;
    var x = (Graphics.width - width) / 2;
    var y = (Graphics.height - height) / 2;
    this._pictureContainer = new Sprite();
    this._pictureContainer.setFrame(x, y, width, height);
    for (var i = 1; i <= $gameScreen.maxPictures(); i++) {
        this._pictureContainer.addChild(new Sprite_Picture(i));
    }
    this.addChild(this._pictureContainer);
};

_pictureContainerを増やしたり、違うレイヤーに装着した後にそこへaddChildする事で、ピクチャをウィンドウの後ろ側に表示したり、色々できるようになります。

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