はじめまして、さくらいみかと申します。

今回はJavaScriptのライブラリであるjQueryを使って、好きな画像を読み込むと自動で「スライドパズル」が生成されるアプリを作ってみました。

パズルの「ブロック」部分を「空きスペース」に移動させて、絵を完成させていきます。子供のころにやったことがある人も多いんじゃないでしょうか。

こういうパズルを作ろうとなったとき、人によってどう実装していくかはかなり違ってくると思います。

今回は基本的なパズルの選択・移動方法について、個人的に「どのような考え方で、どのように作り進めていったか」をまとめてみます。

See the Pen
スライドパズル(1)
by Mika Sakurai (@mika-sakurai)
on CodePen.

▲画像URLを入力し「よみこみ」をクリックすると、任意の画像がスライドパズルに変換されます(※デフォルトでりんごの画像のURLが挿入されています)

1. パズルの外枠を設置する

まず最初にパズルの外枠を作り、その中にパズルを作っていきます。


setOutLine(); // パズルの外枠を設置する

function setOutLine() {
parentBlock = document.createElement("div");
document.body.appendChild(parentBlock);
parentBlock.id = "parentBlock";
parentBlock.style.width = parentWidth+"px";
parentBlock.style.height = parentHeight+"px";
parentBlock.style.position = "relative";
parentBlock.style.border = "2px solid #000000";
parentBlock.style.border = "2px solid #000000";
}

2. ブロックの配置方法を決める

続いて「どこを“空きスペース”として設定するか」「どうやってブロックをバラバラに表示させるか」を決めていきます。

2-1. パズルのスペースとIDのルールについて

各スペースに「行番号_列番号」というルールでIDを付けていきます。

まずはスライドバーを操作し、行と列の数を決定します。例えば3行×3列のばあい、以下のようなルールでスペースIDを付けます。

2-2. 空きスペースをランダムに決める

9つのスペースがあるうち「どこが空きスペースか」を決めます。

このスライドパズルでは、ランダムな位置を空きスペースとして指定します。

 //パズルのスペースとIDを決め、空きスペースをランダムに決める
var rnd = Math.floor(Math.random()*((W*H)-1)); // [空きスペースの位置をランダムに取得] 0~(マス目の数-1)までの整数から、ランダムに数値を取得する
var counter = 0;
for (var cnt1=0; cnt1<H; cnt1++) {
for (var cnt2=0; cnt2<W; cnt2++) {
if (counter == rnd) { // ランダムに取得した値とcounterの値が一致したときに、空きスペースIDをセットする
blankId = cnt1+"_"+cnt2; // 空きスペースID
}
blockIdArr[counter] = cnt1+"_"+cnt2;
counter++;
}
}

2-3. パズルをランダムに配置するために、ブロック番号を並び替える

ブラウザ上のフォームから画像のURLを読み込ませ、読みこんだ画像をブロック上に表示させます。

imgObj = new Image();
imgObj.src = url;
imgObj.onload = function() {
/**ここに「3. ブロックをランダムに並び替えて配置する」の処理を書く**/
}

続いて「ブロックをどうバラバラに配置するか」を決めます。まず、ブロックに番号を振ります。

1~9のブロック番号を並べ替えます。

blockIdArr = getRandamArray(blockIdArr); // 配列をランダムに並び替えて取得

3. ブロックをランダムに並び替えて配置する

画像の読み込み完了後、ブロック用オブジェクトを生成し、並び替えたブロック番号の順に配置します。

スペースIDの箇所にはブロックを配置しないようにすると、空きスペースができます。

// IDをもとに、そのブロックに表示される画像の位置・大きさ情報を設定
var rand1 = blockIdArr[counter].split("_")[1];
var rand2 = blockIdArr[counter].split("_")[0];
var sx = (imgObj.width/W)*rand1;
var sy = (imgObj.height/H)*rand2;
var sw = imgObj.width/W;
var sh = imgObj.height/H;
var dx = 0;
var dy = 0;
var dw = canvas.width;
var dh = canvas.height;

var context = canvas.getContext("2d");
context.lineWidth = 1; // 枠線の太さ
// 画像を配置
context.drawImage(imgObj,sx,sy,sw,sh,dx,dy,dw,dh);
context.beginPath();
context.strokeRect(0, 0, dw, dh);
canvas.addEventListener("click", clickEv, true);

4. ブロックを移動させる

最後にクリックしたブロックを「空きスペース」に移動させ、ブロックが移動させる処理を行います。これで好きな場所にブロックを移動させられるようになります。

4-1. クリックしたブロックの隣に「空きスペース」があるかを判定する

例えば「2_3」のスペースにあるブロックをクリックしたばあい、隣のスペースは空いているので移動させられますね。

以下の2つのIDを比較し、ブロックが移動可能かどうかを判定します。

  • クリックしたブロックがあるスペースID:「2_3」
  • 空きスペースID:「1_3」

IDのルールは「行番号_列番号」なので、以下の2条件を満たしていれば、「クリックしたスペースと空きスペースは隣接している」と判定できます

  • 行番号、または列番号が一致している
  • 行番号、または列番号(一致してない方)の差が1
// クリックしたブロックの隣に「空きスペース」があるかを判定する
// 動かすブロック、空きスペースの情報を取得
var moveId = comp.id.replace("block","") // 動かすブロックID
var moveId0 = moveId.split("_")[0]; // 動かすブロックの行ID
var moveId1 = moveId.split("_")[1]; // 動かすブロックの列ID
var blankId0 = blankId.split("_")[0]; // 空きスペースの行ID
var blankId1 = blankId.split("_")[1]; // 空きスペースの列ID
var moveFlg = false; // 判定フラグ
if (moveId0 == blankId0) {
if (Math.abs(moveId1-blankId1) == 1) { // 動かすブロックと空きスペースが隣り合ってる
moveFlg = true;
}
} else if (moveId1 == blankId1) {
if (Math.abs(moveId0-blankId0) == 1) { // 動かすブロックと空きスペースが隣り合ってる
moveFlg = true;
}
}

4-2. ブロックを移動させる

動かしたいブロックと空きスペースが隣接しているばあい、ブロックの位置を入れ替えます。

if (moveFlg) { // 移動可能な場合、クリックしたブロックを空きスペースに移動させる
// クリックしたスペースIDと空白スペースIDを入れ替える
var _moveId = moveId;
moveId = blankId;
blankId = _moveId;
// ブロックの位置を入れ替える
comp.style.top = comp.height*blankId0+"px";
comp.style.left = comp.width*blankId1+"px";
comp.id = "block"+blankId0+"_"+blankId1;
}

まとめ

今回は、スライドパズルを作る際にどう考えたかという基本的な部分をまとめてみました。

本来この手のパズルは「スライド」の動作でブロックを移動させますが、現在は「クリック」動作で移動させています。なので今はまだ「スライドパズル」とはいえないかもしれません。

今後「ブロックのスライド」に関わるアニメーションの実装など、機能を盛り込んでいく予定です。次回もお楽しみに!

 

次回の記事▼

SHARE

RELATED

  • お問い合わせ
  • お問い合わせ
  • お問い合わせ