スライドパズル(改善)


今回は前回までに問題のあった箇所、変更したほうが良い箇所の改善を行います。

まずはタイトル部分の操作方法についての修正から。
プレイ画面はマウスで操作するのに、
タイトル画面はキーボードで操作するというのはイマイチです。
タイトル画面もマウスだけで操作できるように修正しますが、
せっかくキーボード操作もできるのだから、
キーボード操作もできるままにした方が操作の幅が広がって良いと思うので、
キーボード操作はそのままに、マウス操作機能を追加しましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
*menu
	index = 0
	gosub *draw_menu
	i = 0, 0 // マウスカーソル座標位置の変更確認用一時変数
	repeat
		wait 5
		stick key
		if key & 2 : index-- : if index < 0 : index = length(item) - 1
		if key & 8 : index++ : if index >= length(item) : index = 0
		if key & 10 : gosub *draw_menu
		// マウス座標が変わればカーソル位置の座標がメニュー上かを確認する
		if i.0 ! mousex | i.1 ! mousey {
			i = mousex, mousey
			foreach item
				i.2 = (ginfo_winy - 230) / length(item) * cnt + 200
				if i.0 > 200 & i.0 < 440 & i.1 > i.2 & i.1 < i.2 + 40 {
					index = cnt
					gosub *draw_menu
					break
				}
			loop
		}
		// メニューの決定ボタンは32(エンターキー) or 256(クリック)
		if key & 288 {
			switch index
			case 0:
				gosub *game_start
				gosub *draw_menu
				swbreak
			default:
				break
			swend
		}

	loop
	return
4行目で初期化している一時変数iは、今回はマウスの座標監視用に使用します。 カーソル座標がメニュー上にあるかをチェックして、 「メニュー上ならメニューを選択する」という処理を行いたいのですが、 ループ上で「常にメニュー上にあるかを監視し続ける」と、 今回は「ゲーム開始」と「ソフト終了」の2種類しかないのでCPU負荷は大して掛からないものの、 できるだけ負荷を掛けない様にすべきです。 23行目にあるように現在の取得したカーソル位置をチェックして、 XまたはY座標のいずれかが異なっていれば変数iをその位置に変更し、 また、その変更があったときにだけ座標位置がメニュー上にあるかを確認するようにしておくことで、 今後、相当数メニューが増えても影響を受けにくいでしょう。 尚、27行目のマウスX座標を200〜440としているのは、 長い方のメニューテキストでも選択できる位に幅を取っているだけで、それほど深い意味はありません。 厳密に「メニューテキスト上にある時だけメニューを選択したい」というのであれば、 予め用意した配列変数にメニューテキスト幅情報を退避させておく必要がありますが、 今回はサンプル用のもので、そこまでは必要ないと判断して簡易的なものにしたわけです。 メニュー画面がキーボードのカーソルキーとマウスクリックの2種類に対応させたので、 次はゲーム画面側もマウスクリックだけでなく、カーソルキーでの移動に対応させましょう。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
*game_main
	title strf("%s (残り:%d)", NAME, moved - moved.1)
	repeat
		wait 1
		stick key
		if key & 271 { // 256(クリック) + 1(左キー) + 2(上キー) + 4(右キー) + 8(下キー)
			if (key & 1) ! 0 & space \ numx.stage ! numx.stage - 1 : i = space + 1
			if (key & 2) ! 0 & space / numx.stage ! numy.stage - 1 : i = space + numx.stage
			if (key & 4) ! 0 & space \ numx.stage ! 0 : i = space - 1
			if (key & 8) ! 0 & space / numx.stage ! 0 : i = space - numx.stage
			if key & 256 : i.0 = mousex / SX + mousey / SY * numx.stage
			i.1 = (i - 1 = space) & (i \ numx.stage ! 0)
			i.2 = (i - numx.stage = space) & (i / numx.stage ! 0)
			i.3 = (i + 1 = space) & (i \ numx ! numx.stage - 1)
			i.4 = (i + numx.stage = space) & (i / numx.stage ! numy.stage - 1)
			if i.1 | i.2 | i.3 | i.4 {
				tip.space = tip.space ^ tip.i
				tip.i     = tip.space ^ tip.i
				tip.space = tip.space ^ tip.i
				space = i
				moved.1++
				title strf("%s (残り:%d, 手数:%d)", NAME, moved - moved.1, moved.1)
				gosub *draw_map
				gosub *clear_check
				if clear : break
			}
		}
	loop
	return
カーソルキーでの移動は空きマスの位置に向かってマスを移動させるようにしてみました。 つまり、例えば「右キーが押されたら空きマスの左側にあるマスが右に移動する」、 「下キーが押されたら空きマスの上側にあるマスを下に移動する」という具合です。 処理的には、左キーが押された時は7行目のように「空きマスが一番左端列以外か」を、 上キーが押された時は8行目のように「空きマスが一番上端行以外か」を、 右キーが押された時は9行目のように「空きマスが一番右端列以外か」を、 下キーが押された時は10行目のように「空きマスが一番下端行以外か」をそれぞれ確認し、 それぞれの最端ではないときに移動させるようにすればカーソルキーでの移動対応は完成です。 次の改善として、元のマス情報をヒント的に表示させる処理を追加しましょう。 例えば今回の場合、左上から順に1から順に数字マスを揃えるというものなわけですが、 「4×4マスで左端から数えて2つ目で、下端のマスは何になるか?」と聞かれると、 計算したり1つずつ数えていかないと何になるかパッと出てこないこともあるでしょう。 数字パネルではなく、画像の場合も同じことが言えるでしょう。 完成図を見れば一目で「このマスはココに来るのか」とわかるようなものでも、 似たようなものがバラバラに置き換えられていると案外わかりにくいかもしれません。 そこで、「完成図がわかりやすいようにしてみよう」というのが今回の趣旨。 下記の2ラベル分を修正してください。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
*draw_map
	redraw 0
	color 255, 255, 255 : boxf
	repeat numx.stage * numy.stage
		pos cnt \ numx.stage * SX, cnt / numx.stage * SY
		if cnt = space | (key & 512) ! 0 { // 空きマス or 右クリック時はうっすら表示
			gmode 3, SX, SY, 20
			gcopy 2, cnt \ numx.stage * SX, cnt / numx.stage * SY
			gmode 3, SX, SY, 256
			continue
		}
		gcopy 2, tip.cnt \ numx.stage * SX, tip.cnt / numx.stage * SY, SX, SY
	loop
	redraw 1
	return
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
*game_main
	title strf("%s (残り:%d)", NAME, moved - moved.1)
	repeat
		wait 1
		stick key, 512 // 完成図表示用に右クリックは押しっ放しを許可
		if key & 271 {
			if (key & 1) ! 0 & space \ numx.stage ! numx.stage - 1 : i = space + 1
			if (key & 2) ! 0 & space / numx.stage ! numy.stage - 1 : i = space + numx.stage
			if (key & 4) ! 0 & space \ numx.stage ! 0 : i = space - 1
			if (key & 8) ! 0 & space / numx.stage ! 0 : i = space - numx.stage
			if key & 256 : i.0 = mousex / SX + mousey / SY * numx.stage
			i.1 = (i - 1 = space) & (i \ numx.stage ! 0)
			i.2 = (i - numx.stage = space) & (i / numx.stage ! 0)
			i.3 = (i + 1 = space) & (i \ numx ! numx.stage - 1)
			i.4 = (i + numx.stage = space) & (i / numx.stage ! numy.stage - 1)
			if i.1 | i.2 | i.3 | i.4 {
				tip.space = tip.space ^ tip.i
				tip.i     = tip.space ^ tip.i
				tip.space = tip.space ^ tip.i
				space = i
				moved.1++
				title strf("%s (残り:%d, 手数:%d)", NAME, moved - moved.1, moved.1)
				gosub *draw_map
				gosub *clear_check
				if clear : break
			}
		} else {
			if ((key & 512) ! 0 & i ! -1) | ((key & 512) = 0 & i = -1) {
				gosub *draw_map
				if key & 512 : i = -1 : else : i = 0
			}
		}
	loop
	return
1つは、空きマスに本来のマス画像をうっすら表示。 コレで、ココに来るマスは今どこにあるかを見て、今後の作戦が練られる…かもしれません。 あまり役に立たないヒントかもしれませんが、 単に白く塗り潰されただけの空きマスよりもマシであると思いますが如何でしょうか? もう1つは、右クリックしている間、本来のマスを全部表示。 右クリックを押し続けた瞬間と、右クリックを離した瞬間に描画し直す必要があるので、 一時変数iを使い回して、右クリックが押されている時は−1とすると決めておき、 game_mainラベル内の28行目のように、 右クリックをしていて、前回のループ時には右クリックされていなかった時か、 右クリックはされていないけど、前回のループ時には右クリックされていた時にのみ描画するようにしましょう。 最後の改善として、ステージ開始前の心準備としてステージタイトルを表示させてみましょう。 2章のようなカウントダウン式でも良いのですが、せっかくなので今回は別の表現方法を考えてみました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
*game_start
	stage = 0
	foreach numx
		space = 0
		clear = 0
		moved = 0, 0
		gosub *draw_tips
		gosub *shuffle
		gosub *draw_stagetitle // ステージタイトル描画
		gosub *draw_map
		gosub *game_main
		gosub *game_clear
		if clear = 2 : continue cnt
	loop
	dialog "Stages All Clear !\n\nThank you for Playing."
	return
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
*draw_stagetitle
	i = ginfo_winx, -150, -150
	color 255, 200, 255 : boxf
	repeat 80
		stick key
		if key & 288 : break // 32(エンターキー) or 256(クリック) でタイトルスキップ
		redraw 0
		color 255, 200, 255 : boxf , 50, , 430 : color
		font msmincho, 80, 1
		pos i.0, 50 : mes strf("ステージ%d", stage + 1)
		color , , 255
		font msmincho, 50, 1
		pos i.1, 250 : mes strf("%d×%dマス", numx.stage, numy.stage)
		pos i.2, 350 : mes strf("手数残%d", moved)
		redraw 1
		i.0 -= abs(cos(M_PI * cnt / 64) * 25)
		i.1 += abs(cos(M_PI * cnt / 64) * 20)
		i.2 += abs(cos(M_PI * cnt / 64) * 20)
		wait 2
	loop
	return
新たに*draw_stagetitleラベルを追加してみました。 実行していただければ、どういうエフェクトが掛かっているのかお分かりいただけると思いますが、 軽く説明すると、タイトルテキストが端から横にスライドしてきて逆サイドに消えていくというもの。 *draw_stagetitleラベルの17〜20行目にabs関数やcos関数、M_PIマクロ定数があります。 コレは、単にウィンドウ端から出てきたテキストをそのまま逆側へ流すのではなく、 緩急をつけ、ウィンドウ中央付近で停止する位に減速させて、中央を過ぎれば再度加速させる為に使っています。 一応、全体の移動量を64等分しましたがテキストには幅があり、 64ターンでは端から端まで流しきることができませんので余裕を持たせて80回ループさせています。 尚、メニュー画面やゲーム画面同様に、 「エンターキーおよびクリックのどちらでもイケるようにした」画面スキップ処理も入れました。 コレらの変更で少しは改善されたのではないかと思うので、この章は以上で終了します。 この章でまとめたスクリプトはコチラからダウンロードしてください。