2013/03/08

[js]setInterval()でメソッドを呼んだらいかん

なんか作らないとJavaScriptなどを覚えないと思うので、以前作ったAndroidの威嚇アプリを移植してみることにした。
まあ、全部じゃなくても、なんか動けばいいや、という程度で。。

 

起動すると、アリクイがぐーぐー寝ているアニメーションが出てくる。
あれをやろう。
本を読むと、setInterval()で関数を定期的に呼び出し、そこで描き替えをするみたいだ。
ふむふむ。

var mCanvas = document.getElementById("canvas_arikui");
var mContext = mCanvas.getContext("2d");
function Arikui() {
	this.mPosX = 10;
	this.mPosY = 10;
	this.mImgSleepCnt = 0;
	this.mImgSleep = new Array(2);
	this.mImgSleep[0] = new Image();
	this.mImgSleep[1] = new Image();
	this.mImgSleep[0].src = "sleep_f1.png";
	this.mImgSleep[1].src = "sleep_f2.png";
	this.FuncSleep = function() {
		mContext.drawImage(this.mImgSleep[this.mImgSleepCnt], this.mPosX, this.mPosY);
		this.mImgSleepCnt++;
		if (this.mImgSleepCnt >= this.mImgSleep.length) {
			this.mImgSleepCnt = 0;
		}
	}
	this.FuncAnim = this.FuncSleep;
}
mArikui = new Arikui();
setInterval(mArikui.FuncAnim, 500);

こんなもんじゃなかろうか。
そう思ってやってみると・・・Firebugがエラーを出している。
しかも、定期的にエラーを出しているので、実行時エラーのようだ。

エラーの内容は「this.mImgSleepCntが未定義」というものだった。
えー、あるやん。。。

わからんので、this.mImgSleepCntを定数に置き換えると、今度はthis.mImgSleepが未定義だと。
えー、あるやん。。。

ここで数時間悩んだあと、this.mImgSleepがnullかどうかを出力させることにした。
Firebugには「console.log(文字列)」みたいな関数があって、それを使うとprintfデバッグみたいなことができるのだ。

チェックするのは、コンストラクタとFuncSleepの中。
動かすと・・・コンストラクタでは非nullだったものが、FuncSleepではnullになっていた。

 

・・・つまり、あれだ。
C++でメンバ関数のポインタを渡せないのと同じだ。
しくみはよくわからんがsetInterval()で呼び出すオブジェクトを保持する場所は別の管理領域か何かになっていて(コンテキストが異なるからかな)、Arikui.FuncAnimは呼び出せるけど、mArikuiのthisを参照できなくなっているのだろう。
「それならmArikui.FuncAnimを呼び出すとArikui.FuncSleepが呼び出されるのもおかしいのでは?」と思わなくもないが、そこら辺は最適化か何かによってうまくいっているように見えるだけかもしれん。

試しに、最後の方だけ変更した。

mArikui = new Arikui();
function Loop() {
	mArikui.FuncAnim();
}
setInterval(Loop, 500);

setInterval()に保持してもらうのを、オブジェクトが指すメソッドではなく、グローバルで持つメソッドにしてしまい、そのメソッドの中からオブジェクトが指すメソッドを呼ぶようにしたのだ。

結果としてはうまくいっているが、推測が当たっているからなのか、ちょうどうまくいっているように見えるだけなのかはわからん。
http://www7b.biglobe.ne.jp/~hiro99ma/ikaku01/ikaku.html

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。