9.20 レイヤ移動機能を拡張する(その6)

今回は ExtendedMover クラスの残ってるメソッドを見ていくね。
あといくつ残ってるんだっけ?
3つだよ。
3つかぁ…今回も長くなりそうかも…
それじゃ早速最初のメソッド、stopMove メソッドから見てくね。

stopMove メソッド>

function stopMove()
{
    // 一時レイヤが使われていれば(=拡大・縮小・回転が行われていれば)
    // 画像を最終倍率・最終回転角に拡大・縮小・回転します
    if(refLayer !== void && refLayer isvalid)
    {
        var finalScale = pathex[-2]; // 最終拡大率
        var finalAngle = pathex[-1]; // 最終回転角
        if(finalAngle != 0)
        {
            // 最終回転角が 0°でない場合はアフィン変換します
            calcRotateParams(rotateParams, refLayer, finalAngle * radConst, finalScale / 100); // アフィン変換のパラメータを計算します
            rotateImage(stFastLinear); // 線形補間を使って拡大・縮小・回転します
            layer.setPos(layer.left - rotateParams.dspX, layer.top - rotateParams.dspY); // 位置調整します
        }
        else if(finalScale != 100)
        {
            // 最終拡大率が 100% (等倍)でない場合は拡大・縮小します
            scaleImage(finalScale / 100, stFastLinear); // 線形補間を使って拡大・縮小します
        }
        else
        {
            // 最終的に拡大・縮小・回転していない状態になる場合は
            // 一時レイヤの画像(=元々の画像)をコピーします
            layer.assignImages(refLayer);
        }
        // 移動後の画像が拡大・縮小・回転していてもロード時に復元できるように
        // Anim_loadParams に scale 属性と angle 属性の値を書き込みます(eximage で使用)
        layer.Anim_loadParams.scale = (finalScale != 100) ? finalScale : void;
        layer.Anim_loadParams.angle = (finalAngle != 0) ? finalAngle : void;
    }
}

stopMove メソッドはレイヤの移動を終わらせる時に呼び出されるメソッドなわけだけど、 具体的には何をしたらいいと思う?
え〜っと、確か removeContinuousHandler メソッドを呼び出してコンティニュアスハンドラがこれ以上呼び出されないようにするのと、 あとレイヤの位置とかを最終値に設定するって言ってたよね?
§9.17 参照。また、removeContinuousHandler メソッドについては §9.13 参照。
ん、そうだね。
ちなみに removeContinuousHandler メソッドを呼び出すのとレイヤの位置や不透明度を最終値に設定するのは LinearMover クラスとか SplineMover クラスの stopMove メソッドがやってくれるから、 ExtendedMover クラスの stopMove メソッドでやらきゃいけないのは画像の拡大率と回転角の設定ってことになるね。
LinearMover クラスと SplineMover クラスについては §9.16 参照。
なるほどね。
あともう1つやらなくちゃいけないことがあるんだけど、何だかわかる?
え、まだあるの?
う〜ん…前に聞いたのはそれだけだったよーな気がするんだけどなぁ…
まぁ前に stopMove メソッドの説明した時には言わなかったからね。
えっ?
それじゃわかんなくてとーぜんなんじゃ…
いや、そんなコトはないと思うよ。
eximage マクロに関係してることだから。
eximage マクロってことは…やっぱり画像の拡大とか回転とかの関係ってことだよね?
うん。
eximage マクロを作った時に loadParams ってのが出てきたでしょ。
loadParams については §9.11 参照。
えと、確か eximage マクロを実行した時に指定されてた属性の値が記録されてる辞書配列、だったよね?
そうそう。その loadParams の中身を stopMove メソッドの中で更新しなくちゃいけないんだ。
更新するって辞書配列の中身を書き換えるってこと?
そうだよ。eximage マクロには scaleangle っていう属性が指定できるでしょ。
拡大率と回転角のことだね。
で、セーブデータを読み込む時に、loadParams に記録されてる scaleangle の値を参照して画像を拡大・縮小・回転してたよね。
え〜っと…そーだったかな?
ImageHandlerPlugin クラス(eximage マクロ用のクラスのことね)の onRestore メソッドで loadParams を引数に指定して processImage メソッドを呼び出してたでしょ。
§9.11 参照。
あ〜、そだそだ。
それで processImage メソッドの中で画像を拡大したりしてたんだったよね?
そう。だから stopMove メソッドの中で loadParams の中身を更新しとかなきゃいけないよね。
え、なんで?
例えば、scale=50eximage マクロを実行したとするね。
拡大率 50% だね。
で、その後 exmove マクロを実行して、 画像を 200% に拡大したとするね。
うん。
さらに、その状態でセーブしたとするね。
※セーブする前にセーブ可能なラベルを通過しているものとします。
うん。
そのセーブデータを読み込んだら、画像の拡大率はどうなってると思う?
exmove タグで 200% に拡大したんだから 200% でしょ。
そうなってれば問題ないんだけど、eximage マクロで画像を読み込んだときの scale 属性の値は 50% (つまり、loadParamsscale 要素の値は 50)だから、そのままセーブデータを読み込むと、 画像が 50% のサイズに縮小されちゃうよね。
あ、そっか。確かにそーなっちゃうね。
ってコトは… もしかして stopMove メソッドで loadParamsscale 要素の値を 200 にしとけばおっけー、ってことなんじゃない?
そのとーり。
これで stopMove メソッドで loadParams の中身を更新しなきゃいけないワケがわかったでしょ?
うん。
んじゃスクリプトの方を見てこっか。
stopMove メソッドも move メソッドみたいに全体が1つの if ブロックになってるね。
なんでそーなるんだったかは覚えてる?
ん〜… move メソッドの時は、 一時レイヤがあるかどうかチェックして、一時レイヤがある時だけ if ブロックの中身を実行してたよね。
だね。
一時レイヤが無いってことは、画像を拡大も縮小も回転もしてないってことだから、 move メソッドで何もする事がない、 ってのが全体が1つの if ブロックになってる理由だったと思うんだけど?
そ。stopMove メソッドも同じ理由で全体が1つの if ブロックになってるの。
if の条件も move メソッドと同じになってるでしょ。
ホントだ。どっちも“refLayer !== void && refLayer isvalid”になってるね。
じゃ if ブロックの中身を見てくね。
なんか“pathex[-2]”とか“pathex[-1]”とか書いてあるけど、 配列の添え字にマイナスって指定できるの?
ん、できるよ。
ただマイナスの値を指定するとちょっと特別な意味になるんだけどね。
特別な意味って?
配列の添え字にマイナスの値を指定すると、配列の最後から何番目かを指定してることになるの。
だから、例えば“pathex[-2]”だと、“pathex 配列の最後から2番目の要素になるわけね。
じゃあ例えば pathex 配列に要素が10個あったら、 pathex[-2]pathex[8] とおんなじ意味ってこと?
そうそう。
だから、pathex[-2] が最終拡大率(finalScale)で pathex[-1] が最終回転角(finalAngle)になるの。
そーだっけ?
例えば、前回出てきたこのスクリプトを実行した場合は、 pathex 配列はこうなるから…

pathex 配列に対する普通の添え字指定とマイナスの添え字指定>

pathex[-2] が最終拡大率になってて、 pathex[-1] が最終回転角になってるでしょ。
あー、なるほど。
この場合は配列の要素が8個だから、pathex[-2]pathex[6] とおんなじで、pathex[-1]pathex[7] とおんなじになるんだね。
そ。で、その後の if ブロックとか else ブロックとかで最終拡大率と最終回転角の値に応じた処理をしてるんだ。
それって画像を拡大したり回転したりとかするってこと?
そだよ。まず最初の if ブロックの条件は“finalAngle != 0”だから…
最終回転角が じゃないってことだよね?
つまり、最終的に画像が回転してたら、if ブロックの中身を実行して画像を回転するわけね。
で、もし画像が回転してなかったら(つまり finalAngle0 ってことだね)、 次の else if の条件“finalScale != 100”をチェックすることになるよね。
この条件式は最終拡大率が 100% じゃない時に真になるから、 真になるってことは最終的に画像が拡大されてるか縮小されてるってことだね。
その時は else if ブロックの中身を実行して画像を拡大・縮小するってことね。
で、画像が回転もしてないし拡大・縮小もしてない(つまり finalAngle0finalScale100 ってことだね)場合は…
else ブロックの中身が実行されるんだね。
そういうこと。
ちなみにこの辺のスクリプトは rotate メソッドとかなり似てるから、説明は省略させてもらうね。
ん〜、確かに似てるみたいだけど…
rotateImage メソッドと scaleImage メソッドの引数の数が違ってるよね?
rotate メソッドで呼び出してる時は無かった“stFastLinear”ってゆー引数がついてるんだけど?
あー、ExtendedMover クラスの rotateImage メソッドと scaleImage メソッドは、最後の引数に補間方法を指定できるようにしてるから。
補間方法って…画像をキレイに拡大できたりするののことだっけ?
※画像の補間については §9.2 参照。
そう。
affineCopy メソッド(画像を回転・拡大・縮小できるメソッドのことね)と stretchCopy メソッド(画像を拡大・縮小できるメソッドね)にはどっちも stNearest(最近傍補間)と stFastLinear(低精度線形補間)が指定できるんだ。
affineCopy メソッドについては §9.4stretchCopy メソッドについては §9.2 参照。
確か stFastLinear の方が stNearest よりキレイに補間できるんだよね?
そうだよ。
ただ、キレイに補間できる代わりに画像を拡大するのに時間がかかっちゃうから、 exmove マクロを実行してる間はできるだけ早く補間できるように stNearest を指定して、 exmove マクロを実行し終わった時(つまり stopMove メソッドが呼び出された時ね)にはできるだけキレイに補間できるように stFastLinear を指定してるんだ。
exmove マクロを実行してる間も stFastLinear じゃダメなの?
ん〜、ダメってわけじゃないんだけど、stFastLinearstNearest よりだいぶ時間がかかっちゃうからね。
コンティニュアスハンドラは“できるだけ頻繁に呼び出される”って前に言ったでしょ。
§9.13 参照。
うん、言ってたね。
だから、コンティニュアスハンドラから呼び出されるメソッドの中での処理は、 基本的に“できるだけ早く終わらせる”ようにした方が良いんだ。
そーなんだ。
あと、処理が早く終わるほどコンティニュアスハンドラを頻繁に呼び出せるから、 その分動きが滑らかに見えるっていうメリットもあるしね。
なるほど。
でも、stFastLinear だとあんまりキレイに画像を拡大・縮小できないでしょ。
だよねぇ。
だから、コンティニュアスハンドラが呼び出されてる時(move メソッドが呼び出されてる時)には stNearest で高速に画像を拡大・縮小して、 コンティニュアスハンドラが呼び出されなくなった(stopMove メソッドが呼び出された)時点で stFastLinear に切り替えて、最後はキレイに補間されるようにしてるの。
コンティニュアスハンドラが呼び出されてる時は頻繁に画像が書き換えられるから、 補間した画像があんまりキレイじゃなくてもそんなに目立たないしね。
そっか。
…あ、でも stNearest ってどこにも書かれてなかったよね?
rotateImage メソッドと scaleImage メソッドの最後の引数を省略すると stNearest が指定されてるって見なしてるの。
じゃあ rotate メソッドとかで rotateImage メソッドや scaleImage メソッドを呼び出してる時は最後の引数を省略してるから stNearest になるんだね。
そう。じゃ次行くね。
このスクリプトは見ての通り loadParamsscale 要素と angle 要素に、 それぞれ最終拡大率(finalScale)と最終回転角(finalAngle)の値を書き込んでるスクリプトだよ。
えっと、Anim_loadParams って loadParams のことだったよね?
§9.18 参照。
そだよ。
後は大丈夫かな?
ん〜、大体わかるんだけど、なんで finalScale100 だったり finalAngle0 だったりしたら void を代入してるのかがちょっとよくわかんないかな。
finalScale100 ってことは、 画像を拡大も縮小もする必要ないってことだし、 finalAngle0 ってことは、 画像を回転する必要がないってことでしょ。
うん、そーだね。
つまり、finalScale100 だったら scale 属性を指定する必要がないってことだし、 finalAngle0 だったら angle 属性を指定する必要がないってことだよね。
だから、そういう時は void を代入して、 scale 属性とか angle 属性が指定されてないって見なされるようにしてるの。
ふぅん、そーなんだ。
じゃこれで stopMove メソッドは一通りチェックできたから、 次はデストラクタを見とこっか。

<デストラクタ>

function finalize()
{
    // レイヤの移動を止めます
    stopMove();
    // 一時レイヤを使っていれば無効化します
    invalidate refLayer if refLayer !== void;
}

まぁこれは特に説明が必要なとこは無いよね。
stopMove メソッドを呼び出して、 あと一時レイヤを使ってたら無効化してるんだね。
普通はデストラクタが呼び出される前に stopMove メソッドが呼び出されるから、 ここで stopMove メソッドは呼び出さなくてもいいかもだけど、 まぁ念のためってことで。
それじゃ最後は beginMove メソッドね。

beginMove メソッド>

function beginMove(elm)
{
    
// exmove マクロに指定されている layer, page 属性からレイヤへの参照を取得します
    var layer = kag.getLayerFromElm(elm);

    // レイヤの移動を止めます
    layer.stopMove();

    // 移動用オブジェクトを作成します
    if(elm.spline !== void && +elm.spline)
    {
        // スプライン補間の場合は SplineMoverEx クラスのオブジェクトを作成します
        layer.moveObject = new SplineMoverEx(layer, elm, layer.moveFinalFunction);
    }
    else
    {
        // 直線補間の場合は LinearMoverEx クラスのオブジェクトを作成します
        layer.moveObject = new LinearMoverEx(layer, elm, layer.moveFinalFunction);
    }
    layer.window.moveCount++; // 動いているレイヤの数を1つ増やします(この値は KAG システムがレイヤの移動を制御するために使用します)
    layer.moveObject.startMove(+elm.delay); // レイヤの移動を開始します
}

先にデストラクタが出てきたからもう終わりなのかと思ったんだけど、 まだメソッドが残ってたんだね…
ExtendedMover クラスの beginMove メソッドはちょっと特殊なメソッドだから、最後に説明することにしたんだ。
え、特殊ってどーゆーコト?
それはね、beginMove メソッドを呼び出してるとこを見ればわかると思うよ。
そーいえば今まで beginMove メソッドを呼び出してるとこ見たことない気がするんだけど?
ん、beginMove メソッドを呼び出してるとこはまだチェックしてないからね。
あ、やっぱりそーなんだ?
beginMove メソッドってどこから呼び出されてるの?
exmove マクロからだよ。
マクロの中でこんなふうに呼び出されてるんだ。

exmove マクロ>

[macro name=exmove]
[eval exp="ExtendedMover.beginMove(mp)"]
[endmacro]

確かに呼び出されてるねー。
…ん? でもこれなんかヘンじゃない?
あ、やっぱり気がついた?
“ExtendedMover.beginMove(mp)”って書いてあるけど、 ExtendedMover ってクラスの名前になってるから変数の名前には使えないよね?
それに ExtendedMover クラスのオブジェクトも作ってないみたいだし。
ExtendedMover クラスの beginMove メソッドはね、 オブジェクトが無くても呼び出せるようになってるんだ。
えっ、そんなコトできるの?
うん。オブジェクトを作らなくても“クラス名.メソッド名(引数)”って感じに呼び出せるの。
クラス名が“ExtendedMover”、 メソッド名が“beginMove”、 引数が“mp”だから“ExtendedMover.beginMove(mp)”になるわけね。
ちなみにこういうオブジェクトを作らなくても呼び出せるメソッドのことを静的メソッドって言うんだ。
へぇ、静的メソッドねぇ…
でも今まではオブジェクトを作らないとメソッドって呼び出せなかったよね?
ある条件をみたしてるメソッドだけが静的メソッドだからね。
それ以外のメソッドはオブジェクトが無いと呼び出せないよ。
ある条件…って?
『メソッドの中でメンバ変数やプロパティにアクセスしたり自分のクラスのメソッドを呼び出したりしてない』っていうのが静的メソッドの条件だよ。
(注)TJS における静的メソッドは『静的メソッド内では自身のクラスのいかなるメソッドも(そのメソッドが静的メソッドであっても)呼び出すことができない』という点で Java や C++ 等のオブジェクト指向プログラミング言語における静的メソッド(静的メンバ関数)とは若干性質が異なっています。また、ここでは beginMove メソッドを便宜上静的メソッドと呼ぶことにしていますが、TJS では静的メソッドという用語は正式に定義されていません。
えっと、ちょっとよくわからないかも…
じゃあ簡単な例で説明するね。
ちょっとこのスクリプトを見てみて。

<現在の年の情報を扱う Year クラス>

class Year
{
    // メンバ変数
    var member_year;

    // コンストラクタ
    function Year()
    {
        var d = new Date();
        member_year = d.getYear();
    }

    // デストラクタ
    function finalize()
    {
    }

    // 静的メソッド
    function displayYear1()
    {
        var d = new Date();
        System.inform("今年は " + d.getYear() + " 年です。");
    }

    // 静的メソッドではない(メンバ変数を参照しているので)
    function displayYear2()
    {
        System.inform("今年は " + member_year + " 年です。");
    }

    // 静的メソッドではない(プロパティを参照しているので)
    function displayYear3()
    {
        System.inform("今年は " + property_year_1 + " 年です。");
    }

    // 静的メソッドではない(自身のクラスのメソッドを呼び出しているので)
    function displayYear4()
    {
        displayYear1();
    }

    // 静的プロパティ
    property property_year_1
    {
        getter()
        {
            var d = new Date();
            return d.getYear();
        }
    }

    // 静的プロパティではない(メンバ変数を参照しているので)
    property property_year_2
    {
        getter()
        {
            return member_year;
        }
    }

    // 静的プロパティではない(プロパティを参照しているので)
    property property_year_3
    {
        getter()
        {
            return property_year_1;
        }
    }
}

…これホントにカンタンな例なの?
なんかそうは見えないんだけど…
確かにスクリプトはちょっと長いけど、やってることは単純だから。
じゃ最初は displayYear1 っていうメソッドを見てみて。
あ、Date クラスだ。ひさしぶり〜。
Date クラスについては §1.2§1.3 参照。
このメソッドの中には今まで使ったことないメソッドはないから、何やってるかはわかるよね?
う〜ん、大体わかるけど…
文字列の足し算って文字列をつなぎ合わせるんだったっけ?
※文字列の足し算については §1.6 参照。
そだよ。だから、例えば "a" + "b""ab" になるね。
そっか。
あ、でも getYear メソッドの戻り値って文字列じゃなくて数字だよね?
文字列と数値を足し算するとどうなるかは前にやったよね。
それってかなり前だったよーな…
えーと、確かフツーに足し算できたんじゃなかったかなぁ?
例えば "a" + 1 だと "a1" みたいな?
それを普通の足し算って言うかどうかはビミョーだけど、まぁそれで合ってるよ。
正確に言うと、"a" + 1 の場合は数値が文字列に変換されて、"a" + "1" になるから、結局足し算の結果は "a1" になるわけね。
あ、そーいえばそんな感じだったね。
あと、“d.getYear()”の戻り値がどんな値になるかは覚えてる?
getYear メソッドの戻り値は年の値だったよね。
今年は 2009 年だから、 今 getYear メソッドを呼び出すと 2009 が戻り値になるよね。
※コンストラクタの引数を省略して Date クラスのオブジェクトを作った場合。
そうだね。
ここまでわかれば displayYear1 メソッドを呼び出すとどうなるかはわかるでしょ?
ん〜っと、じゃあ結局“System.inform("今年は 2009 年です。")”が実行されることになるんだと思うから、 「今年は 2009 年です。」っていうメッセージが表示されるのかな?
System.inform メソッドについては §0.2 参照。
そうそう。
それじゃ次は displayYear2 メソッドを見てみて。
なんかさっきの displayYear1 メソッドと似てるけど…さっきは“d.getYear()” だったとこが、 今度は“member_year”になってるね。
これってメソッドの中で宣言されてないから、メンバ変数なのかな?
そうだよ。
ちなみに member_year にはコンストラクタで値を代入してるよ。
member_year にも getYear メソッドの戻り値を代入してるんだね。
そ。じゃあ displayYear2 メソッドを呼び出すとどうなるかはわかるよね?
displayYear1 メソッドを呼び出した時とおんなじで、 「今年は 2009 年です。」っていうメッセージが表示されるんじゃない?
そうそう。んじゃ次は displayYear3 メソッドね。
なんかこのメソッドも呼び出したら displayYear2 メソッドとかとおんなじ結果になりそーだよね…
ま一応ちゃんとチェックしとこっか。
今度はさっき“member_year”だったとこが“property_year_1”になってるみたいだけど…これもメンバ変数?
ううん、これはメンバ変数じゃなくて、ここに書いてある通りプロパティだよ。
プロパティ…ってメンバ変数みたいに使えるんじゃなかったっけ?
確かにそうなんだけど、プロパティはもうちょっと複雑なことができて、 例えばこの property_year_1 っていうプロパティは getter しか定義されてないから読み取り専用なの。
※プロパティの詳細については §2.5 参照。
読み取り専用ってことは、値を参照できるけど代入はダメってこと?
そうそう。
で、property_year_1 プロパティの getter を見てもらうと…
また getYear メソッドだ…
ってワケだから、displayYear3 メソッドを呼び出すとどうなるかはもうわかるよね?
やっぱり「今年は 2009 年です。」っていうメッセージが表示されるんだね…
そ。じゃ最後は displayYear4 メソッドね。
もう中身見なくても呼び出すとどーなるかは予想できるケド…
まぁまぁ、とりあえず見てみてよ。
displayYear1 メソッドを呼び出してるだけみたいだから…
やっぱり displayYear1〜displayYear4 って呼び出したら全部同じ結果になるメソッドってことだよね。
確かに普通に Year クラスのオブジェクトを作ってから、 この4つのメソッドを呼び出すと全部同じ結果になるんだけど…

displayYear1〜displayYear4 メソッドを静的メソッドとして呼び出すスクリプト>

try
{
    Year.displayYear1();
}
catch(e)
{
    System.inform("displayYear1 メソッド実行中に例外が発生しました。\n" + e.message);
}

try
{
    Year.displayYear2();
}
catch(e)
{
    System.inform("displayYear2 メソッド実行中に例外が発生しました。\n" + e.message);
}

try
{
    Year.displayYear3();
}
catch(e)
{
    System.inform("displayYear3 メソッド実行中に例外が発生しました。\n" + e.message);
}

try
{
    Year.displayYear4();
}
catch(e)
{
    System.inform("displayYear4 メソッド実行中に例外が発生しました。\n" + e.message);
}

こうやって、それぞれのメソッドを静的メソッドとして呼び出そうとすると、 全部おんなじ結果にはならないんだ。
静的メソッドって、さっき言ってたオブジェクトを作らなくても呼び出せるメソッドのこと、だよね?
そ。だからオブジェクトを作らずに、 “Year.displayYear1();”っていうふうに“クラス名.メソッド名();”でそれぞれのメソッドを呼び出してるでしょ。
確かにそーなってるね。
ところで、全部 try ブロックと catch ブロックが書いてあるけど、 これって例外が起きるかもしれないってことなんだよね?
※例外処理については §3.12§3.13 参照。
ん、静的メソッド以外はオブジェクトを作らずに呼び出そうとすると例外が起きるからね。
ってワケで、どのメソッドがちゃんと呼び出せて、 どのメソッドが呼び出せない(つまり例外が起きるってことね)のか、実際に実行して確かめてみて。
スクリプトはこれね。
りょ〜かい。
それじゃ実行してみるね。

displayYear1 メソッドの実行結果>

ちゃんと「今年は 2009 年です。」って表示されたね。
じゃ OK ボタン押して次いって。
はーい。

displayYear2 メソッドの実行結果>

ん? これって例外が起きたってこと?
うん。メッセージボックスに書いてある通りね。
詳しくは後で説明するから、とりあえず次いってみて。
うん。

displayYear3 メソッドの実行結果>

あ、これも例外が起きちゃったみたいだね。
だね。
じゃ次いってみよっか。

displayYear4 メソッドの実行結果>

あ、また例外だ…
結局、静的メソッドとしてちゃんと呼び出せたのは最初の displayYear1 メソッドだけってことだね。
じゃあ displayYear2〜displayYear4 はオブジェクトを作らないと呼び出せないメソッドってことだよね?
そういうこと。
じゃ何でそうなるのかを簡単に確認していこっか。
うん。
まず静的メソッドとして呼び出せなかった displayYear2 メソッドから。
このメソッドは member_year っていうメンバ変数を使ってるでしょ。
そーだね。
こんなふうに、メソッドの中でメンバ変数が使われてると、 そのメソッドは静的メソッドとして呼び出せないんだ。
へぇ、そーなんだ。
何でメソッドの中でメンバ変数が使われてると静的メソッドとして呼び出せなくなるかわかる?
えっ?
う〜ん…ムズカシイ質問だね…
メンバ変数とオブジェクトの関係を考えるとわかるかもね。
メンバ変数とオブジェクトの関係ねぇ…
んー…もしかしてオブジェクトを作らないとメンバ変数も作れないから、とか?
ん、そういうことだね。
えっ、合ってるの?
わりとテキトーに言ってみたんだけど…
メンバ変数はオブジェクトごとに作られるから、例えば…

Year クラスのオブジェクト x, y の生成>

var x = new Year();
var y = new Year();

こんなふうに x っていうオブジェクトと y っていうオブジェクトを作ると、 x 用の member_yeary 用の member_year が別々に作られるのね。
別々に作っとかないと x.member_year を書き換えたら y.member_year も書き換わっちゃうんだよね?
そうそう。
で、オブジェクトごとにメンバ変数が作られるってことは、 逆に言うとオブジェクトを作らなかったらメンバ変数も作られないってことだから、 オブジェクトを作らないとメンバ変数を使うメソッドは呼び出せないってワケ。
だからメンバ変数を使うメソッドは静的メソッドにならないんだね。
そう。
あと、メソッドの中でプロパティを使ってる displayYear3 メソッドと、 メソッドを呼び出してる displayYear4 メソッドなんだけど、 これが静的メソッドとして呼び出せないのは、 TJS には「メソッドの中で自分のクラスのプロパティを使ってたりメソッドを呼び出したりしてる場合は静的メソッドになれない」っていう決まりがあるからなんだ。
※静的メソッドの中で他のクラスの(静的)メソッドを呼び出すことは可能です。また、自身のクラスのオブジェクトを作った上で、そのオブジェクトの任意のメソッドを呼び出すことは可能です。
へぇ、そーなんだ。
あと、静的メソッドがあるからには静的プロパティもあって、 これもオブジェクトを作らなくても使えるんだ。
ちなみにさっき出て来た property_year_1 っていうプロパティも静的プロパティだよ。
(注)便宜上 property_year_1 を静的プロパティと呼ぶことにしていますが、静的メソッド同様、TJS では静的プロパティという用語も正式に定義されていません。
property_year_1 もメンバ変数を使ったりメソッドを呼び出したりしてないから静的プロパティってことなの?
そうそう。
だから、メンバ変数を使ってる property_year_2 とか、 プロパティを使ってる property_year_3 は静的プロパティじゃないわけね。
もちろんメソッドを呼び出してるプロパティも静的プロパティじゃないよ。
えっと、静的プロパティの場合は、例えば“var y = Year.property_year_1;”を実行したら ygetYear メソッドの戻り値が代入されるってことでいいのかな?
ん、そうだよ。
まぁそんなワケだから、exmove マクロ の中に書いてある“ExtendedMover.beginMove(mp)”はちゃんと実行できるのね。
あ、そーいえば元々その話だったよね…
じゃあ、beginMove メソッドは静的メソッドで、 メンバ変数とか自分のクラスのメソッドを使ってないってことなんだね。
そ。で、ExtendedMover クラスの beginMove メソッドの話も一緒にするつもりだったんだけど、 だいぶ長くなっちゃったから、それは次回にまわそっか。
そーだね。最近ホント長いもんね…
ん、それじゃまた次回ね!


前へ | TOP | 次へ