こんにちわ。アドベントカレンダー用に初めて投稿いたします、剣崎宗二と申します。
普段はツクールでプラグインを投稿してたりUnity関係の調整をしてたりしてます。
さて、今回のお題は、ゲームにとって重要な…画像周辺についてです。
#ImageManagerについて
##ImageManager周辺仕様解説
ImageManagerは、主に画像をファイルからメモリ内にロードするのを担当しています。
仕組みとしましては、各種load系function(loadAnimation
, loadPicture
等)がファイルがロードされるフォルダを決定し、そのフォルダとファイル名からloadBitmap
→loadNormalBitmap
と繋がります。
(ファイル名を空白にすれば空白のbitmapを作る事も可能です。loadEmptyBitmap
)
これは
bitmap.addLoadListener(function() {
bitmap.rotateHue(hue);
});
の通り、asynchronous(非同期型)ロードとなっており、ロード待ちのの間に他の処理が進みます。
非同期型であるのは、恐らくはウェブページの特性(ロードに時間が掛かる&メモリに制約有り)を考慮しての話かと。
ロードが終了したbitmapはcache
に格納され、再度ロードされる際はここから直接取り出されます。なので2度目以降のロードはほぼ即時です。
##ロードの完了を確認する/待つ
画像を扱う多くのプラグイン作者さんが恐らく経験した事があるのが「非同期型故に、使う直前でロードを掛けても画像が表示されない」と言う問題かと。
これは上で言ったように非同期型ロード故にロードが完了される前に次の行が実行される事に起因します。
回避するには、以下の方法が考えられます。(上であるほどお勧めです)
###1.Spriteを使う
Spriteのイメージとしては、画像を格納しておける「箱」のような物だと取って頂いて構いません。
箱なので、箱ごと移動させるのも消去するのも楽ですし、何よりSpriteにbitmapをロードしておけば
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で次の処理を待たせる
私が以前「ツクマテ」に投稿した方法です。
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
毎に
Sprite_Picture.prototype.picture = function() {
return $gameScreen.picture(this._pictureId);
};
で取り込んで、Sprite自体の画像や座標データを更新しているのがその正体となります。
##Game_Pictureはどこにあるの?
Game_Screenに連結されています。
Game_Screen.prototype.clearPictures = function() {
this._pictures = [];
};
##Sprite_Pictureはどこにあるの?
画面上では以下で生成されています。
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
する事で、ピクチャをウィンドウの後ろ側に表示したり、色々できるようになります。