ヘビゲーム(進化)


前回、「壁や自分自身に接触すれば初めから」になるように組みました。
コレを元に機能を肉付けして、よりゲームらしくしてみましょう。
まずは、ステージ内のランダムな位置に1つだけアイテムを設置し、
キャラクタが接触したら成長して一段階伸びるようにスクリプトを拡張します。


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
*draw_item
	// アイテムが表示されていなければランダムな位置に配置
	if item = 0 {
		itemx = rnd(ginfo_winx / size)
		itemy = rnd(ginfo_winy / size)
		item = 1
	}
	color 200, 255, 255
	i = itemx * size, itemy * size
	boxf i.0 + 1, i.1 + 1, i.0 + size - 1, i.1 + size - 1
	return
アイテムもキャラクタと同じように、 見分けが付きやすいようキャラクタとは別の色でランダムなマスを塗りつぶします。 尚、メインループ内で処理ごとに小さく分けていっていたので、 今回のアイテムの描画もメインループからジャンプできるようにしています。 スクリプトの直接実行されない箇所に追加して、 メインループ内から当*draw_itemラベルにサブルーチンジャンプさせてください。 3行目で変数itemを新たに使用していますが、 この変数はステージ内に1つだけアイテムを描画させるためのフラグ用変数です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
*move_char
	// アイテムと先頭部分が接触したら成長する
	if posx = itemx & posy = itemy {
		len++
		item = 0
	}
	repeat len - 1
		dir(len - cnt - 1) = dir(len - cnt - 2)
		posx(len - cnt - 1) = posx(len - cnt - 2)
		posy(len - cnt - 1) = posy(len - cnt - 2)
	loop
	stick key, 5
	if key & 1 : dir = dir / 2 + (dir <= 1) * 8
	if key & 4 : dir = dir * 2 - (dir >= 8) * 15
	posx += (dir = 4) - (dir = 1)
	posy += (dir = 8) - (dir = 2)
	return
キャラの移動ロジックで、アイテムとキャラが接触した時にパワーアップさせるようにします。 付け足したのは2〜6行目の明るい青字の部分です。 キャラクタの先頭部分とアイテムのマスが一緒なら接触したとみなして、 キャラクタを1マス分成長し、itemフラグ変数をに戻して、 先に追加した*draw_itemラベルでアイテムを別の場所に再設置させます。 コレで、アイテムと接触することで成長するようになりましたね。 ただ、成長してゲームオーバーにはなりやすくなっても、ゲームクリアの概念はなく、 いわば「壁や自分と言う障害物をひたすら避け続けるエンドレスなゲーム」です。 次の段階で「一定の要件を満たせばクリアする」機能を付け足します。
 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
*hantei
	if posx < 0 | posy < 0 | posx >= ginfo_winx / size | posy >= ginfo_winy / size {
		i = -1
	} else {
		repeat len - 1
			i = cnt
			repeat len - i - 1, i + 1
				if posx.i = posx.cnt & posy.i = posy.cnt {
					i = -2
					break
				}
			loop
			if i = -2 : break
		loop
	}
	if i < 0 {
		if i = -1 : s = "壁" : else : s = "自分"
		dialog s + "に激突!", 1, "ゲームオーバー"
		gosub *init
	}
	// クリア判定
	if len > 30 {
		dialog "長さ" + len + "達成おめでとう", , "ゲームクリア!"
		end
	}
	return
ゲームをクリアしたかを判定させるところは*hanteiラベル内で良いでしょう。 上記の21〜25行目が「長さが30を超えたらゲームを終えて終了する」ロジックです。 定数で「30を超えると…」と指定してますが、ココは好きな数字に変更して試してください。
 1
 2
 3
 4
 5
 6
*start
	randomize
	stage = 0
	mission = 30, 40, 60 // 1ステージ:30個, 2ステージ:40個, 3ステージ:60個
	gosub *init
	return
続いては「ステージ制」を導入するための準備をしてみましょう。 *initラベルはステージ毎の初期化として、ゲームの初期化として*startラベルを用意しました。 2行目で行っている乱数の初期化は、アイテムのランダム配置に使用します。 3行目のstageが現在のステージを示す変数であり、 4行目のステージクリアに必要なキャラクタの長さを示す配列の要素番号でもあります。 *startラベル内から*initラベルにジャンプする仕組みにしましたので、 ゲーム開始直後の*mainラベルへ行く前の「gosub*init」の部分を書き換えてください。
1
2
	gosub *start
	goto *main
 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
*hantei
	if posx < 0 | posy < 0 | posx >= ginfo_winx / size | posy >= ginfo_winy / size {
		i = -1
	} else {
		repeat len - 1
			i = cnt
			repeat len - i - 1, i + 1
				if posx.i = posx.cnt & posy.i = posy.cnt {
					i = -2
					break
				}
			loop
			if i = -2 : break
		loop
	}
	if i < 0 {
		if i = -1 : s = "壁" : else : s = "自分"
		dialog s + "に激突!", 1, "ゲームオーバー"
		gosub *init
	}
	if len >= mission.stage {
		stage++
		if stage >= length(mission) {
			dialog "長さ" + mission(stage - 1) + "達成おめでとう", , "ゲームクリア!"
			end
		} else {
			dialog "長さ" + mission(stage - 1) + "達成です", , "ステージ" + stage + "クリア"
			gosub *init
		}
	}
	return
先ほど*hanteiラベルに追加したクリア条件を上記のように書き換えればステージ制の完成です。 22行目でインクリメントしているステージ数が、 ステージ毎のクリア条件を定義している変数missionの要素数を超えたらゲームクリア、 要素の最大数を超えてない場合は、ステージ最初の状態に戻して次のステージへ進みます。
 1
 2
 3
4
5
6
7
*start
	randomize
	stage = 0
	life = 3 // ライフ(残機数)
	mission = 30, 40, 60
	gosub *init
	return
ステージ制導入にあたり、ゲームオーバーも拡張してみます。 *startラベル内にライフ(上記4行目部分)を追加し、*hanteiラベル内を以下のように変更します。
 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
37
38
39
*hantei
	if posx < 0 | posy < 0 | posx >= ginfo_winx / size | posy >= ginfo_winy / size {
		i = -1
	} else {
		repeat len - 1
			i = cnt
			repeat len - i - 1, i + 1
				if posx.i = posx.cnt & posy.i = posy.cnt {
					i = -2
					break
				}
			loop
			if i = -2 : break
		loop
	}
	if i < 0 {
		life--
		if i = -1 : s = "壁" : else : s = "自分"
		// まだライフが残っているなら続行
		if life {
			dialog "長さ" + len + "で" + s + "に激突!", 1, "残り" + life + "回で終了です"
			gosub *init
		// ライフがなくなったら、ステージ0からやり直すかゲーム終了
		} else {
			dialog "長さ" + len + "で" + s + "に激突!\nやり直しますか?", 2, "ゲームオーバー"
			if stat = 6 : gosub *start : else : end
		}
	}
	if len >= mission.stage {
		stage++
		if stage >= length(mission) {
			dialog "長さ" + mission(stage - 1) + "達成おめでとう", , "ゲームクリア!"
			end
		} else {
			dialog "長さ" + mission(stage - 1) + "達成です", , "ステージ" + stage + "クリア"
			gosub *init
		}
	}
	return
激突処理内でライフを1つ減らし、 まだライフが残っているなら*initラベルへジャンプ、つまりキャラの長さを最初に戻してプレイ続行。 ライフが0になったら、ゲームオーバーメッセージを表示してコンテニューするかを確認。 コンテニューするならゲームは終了しませんが*startラベルへジャンプ、つまりステージ0に戻ります。 コレで少しはプレイできるレベルとなりましたが、 実際に試してみると、キーが反応しにくい、現在の状況がわかりにくい等の細かい問題が幾つか残ってます。 ソレらについては次回説明するとして今回は以上で終了です。 まとめてみたスクリプトはコチラからどうぞ。