15 PUZZLE Ver.1.03(写真説明追加)

20131124a

ゲームをクリアした後に、写真の下に説明文を表示するようにしました。

映画「スターウォーズ」最新作エピソード7が2015年12月18日に公開予定らしい。

まだまだ、だいぶ先の話ですが、今から楽しみです。

そんなこんなで、今回は、写真に星雲・星団・銀河を使用してみました。

画像はネット上から、説明文はウィキペディアのサイトから拝借いたしました。

説明文がどのように表示されるかは、画像をクリックして実際にゲームを試してみて下さい。



ますます汚くなってきたソースはこちら。


<!doctype html>
<html lang="ja">
<head>
	<meta charset="utf-8">
	<title>15パズル</title>
	<meta name="viewport" content="width=600">
	<link rel="stylesheet" type="text/css" href="../css/15-puzzle.css">
	<script type="text/javascript" src="../js/15-puzzle103.js">
	</script>
</head>
<body onload="init()">
	<div id="top_title"></div>
	<canvas id="gameCanvas" width="600" height="600"></canvas>
	<div id="pict_txt"></div>
</body>
</html>

// 各種設定
var PICTURES = ["star_IC434_batou.jpg", "star_M1_kani.jpg", "star_M2_ring.jpg", "star_M3_kyujyou.jpg", "star_M16_washi.jpg","star_M20_sanretsu.jpg","star_M27_areijyou.jpg","star_M31_andromeda.jpg","star_M42_orion.jpg","star_M45_pleiades.jpg","star_M51_komochi.jpg","star_M77.jpg","star_M83.jpg","star_M94.jpg","star_M104_sombrero.jpg","star_NGC2237_bara.jpg"];
var PICT_TXT = [
"馬頭星雲、IC434<br>オリオン座にある暗黒星雲である。オリオン座の三ツ星の東端にあるζ星アルニタクの約27\'南に位置する。その名前の通り、馬の頭に似た形で非常に有名な星雲で、散光星雲IC434を背景に馬の頭の形に浮かびあがって見える。この星雲は巨大な暗黒星雲の一部である。1888年にハーバード大学天文台の写真観測によって初めて発見された。",
"かに星雲、M1<br>おうし座にある超新星残骸で、1731年にイギリスの開業医でありアマチュア天文家のジョン・ベヴィスによって発見された。ウィリアム・パーソンズの観測で微細なフィラメント構造がカニの足を思わせることからカニ星雲と命名された。地球からの距離はおよそ7000光年。典型的なパルサー星雲で、現在も膨張を続けており、中心部には「かにパルサー」と呼ばれるパルサーの存在が確認されている。超新星自体は1054年に出現したことが中国や日本の記録に残されている。",
"リング状星雲、M2<br>こと座にある惑星状星雲である。地球からの距離は約2600光年。リング状の特徴的な姿をしており、惑星状星雲の中では最も有名な天体の一つで、「リング星雲」「ドーナツ星雲」の別名がある。惑星状星雲としてはM27に次いで発見された。",
"球状星団、M3<br>りょうけん座にある。大きく明るい球状星団の一つで、およそ500,000の星からなる。地球からの距離は約33900光年。見かけの等級は6.2だが肉眼では5.8等であるとする人もおり、ぎりぎり最良の観測地では肉眼で見えるとする人もいる。ただその際、隣の6等級の恒星との分離が難しい。",
"わし星雲、M16<br>へび座に位置する散開星団と散光星雲の複合した天体である。散開星団の背景に散光星雲が広がっており、メシエ天体としての番号M16は散開星団の方に付けられた番号である。散光星雲にはIC4703という番号が付けられている。",
"三裂星雲、M20<br>いて座にある散光星雲。星雲が3つの部分に裂けて見えるところから三裂星雲と呼ばれている。ただし、実際に星雲が3つに分割されているわけではなく、M20の輝いて見える散光星雲の手前に位置する暗黒星雲の姿により、後ろの散光星雲が3つに分割されているように見えている。",
"亜鈴状星雲、M27<br>こぎつね座にある惑星状星雲である。地球からの距離は約820光年。その形が鉄亜鈴に似ていることから名づけられている。",
"アンドロメダ星雲、M31<br>アンドロメダ座に位置する目視可能な渦巻銀河である。さんかく座銀河、銀河系(天の川銀河)、大マゼラン銀河、小マゼラン銀河などとともに局部銀河群を構成する。銀河系外の天体でありながら、ケフェイド変光星を利用して距離が測定されたことでも知られる。",
"オリオン大星雲、M42<br>オリオン座の三ツ星の南の小三ツ星の中央にある散光星雲である。肉眼で見える星雲の中で干潟星雲(M8)と並び最も明るいものの一つである。地球から約1,600光年の距離にあり、約33光年の実直径を持つと考えられている。低倍率の双眼鏡でもはっきりと見ることができる。肉眼では通常緑がかった色に見える。",
"プレアデス星団、M45<br>おうし座にある散開星団で、和名は「すばる」。地球から400光年の距離にあり、肉眼でも輝く5–7個の星の集まりを見ることができる。双眼鏡で観測すると数十個の青白い星が集まっているのが見える。比較的近距離にある散開星団であるため狭い範囲に小さな星が密集した特異な景観を呈しており、このため昔から多くの記録に登場し、各民族で星座神話が作られてきた。",
"子持ち銀河、M51、NGC5194<br>りょうけん座にある渦巻銀河。4\' 35\" 離れたすぐ近くに伴銀河NGC 5195があることが名前の由来であり、伴銀河を含めて子持ち銀河と呼ぶ場合もある(このときNGC 5194をM51A、NGC 5195をM51Bと表記することがある)。",
"銀河、M77<br>くじら座にある渦巻銀河。6000万光年も離れているのに、みかけの直径は大きく明るい。実際の広がりが17万光年と大きな渦状銀河で、中心部が明るく輝くセイファート銀河である。",
"銀河、M83<br>うみへび座にある渦巻銀河。",
"銀河、M94<br>りょうけん座にある渦巻銀河。",
"ソンブレロ銀河、M104<br>おとめ座にある銀河。通称はソンブレロ(メキシコで広く用いられるツバの広い帽子)を横から見た姿に似ていることから付けられている。",
"薔薇星雲、NGC2237<br>いっかくじゅう座に位置する散光星雲。肉眼で見ることはできないが、望遠鏡に干渉フィルターを用いることで視認することができる。 写真に写すと真紅のバラの花飾り(ロゼット)のような姿に見えることからバラ星雲(ばら星雲)とよばれている。(英名: The Rosette Nebula)"];
var PICTURE_URL = "star_IC434_batou.jpg";	// 画像ファイルのURL
var PICTURE_TXT = "";	// 写真の説明
var menu_msg = "<h1>15 PUZZLE MENU (写真" + PICTURES.length + "枚)</h1>";	// MENUのタイトル
var play_msg = "<h1>15 PUZZLE</h1>";	// PUZZLEのタイトル
var clear_msg = "<h1>15 PUZZLE CLEAR !</h1>";	// PUZZLE クリア時のタイトル
var BLOCK_W = 150;	// ブロックの幅
var BLOCK_H = 150;	// ブロックの高さ
var ROW_COUNT = 4;	// 列を何枚に切るか
var COL_COUNT = 4;	// 行を何枚に切るか
var NUM_BLOCKS = ROW_COUNT * COL_COUNT;
// 上下左右の相対座標を定義したもの
var UDLR = [[0,-1],[0,1],[-1,0],[1,0]];
// ゲーム全体で使う変数
var context, image, selImage;	// 描画用
var selBlocks = [];	// 各ブロックを管理する配列変数
var blocks = [];	// 各ブロックを管理する配列変数
var isLock;	// マウス操作をロックするかどうか
var selFlag = true;	// 画像選択フラグ
var clearFlag = false;	// ゲームクリアフラグ
// 初期化処理
function init() {
	// 描画コンテキストの取得
	var canvas = document.getElementById("gameCanvas");
	if (!canvas.getContext) {
		alert("Canvasをサポートしていません。");
		return;
	}
	context = canvas.getContext("2d");
	// マウスイベントの設定
	canvas.onmousedown = mouseHandler;
	// 画像を選択
	selectImage();	// ■画像1枚でMENU表示へ
	// メニュー用画像を縮小表示
 // 画像キャプチャー用(使用時は上記selectImageを無効に下記を有効に)
 // drawMenu();	// ■PICTURES縮小でNEMU表示へ
}
// ゲーム画像の選択画面(MENU)を表示
function selectImage() {
	document.getElementById('top_title').innerHTML = menu_msg;
	selFlag = true;
	// 画像を描画
	selImage = new Image();
	selImage.src = "menu_star.jpg?" + new Date().getTime();	// IE対策
	selImage.onload = function() {
		context.drawImage(selImage, 0, 0);
	}
}
// ゲーム開始時の画面を描画する(画像キャプチャー用)
// この関数はMENU画像作成時にのみ使用
function drawMenu() {
	document.getElementById('top_title').innerHTML = menu_msg;
	for (var i = 0; i < PICTURES.length; i++) {
		// 描画先座標を計算
		var dx = (i % COL_COUNT) * BLOCK_W;
		var dy = Math.floor(i / COL_COUNT) * BLOCK_H;
		selImage = new Image();
		selImage.src = PICTURES[i];
		// 画像を縮小して描画
		context.drawImage(selImage, 0, 0, 600, 600, dx, dy, BLOCK_W, BLOCK_H);
		// 描画の枠を表示
		context.beginPath();
		context.strokeStyle = "white";
		context.lineWidth = 3;
		context.rect(dx, dy, BLOCK_W, BLOCK_H);
		context.stroke();
		context.closePath();
	}
}
// ゲーム開始
function gameStart() {
	document.getElementById('top_title').innerHTML = play_msg;
	// メイン画像を読み出す
	image = new Image();
	image.src = PICTURE_URL;
	image.onload = initGame;	// 読み込んだらゲームを初期化
}
// ゲームの初期化
function initGame() {
	isLock = true;	// ユーザ操作をロックする
	// パズルのブロックを作成する
	for (var i = 0; i < NUM_BLOCKS; i++) {
		blocks[i] = i;
	}
	// 末尾(右下)を空きブロックとする
	blocks[NUM_BLOCKS -1] = -1;
	drawPuzzle();	// 見本を表示する
	// 1秒後にシャッフルを開始する
	setTimeout(shufflePuzzle,1000);
}
// パズルの各ピースをシャッフルする
function shufflePuzzle() {
	var scount = 160;	// シャッフルする回数を指定
	var blank = NUM_BLOCKS - 1;	// 空きブロック位置
	// 一回のみシャッフルを行う関数
	var shuffle = function () {
		scount--;
		if (scount <= 0) {
			isLock = false;	// ゲーム開始
			return;
		}
		var r, px, py, no;
		while (1) {
			r = Math.floor(Math.random() * UDLR.length);
			px = getCol(blank) + UDLR[r][0];
			py = getRow(blank) + UDLR[r][1];
			if (px < 0 || px >= COL_COUNT) continue;
			if (py < 0 || py >= ROW_COUNT) continue;
			no = getIndex(px, py);
			break;
		}
		blocks[blank] = blocks[no]
		blocks[no] = -1;
		blank = no;
		drawPuzzle();
		setTimeout(shuffle, 2);
	};
	shuffle();
}
// パズルの画面を描画する
function drawPuzzle() {
	for (var i = 0; i < NUM_BLOCKS; i++) {
		// 描画先座標を計算
		var dx = (i % COL_COUNT) * BLOCK_W;
		var dy = Math.floor(i / COL_COUNT) * BLOCK_H;
		// 描画元座標を計算
		var no = blocks[i];
		if (no < 0) {	// 空きブロック
			context.fillStyle = "#0000FF";
			context.fillRect(dx, dy, BLOCK_W, BLOCK_H);
		} else {
			var sx = (no % COL_COUNT) * BLOCK_W;
			var sy = Math.floor(no / COL_COUNT) * BLOCK_H;
			// 画像の一部を切り取って描画
			context.drawImage(image, sx, sy, BLOCK_W, BLOCK_H, dx, dy, BLOCK_W, BLOCK_H);
		}
		// 描画の枠を表示
		context.beginPath();
		context.strokeStyle = "white";
		context.lineWidth = 3;
		context.rect(dx, dy, BLOCK_W, BLOCK_H);
		context.stroke();
		context.closePath();
		// ブロック番号を描画する
		context.fillStyle = "rgba(255, 255, 255, 0.8)";
		context.font = "bold 48px Arial";
		var cx = dx + (BLOCK_W - 40) / 2;
		var cy = dy + BLOCK_H /2;
		if (no != -1){
			context.fillText((no+1), cx, cy);
			context.strokeStyle = "black";
			context.strokeText((no+1), cx, cy);
		}
	}
}
// マウスで移動先をクリックした時の処理
function mouseHandler(t) {
	if (isLock) return;
	if (selFlag) {	// ----- MENU のマウス処理 -----
		// タッチ座標の取得
		var px = t.offsetX, py = t.offsetY;
		if (px == undefined) {	// FireFox対策
			var p = t.currentTarget;
			px = t.layerX - p.offsetLeft;
			py = t.layerY - p.offsetTop;
		}
		// 何番目の画像をクリックしたのか計算する
		var px2 = Math.floor(px / BLOCK_W);
		var py2 = Math.floor(py / BLOCK_H);
		var selNo = getIndex(px2, py2);
		PICTURE_URL = PICTURES[selNo];
		PICTURE_TXT =	PICT_TXT[selNo];	// 選択した写真の説明を変数にセット
		// document.getElementById('pict_txt').innerHTML = PICTURE_TXT;	// 写真説明を表示(確認用)
		selFlag = false;
		gameStart();
	}else{
		if (clearFlag) {	// ----- CLEAR 時の処理 -----
			clearFlag = false;
			document.getElementById('pict_txt').innerHTML = "";	// 写真説明を消去
			selectImage();	// 再度ゲームを実行
		}else{	// ----- PUZZLE プレイ中のマウス処理 -----
			// タッチ座標の取得
			var px = t.offsetX, py = t.offsetY;
			if (px == undefined) {	// FireFox対策
				var p = t.currentTarget;
				px = t.layerX - p.offsetLeft;
				py = t.layerY - p.offsetTop;
			}
			// 何番目のピースを動かしたいのか計算する
			var px2 = Math.floor(px / BLOCK_W);
			var py2 = Math.floor(py / BLOCK_H);
			var no = getIndex(px2, py2);
			// 空白ブロックなら動かせない
			if (blocks[no] == -1) return;
			// 上下左右に動かせるブロックがあるか確認
			for (var i = 0; i < UDLR.length; i++) {
				var pt = UDLR[i];
				var xx = px2 + pt[0];
				var yy = py2 + pt[1];
				var no = getIndex(xx, yy);
				if (xx < 0 || xx >= COL_COUNT) continue;
				if (yy < 0 || yy >= ROW_COUNT) continue;
				if (blocks[no] == -1) {	// 移動可能か
					blocks[no] = blocks[getIndex(px2,py2)];
					blocks[getIndex(px2,py2)] = -1;
					drawPuzzle();
					checkClear();
					break;
				}
			}
		}
	}
}
// クリアしたかどうかチェックする
function checkClear() {
	var flag = true;
	for (var i = 0; i < (NUM_BLOCKS -1); i++) {
		if (blocks[i] != i) { flag = false; break; }
	}
	if (flag) {
		document.getElementById('top_title').innerHTML = clear_msg;
		context.drawImage(image, 0, 0);	// 元画像を描画する
		document.getElementById('pict_txt').innerHTML = PICTURE_TXT;	// 写真説明を表示
		clearFlag = true;
	}
}
// 列と行からブロック番号を調べる関数
function getIndex(col, row) {
	return row * COL_COUNT + col;
}
function getCol(no) { return no % COL_COUNT; }
function getRow(no) {
	return Math.floor(no / COL_COUNT);
}

* {
	padding:0;
	margin:0;
	text-align:center;
}

h1 {
	background-color:blue;
	color:white;
	font-size:20px;
	padding:4px;
}

#pict_title {
	max-width: 600px;
	margin: 0 auto;
	text-align: left;
	font-size: 1.2em;
	font-weight: 600;
}

#pict_txt {
	max-width: 600px;
	margin: 0 auto;
	text-align: left;
	line-height: 1.4em;
}