画像を使ったジグソーパズルを作ってみよう - jQuery入門
目次
- jQuery入門
- jQueryのインストール・簡単な使い方
- クイズゲームの作り方
- 秘密の暗号を作ってみよう(たぬき暗号)
- アクションゲームを作ってみよう(ぬりかべ)
- 画像を使ったジグソーパズルを作ってみよう
- もぐらたたきっぽいゲーム
- ドラッグ可能なポップアップウインドウを作ろう
- jQuery UI Sortableで1ラインオセロゲーム
- ブラウザ全体をブロックしてみる
- Geolocation APIを使って都道府県のセレクトボックスを現在地に近い順にソートする
- 発生したイベントの状態を保持・保存する6つのパターン
- Ajaxを利用したシンプルなイメージギャラリーを作ってみる
- テーブルにページ送り(ページング)を実装してみる
- jQuery UI Draggableを使って付箋(sticky)を作ってみる
- カラムでソートできるテーブルを自作してみる
- テーブルを使ったシンプルなドット絵エディタを作ってみる
- iPhoneのようにマウスではじいてスクロール(フリックスクロール)を実装してみる
- テキストフィールドの数値をマウスの上下移動で増減する
- iPhoneのように大きい画像の表示領域をマウスのドラッグで移動してみる
- iPhoneのように画像をダブルクリックした地点を中心に拡大縮小する
- リアルタイムプレビュー付きのHTMLエディタを作ろう
- 保存できる付箋を作ってみる(Cookie、localStorage)
ジグソーパズル
jQuery入門第6回目は、画像を使った簡易ジグソーパズルゲームを作ってみます。簡易的なものなので、ピースの凹凸はありません。今回のポイントはCSSによって画像の一部分のみを指定する方法(background-position)です。まずはプレイ画面をどうぞ。実行結果
2つのピースをクリックすると入れ替わります。元の絵に戻すとクリアです。簡易ジグソーパズルのソース
完成画像
まず完成画像を縦横320ピクセルのサイズの「pict.jpg」という名前で用意してください。サンプルを以下に示します。ソース
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
<title>ジグソーパズル</title>
<script>
var sel = -1; // 現在選択されているピース番号
var pos = []; // 各ピースの現在位置
$(function() {
for (var i = 0; i < 16; i++) pos[i] = i;
// シャッフルする。
for (var i = 16; i > 0; i--) {
var j = Math.floor(Math.random() * i);
swap(i - 1, j);
}
// ピースを配置する。
for (var i = 0; i < 16; i++) {
$('<div id="piece' + i + '" class="piece"></div>').css({
backgroundPosition: '-' + getx(i) + 'px -' + gety(i) + 'px',
left: getx(pos[i]), top: gety(pos[i])
}).appendTo($('body'));
}
// ピースをクリックしたとき
$('.piece').click(function() {
var no = this.id.substring(5);
if (sel == no) {
// 自分自身が選択されているときは選択をキャンセルする。
$(this).fadeTo(100, 1);
sel = -1;
} else if (sel == -1) {
// 何も選択されていないときは選択する。
$(this).fadeTo(100, 0.5);
sel = no;
} else {
// 他のピースが選択されているときは入れ替える。
swap(no, sel);
$('#piece' + sel).fadeTo(100, 1).animate({left: getx(pos[sel]), top: gety(pos[sel])});
$(this).animate({left: getx(pos[no]), top: gety(pos[no])}, function() {
// アニメーション終了時にクリア判定する。
var clear = true;
for (var i = 0; i < 16; i++) if (pos[i] != i) clear = false;
if (clear) alert("クリア!");
});
sel = -1;
}
});
});
// ピースの番号から座標を得る。
function getx(n) {return (n % 4) * 80;}
function gety(n) {return Math.floor(n / 4) * 80;}
// ピースの配列を入れ替える。
function swap(i, j) {
var tmp = pos[i];
pos[i] = pos[j];
pos[j] = tmp;
}
</script>
<style>
.piece {
width: 80px;
height: 80px;
background-image: url('pict.jpg');
position: absolute;
}
</style>
</head>
<body>
</body>
</html>
プログラムの解説
グローバル変数
var sel = -1; // 現在選択されているピース番号
var pos = []; // 各ピースの現在位置
ピースには0~15の「ピース番号」が付いています。画像の位置に対するピース番号は以下の通り。0 | 1 | 2 | 3 |
4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 |
ピースのシャッフル
for (var i = 0; i < 16; i++) pos[i] = i;
まず初期値として、完成形で配列posを作ります(添え字が中の値と等しい)。
for (var i = 16; i > 0; i--) {
var j = Math.floor(Math.random() * i);
swap(i - 1, j);
}
その後、配列posの中身がバラバラになるようにシャッフルしています。「Fisher-Yates」というアルゴリズムを使っていますので、詳しくはググってみてください。画面上にピースを配置する
for (var i = 0; i < 16; i++) {
$('<div id="piece' + i + '" class="piece"></div>').css({
backgroundPosition: '-' + getx(i) + 'px -' + gety(i) + 'px',
left: getx(pos[i]), top: gety(pos[i])
}).appendTo($('body'));
}
今回のポイントである、画像の一部をCSSで指定して画面上に配置している部分です。「piece + ピース番号」というidを付けたdiv要素にCSSを設定しbodyに追加しています。background-positionは背景画像の表示開始位置を決めるプロパティなのですが、マイナスの値を設定すると開始位置を逆方向に設定する、つまり画像の途中から表示させることが可能になるのです。例えば「background-position: -80px -160px」とすると、画像の左端から80ピクセル、上端から160ピクセルの位置から画像を表示させることができます。JavaScriptの仕様でプロパティ名にはハイフンが使えないので「backgroundPosition」と書くことに注意してください。getxとgetyは、最下部に定義してありますが、ピース番号を指定するとその座標を返してくれる関数です。「left: getx(pos[i]), top: gety(pos[i])」によって、シャッフルされた位置にピースを持ってきています。
ピースをクリックしたときの処理
var no = this.id.substring(5);
それぞれのピースのidは「piece + ピース番号」なので、変数noには「piece」という文字をスキップしたピース番号が入ります。
if (sel == no) {
// 自分自身が選択されているときは選択をキャンセルする。
$(this).fadeTo(100, 1);
sel = -1;
選択されているピースを再度選択したときに、選択解除しています。fadeToは透明度を変更するjQueryのメソッドで、透明度は0~1(0が完全に透明、1が完全に不透明)で指定します。今回は100msかけて透明度1になります。
} else if (sel == -1) {
// 何も選択されていないときは選択する。
$(this).fadeTo(100, 0.5);
sel = no;
何も選択されていないときはクリックされたピースを選択状態にしています。100msかけて透明度0.5(半分透けている状態)にしています。
swap(no, sel);
ピースを交換する場合は、まずpos配列の中のクリックされたピース番号と選択されているピース番号を入れ替えます。
$('#piece' + sel).fadeTo(100, 1).animate({left: getx(pos[sel]), top: gety(pos[sel])});
選択されているピースの透明度を元に戻し、クリックされたピースの位置へ移動するアニメーションを行なっています。
$(this).animate({left: getx(pos[no]), top: gety(pos[no])}, function() {
// アニメーション終了時にクリア判定する。
var clear = true;
for (var i = 0; i < 16; i++) if (pos[i] != i) clear = false;
if (clear) alert("クリア!");
});
クリックされたピースを選択されているピースの位置へ移動するアニメーションを行なっています。さらにアニメーションが終わったときのコールバック関数を指定し、そこでクリア条件のチェックをしています。クリア条件は、pos配列全ての要素の添え字がその要素の値と等しい時です。ピースのスタイルシート
.piece {
width: 80px;
height: 80px;
background-image: url('pict.jpg');
position: absolute;
}
各ピースに割り当てられているCSSです。pict.jpgは320×320ピクセルの画像なのですが、widthとheightプロパティによって幅と高さを80ピクセルに固定し、縦横とも4分割で表示するための準備をしています。さらにpositionをabsoluteに設定することによって画面上の自由な位置にピースを表示できるようにします。まとめ
- 「position: absolute」によって絶対位置指定をし、「left」と「top」プロパティによって位置を指定する。
- 「background-position」プロパティにマイナスの値を指定することによって、画像の途中から表示を始めることができる。
- 「background-position」プロパティをjQueryで指定するときは「backgroundPosition」と書く。