8.3 パズルのピースを作る(その1)

今回はパズルのピース用のクラスを作っていくね。
パズルのピース用のクラスって DraggableLayer クラスじゃないの?
DraggableLayer クラスについては §8.2 参照。
そーなんだけど、パズルのピースとして使うためには DraggableLayer クラスをちょっと改造しなくちゃいけないんだ。
えっ、そーなの?
DraggableLayer クラスは onMouseDown メソッドや onMouseUp メソッドをオーバーライドしてなかったでしょ?
うん、確かにしてなかったけど、それって必要なの?
onMouseDown メソッドはドラッグが始まった時に呼び出されるよね。
そだね。
ピースがドラッグされ始めたら、そのピースを一番手前に表示するために onMouseDown メソッドをオーバーライドするの。
え? なんで一番手前に表示するの?
ドラッグしてるピースより手前に他のピースがあると、ドラッグしてるピースが見づらくなっちゃうからね。
こんなふうに。

<ドラッグしているピースより手前に他のピースがある場合>

ホントだ。ドラッグしてるピースが他のピースの奥に隠れて見えなくなっちゃってるね。
ドラッグしてるピースを一番手前に表示すれば、 こんな感じでいつもドラッグしてるピース全体が見えるから操作しやすいでしょ?

<ドラッグしているピースが一番手前にある場合>

確かにこれなら見やすいね。
onMouseDown メソッドをオーバーライドすれば、 ドラッグが始まった時にピースを一番手前に表示させられるってワケ。
なるほどねぇ。
えっと、じゃあ onMouseUp メソッドをオーバーライドするのは何でなの?
onMouseUp メソッドが呼び出されるのはどんな時だった?
マウスのボタンを離した時だよね?
そ。つまり、ドラッグが終わった時に呼び出されるわけね。
で、ドラッグが終わったら onMouseUp メソッドの中で、 そのピースが正しい位置に置かれてるかどうかチェックするの。
それってどーいうこと?
例えば、下の図の(A)の方はピースが正しい位置に置かれてるけど、 (B)の方はピースの位置が正しくないよね。

<ピースが正しい位置に置かれている場合(A)と正しい位置に置かれていない場合(B)>

そだね。このピースは左下に置かなきゃいけないから、(A)は合ってるけど(B)は間違ってるね。
ドラッグが終わった時にピースの位置をチェックして、もし全部のピースが正しい位置に置かれてたら、 パズルが完成したってことがわかるでしょ。
そっか。じゃあパズルが完成したかどうかチェックするために onMouseUp メソッドを使うんだね。
ん、そういうこと。
それじゃ DraggableLayer クラスを継承して、 パズルのピース用のレイヤ PieceLayer クラスを作ってくね。
まず、コンストラクタとデストラクタ、あとメンバ変数はこんな感じ。

PieceLayer クラスのコンストラクタ・デストラクタ・メンバ変数>

class PieceLayer extends DraggableLayer
{
    var goalLeft, goalTop; // 正しい位置の x, y 座標
    var funcOnMouseDown, funcOnMouseUp; // onMouseDown メソッド、onMouseUp メソッドが呼び出された時に実行するメソッドの参照

    // コンストラクタ
    function PieceLayer(win, par, x, y, mousedownfunc, mouseupfunc)
    {
        // スーパークラスのコンストラクタを呼び出します
        super.DraggableLayer(win, par);
        // 正しい位置の座標を保存しておきます
        goalLeft = x;
        goalTop = y;
        // ドラッグ開始時(onMouseDown メソッドが呼び出された時)と
        // ドラッグ終了時(onMouseUp メソッドが呼び出された時)に
        // 呼び出されるメソッドへの参照を保存しておきます
        funcOnMouseDown = mousedownfunc;
        funcOnMouseUp = mouseupfunc;
    }

    // デストラクタ
    function finalize()
    {
        // スーパークラスのデストラクタを呼び出します
        super.finalize();
    }
}

わりとシンプルな感じだね。
まぁそんなに追加する機能は多くないからね。
じゃまずはコンストラクタから。
なんか引数が4つも増えてるね。
DraggableLayer クラスのコンストラクタ・デストラクタについては §8.2 参照。
onMouseDown メソッドが呼び出された時と onMouseUp メソッドが呼び出された時にそれぞれ呼び出すメソッドへの参照と、 あとこのピースの正しい位置の座標もコンストラクタの引数に指定するようにしたから、引数が4つ増えて全部で6つになったの。
えっと、第1引数の win と第2引数の parDraggableLayer クラスのコンストラクタに指定するのとおんなじなんだよね?
ん、win がこのレイヤが所属するウィンドウで、 par が親レイヤだよ。
第3引数の x と第4引数の y っていうのが、 このピースの正しい位置の座標なの?
そうだよ。
それぞれ goalLeftgoalTop っていうメンバ変数に値を保存しといて、ドラッグが終わった時に、 ピースが正しい位置に置かれてるかどうかチェックする時に参照するんだ。
なるほどね。
あと、第5引数の mousedownfunconMouseDown メソッドが呼び出された時に呼び出すメソッドで、 第6引数の mouseupfunconMouseUp メソッドが呼び出された時に呼び出すメソッドだよね?
そ。それぞれ funcOnMouseDownfuncOnMouseUp っていうメンバ変数に参照を保存しといて、ドラッグが始まった時と終わった時に呼び出すわけね。
次はデストラクタだけど、これは大丈夫だよね?
うん、スーパークラスのデストラクタを呼び出してるだけだよね。
onMouseDown メソッドと onMouseUp メソッドは、 それぞれコンストラクタで保存した funcOnMouseDownfuncOnMouseUp を呼び出せばいいだけだから、ちょっと作ってみて。
あ、呼び出し先で使うから、引数には this を指定しといてね。
わかった。
じゃあ最初は onMouseDown メソッドから作ってみるね。

onMouseDown メソッド>

function onMouseDown(x, y, button, shift)
{
    // ドラッグが始まった時に呼び出すメソッドを呼び出します
    funcOnMouseDown(this);
    // スーパークラスのコンストラクタを呼び出します
    super.onMouseDown(...);
}

これでいいかな?
ん、OK。
それじゃ次は onMouseUp メソッドを作るね。

onMouseUp メソッド>

function onMouseUp(x, y, button, shift)
{
    // ドラッグが終わった時に呼び出すメソッドを呼び出します
    funcOnMouseUp(this);
    // スーパークラスのコンストラクタを呼び出します
    super.onMouseUp(...);
}

こんな感じだね。
ん、こっちも OK。
それじゃ実際に PieceLayer クラスのオブジェクトを作ってみよっか。
うん。
first.ks はこんな感じにしとくね。

PieceLayer クラスのテスト用 first.ks

; DraggableLayer クラスと PieceLayer クラスの定義を読み込みます
[call storage="DraggableLayer.ks"]
[call storage="PieceLayer.ks"]

[iscript]
// ピースの幅と高さを pieceWidth×pieceHeight に設定します
var pieceWidth = 64; // ピースの幅
var pieceHeight = 64; // ピースの高さ
// 正しい位置は表画面の背景レイヤの中央に設定します
var goalLeft = (kag.fore.base.width - pieceWidth) \ 2;// 正しい位置 x 座標
var goalTop = (kag.fore.base.height - pieceWidth) \ 2; // 正しい位置 y 座標

with(kag.fore.base)
{
    // 表画面の背景レイヤを白色で塗りつぶします
    .fillRect(0, 0, .width, .height, 0xFFFFFF);
    // 正しい位置を黒い枠で囲みます
    .fillRect(goalLeft, goalTop, pieceWidth, 1, 0x000000);
    .fillRect(goalLeft, goalTop, 1, pieceHeight, 0x000000);
    .fillRect(goalLeft + pieceWidth - 1, goalTop, 1, pieceHeight, 0x000000);
    .fillRect(goalLeft, goalTop + pieceHeight - 1, pieceWidth, 1, 0x000000);
}

// 表画面の背景レイヤ上にピース用レイヤを作って kag オブジェクトに管理してもらいます
kag.add(global.pieceLayer = new PieceLayer(kag, kag.fore.base, goalLeft, goalTop, onDragStarted, onDragFinished));

// ドラッグが開始された時に実行されるメソッド
function onDragStarted(piece)
{
    // レイヤを赤色で塗りつぶします
    piece.fillRect(0, 0, piece.width, piece.height, 0xFFFF0000);
}

// ドラッグが終了した時に実行されるメソッド
function onDragFinished(piece)
{
    with(piece)
    {
        // レイヤを青色で塗りつぶします
        .fillRect(0, 0, .width, .height, 0xFF0000FF);

        // ピースの x 座標が goalLeft±2 ピクセルの範囲にあって…
        if(.left >= .goalLeft - 2 && .left <= .goalLeft + 2)
        {
            // さらに、ピースの y 座標が goalTop±2 ピクセルの範囲にあれば、
            // ピースが正しい位置に置かれたとみなします
            if(.top >= .goalTop - 2 && .top <= .goalTop + 2)
            {
                // ピースを正しい位置に置いて、
                .setPos(.goalLeft, .goalTop);
                // それ以上動かせなくします
                .enabled = false;
                // ピースが正しい位置に置かれたことを知らせるためにメッセージを表示します
                System.inform("OK");
            }
        }
    }
}

with(pieceLayer)
{
    // ピース用レイヤの画像サイズを pieceWidth×pieceHeight ピクセルに設定します
    .setImageSize(pieceWidth, pieceHeight);
    // レイヤの表示サイズを画像サイズに合わせます
    .setSizeToImageSize();
    // レイヤを青色で塗りつぶします
    .fillRect(0, 0, .width, .height, 0xFF0000FF);
    // 適当な位置に置きます
    .setPos(int (Math.random() * (kag.fore.base.width - .width)), int (Math.random() * (kag.fore.base.height - .height)));
    // 表示状態にします
    .visible = true;
}
[endscript]

うわっ、なんかすごい長いしフクザツ…
う〜ん、一応基本的なことだけやろうと思ったんだけど、確かにちょっと長くなっちゃったね。
かなり長いと思うんだけど…
まぁ、とりあえず実行してみよ。
必要なファイルはここに置いとくから。
う、うん。じゃあ実行してみるね。

<実行結果>

表示されたウィンドウ

なんか白い四角と青い四角が表示されてるけど…?
青い四角がピースで、白い四角が正しい位置を表してるの。
えっと、じゃあピースをドラッグして、白い四角の中に入れればいいってこと?
そういうこと。
それじゃピースをドラッグしてみるね。
ん。

<ピースの上でマウスのボタンを押した時>

あっ、ピースをクリックしたらピースが赤くなった!
ピースの上でマウスのボタンを押したらピースの色を変えるようにしてるからね。
あ、そーなんだ。
ちなみにボタンを離すと元の色に戻るよ。

<マウスのボタンを離した時>

ホントだ。青色に戻ったね。
んじゃ次はピースを白い四角の中までドラッグしてみて。
ちょっとくらいずれてても大丈夫だから。
そうなの?
ん、四角の中にぴったり合わせるのは難しいから、少しずれた位置にピースを置いても、 正しい位置に置けたってみなしてるんだ。
へぇ、そうなんだ。
それじゃあドラッグしてみるね。

<ピースを正しい位置に置いた時>

あ、「OK」って表示された!
これでこのピースは正しい位置に固定されたから、それ以上は動かせなくなってるはずだよ。
確かにドラッグしてももう動かせないね。
パズルのピースの基本的な動作は大体こんな感じだよ。
じゃ、今回はこの辺にしといて、スクリプトの方は次回見ていくことにするね。
あ、スクリプトは次回にするんだ。
ん、見ての通り色々説明することがあるからね。
今から見ていくとかなり長くなっちゃいそうだから。
う〜ん、確かにややこしそうだもんねぇ。
ってワケで、今回はここまで。
それじゃ、また次回ね!


前へ | TOP | 次へ