ローグっぽい2D迷路探索ゲームを作る2(PowerShellで)
はじめに
ローグっぽい2D迷路探索ゲームを作る2回目です。
Windowsに標準搭載されているPowerShellを使って
ローグっぽい2D迷路探索ゲーム開発に挑戦します。
3回くらいの記事にしようと思います。
1回目 ローグの解説、ゲーム基礎部分
2回目 ゲーム部分の機能強化
3回目 ランダムな迷路の自動生成
今回は2回目の記事です。
前回の記事
プログラム
# 変えたところ
#- 方向入力の数字をテンキーに合わせる
#- 壁の文字変更
#- 移動量の制限の追加(食料の概念)
#- 移動数の表示
#- イベントの追加
#- 壁が壊せる
$maze=@(
"▓▓▓▓▓▓▓▓▓▓▓",
"▓ ▓ ▓",
"▓ ▓ ▓▓▓ ▓ ▓",
"▓ ▓▓ ▓ ▓",
"▓ ▓▓▓ ▓",
"▓ ▓▓▓ ▓G▓ ▓",
"▓ ▓ ▓ ▓ ▓",
"▓ ▓ ▓ ▓ ▓ ▓",
"▓S▓ ▓ ▓",
"▓▓▓▓▓▓▓▓▓▓▓"
)
# 変数初期化
# 自分の位置と向き
$my_x = -1
$my_y = -1
$my_direction = 8 # 向き 8北 6東 2南 4西
$my_char = @("","","v","","<","",">","","^") # 向き 8北 6東 2南 4西
$my_food = 50 # 食料 残り移動可能数
$my_scope = 2 # 見える範囲
$my_stepcount = 0 # 移動数
$my_mattockcnt = 1 # 壁が壊せる回数
# ゴールの位置
$goal_x = -1
$goal_y = -1
# 移動用変数
$dx = @(0,0,0,0,-1,0,1,0, 0) # 向き 8北 6東 2南 4西
$dy = @(0,0,1,0, 0,0,0,0,-1) # 向き 8北 6東 2南 4西
# 壁の文字
$kabemoji = "▓"
# 表示ウェイト時間(秒)
$waitcnt = 1
# スタートとゴールを探す
for($i=0;$i -lt $maze.length;$i++) {
for($j=0;$j -lt $maze[$i].length;$j++) {
if($maze[$i][$j] -eq "S") {
$my_x = $j
$my_y = $i
}
if($maze[$i][$j] -eq "G") {
$goal_x = $j
$goal_y = $i
}
}
}
# 自分キャラの上書き
$maze[$my_y] = $maze[$my_y].Remove($my_x,1)
$maze[$my_y] = $maze[$my_y].Insert($my_x,$my_char[$my_direction])
function disp-maze($x,$y,$maze,$scope) {
# 表示範囲の計算
$mx = $x - $scope
$my = $y - $scope
if($mx -lt 0) {$mx = 0}
if($my -lt 0) {$my = 0}
# 表示範囲の計算 横の最大値
$width = $x + $scope
if($width -ge $maze[0].length) {
$width = $maze[0].length - 1
}
# 表示範囲の計算 縦の最大値
$height = $y + $scope + 1
if($height -gt $maze.length) {
$height = $maze.length
}
# 枠の表示 上側
write-host "+" -NoNewline
for($i=0;$i -le $width-$mx+2;$i++){
write-host "-" -NoNewline
}
write-host "+"
# 自分の周りの表示
for($yy = $my;$yy -lt $height;$yy++) {
$temp_maze = ""
for($xx=$mx;$xx -le $width;$xx++) {
$temp_maze+=$maze[$yy][$xx]
}
write-host "| $temp_maze |"
}
# 枠の表示 下側
write-host "+" -NoNewline
for($i=0;$i -le $width-$mx+2;$i++){
write-host "-" -NoNewline
}
write-host "+"
}
function checkEvent($my_food ,$my_scope ,$my_mattockcnt ,$auto) {
# 乱数リセット
$event = Get-Random -SetSeed $(Get-Date -Format "ffff")
if($auto -eq $False) { # 自発的に見回した時とそれ以外で発生率を分ける
write-host "周りを見回した..."
Start-Sleep -Seconds $waitcnt
$event = Get-Random -Minimum 0 -Maximum 20
} else {
$event = Get-Random -Minimum 0 -Maximum 100
}
if($event -lt 3) {
write-host "壁の隙間にキノコが生えている..."
Start-Sleep -Seconds $waitcnt
$rand_food = Get-Random -Minimum 5 -Maximum 8
write-host "食料を ${rand_food}個見つけました"
$my_food+=$rand_food+1
Start-Sleep -Seconds $waitcnt
} elseif($event -eq 5) {
write-host "壁の隙間にキノコが生えている..."
Start-Sleep -Seconds $waitcnt
write-host "食べられないようだ"
Start-Sleep -Seconds $waitcnt
} elseif($event -eq 10) {
write-host "ネズミが足元を走り抜けた..."
Start-Sleep -Seconds $waitcnt
$rand_food = Get-Random -Minimum 3 -Maximum 5
write-host "食料を ${rand_food}個失った"
$my_food-=$rand_food+1
Start-Sleep -Seconds $waitcnt
} elseif($event -eq 11) {
write-host "ネズミが足元を走り抜けた..."
Start-Sleep -Seconds $waitcnt
write-host "捕まえて食料にした"
Start-Sleep -Seconds $waitcnt
$rand_food = Get-Random -Minimum 5 -Maximum 8
write-host "食料が ${rand_food}個増えた"
$my_food+=$rand_food+1
Start-Sleep -Seconds $waitcnt
} elseif($event -eq 12) {
write-host "ネズミが足元を走り抜けた..."
Start-Sleep -Seconds $waitcnt
write-host "松明を振り回して追い払った"
Start-Sleep -Seconds $waitcnt
write-host "松明の火が小さくなった"
$my_scope-=1
if($my_scope -eq 0){
$my_scope = 1
}
Start-Sleep -Seconds $waitcnt
} elseif($event -eq 15) {
write-host "つまずいて食料と松明を落とした..."
Start-Sleep -Seconds $waitcnt
$rand_food = Get-Random -Minimum 3 -Maximum 5
write-host "食料を ${rand_food}個失った"
$my_food-=$rand_food+1
Start-Sleep -Seconds $waitcnt
write-host "松明の火が小さくなった"
$my_scope-=1
if($my_scope -eq 0){
$my_scope = 1
}
Start-Sleep -Seconds $waitcnt
} elseif($event -eq 16) {
write-host "突風が吹いて松明の火が小さくなった..."
$my_scope-=1
Start-Sleep -Seconds $waitcnt
if($my_scope -eq 0){
write-host "...かと思ったら、天井から油が滴っていた"
Start-Sleep -Seconds $waitcnt
write-host "油を松明に擦り付けて火を大きくした"
Start-Sleep -Seconds $waitcnt
$my_scope = 3
}
Start-Sleep -Seconds $waitcnt
} elseif($event -eq 17) {
write-host "壁から木の根が生い茂っている..."
Start-Sleep -Seconds $waitcnt
if($my_scope -lt 3){
$my_scope+=1
write-host "はがして松明にした"
} else {
write-host "剝がそうとしたがビクともしなかった"
}
Start-Sleep -Seconds $waitcnt
} else {
if($auto -eq $False) {
write-host "...何もなかった"
Start-Sleep -Seconds $waitcnt
}
}
return $my_food ,$my_scope ,$my_mattockcnt
}
$loopflg = $True
while($loopflg) {
# 画面表示
disp-maze $my_x $my_y $maze $my_scope
# 入力
write-host "食料:${my_food} 松明:${my_scope} マトック:${my_mattockcnt} 移動数:${my_stepcount}歩"
write-host "どちらに進みますか "
$keyinput = (read-host "8:北 6:東 2:南 4:西 77:周りを見る 88:壁を壊す 99:終了") # 向き 8北 6東 2南 4西
# 入力チェック
if($keyinput -ne "8" -and $keyinput -ne "6" -and $keyinput -ne "2" -and $keyinput -ne "4" -and $keyinput -ne "88" -and $keyinput -ne "77" -and $keyinput -ne "99") {
# 該当の数字以外は無効とする
write-host "入力は半角数字 2,4,6,8,77,88,99のみ"
continue;
}
# 終了判定
if($keyinput -eq "99"){
$loopflg = $False
continue;
}
# 壁を壊す
if($keyinput -eq "88"){
if($my_mattockcnt -ge 1) {
$tmp_my_x = $my_x + $dx[$my_direction]
$tmp_my_y = $my_y + $dy[$my_direction]
if($tmp_my_x -lt 1 -or $tmp_my_x -ge $maze[$tmp_my_x].length-1 -or $tmp_my_y -lt 1 -or $tmp_my_y -ge $maze.length-1){
write-host "その壁は壊せなかった"
} elseif($maze[$tmp_my_y][$tmp_my_x] -eq $kabemoji){
write-host "壁を壊した"
$my_mattockcnt-=1
$maze[$tmp_my_y] = $maze[$tmp_my_y].Remove($tmp_my_x,1)
$maze[$tmp_my_y] = $maze[$tmp_my_y].Insert($tmp_my_x," ")
} else {
write-host "壁はなかった"
}
}
continue;
}
# 周りを見る
if($keyinput -eq "77"){
$my_food ,$my_scope ,$my_mattockcnt = checkEvent $my_food $my_scope $my_mattockcnt $False
continue;
}
# 移動処理
if($keyinput -ne $my_direction) {
# 向きが違う場合、向きを変えるのみ
$tmp_my_direction = $keyinput
$tmp_my_x = $my_x
$tmp_my_y = $my_y
} else {
# 向きが同じなら進む
$tmp_my_direction = $keyinput
$tmp_my_x = $my_x + $dx[$keyinput]
$tmp_my_y = $my_y + $dy[$keyinput]
}
# 進む処理
if($maze[$tmp_my_y][$tmp_my_x] -ne $kabemoji){# 壁の判定
$my_stepcount+=1
# 現在地を空白で消す
$maze[$my_y] = $maze[$my_y].Remove($my_x,1)
$maze[$my_y] = $maze[$my_y].Insert($my_x," ")
# 位置移動
$my_x = $tmp_my_x
$my_y = $tmp_my_y
$my_direction = $tmp_my_direction
# 表示
$maze[$my_y] = $maze[$my_y].Remove($my_x,1)
$maze[$my_y] = $maze[$my_y].Insert($my_x,$my_char[$my_direction])
# ゴールの判定
if($my_x -eq $goal_x -and $my_y -eq $goal_y) {
write-host "ゴールに到着しました"
disp-maze $my_x $my_y $maze $my_scope
$loopflg = $False
} else {
# イベント発生チェック
$my_food ,$my_scope ,$my_mattockcnt = checkEvent $my_food $my_scope $my_mattockcnt $True
}
# 終了の判定
$my_food-=1
if($my_food -lt 0 -and $loopflg -eq $True){
write-host "食料が底をつきました"
$loopflg = $False
}
}
}
プログラム解説
次の機能を盛り込みました。
方向入力の数字をテンキーに合わせる
見える範囲の概念
移動量の制限(食料の概念)
壁が壊せる
壁の文字変更
イベントの追加
方向入力の数字をテンキーに合わせる:
これは、前回入力が0,1,2,3だったのをテンキーの数字の並び8,6,4,2に合わせました。8,6,4,2の方が直感的に遊びやすいので変えました。自分のパソコンにはテンキーが無いんですけども昔のパソコンゲームは方向を8,6,4,2にしているものが多かったのでこうしてみました。
見える範囲の概念:
松明というステータスを足して、見える範囲が変わるようにしました。
変数$my_scopeが見える範囲です。
移動量の制限(食料の概念):
ローグライクゲームに食料の概念があったので取り入れてみました。
壁が壊せる:
今は迷路が固定なのですが、次の記事でランダムに迷路を生成するようにしたいので、閉路で積んでしまわないように壁が壊せるようにしました。
変数$my_mattockcntが壁を壊せる回数です。
壁を壊して通路を作ったら、周りの通路のどれかが塞がるとかにしたら面白くなるかな?と考えたのですが今回は壊すだけにしました。
壁の文字変更:
壁の文字が*だったのを▓にしました。▓は見たことがない半角文字なんですけどWindows系なら大丈夫だろうと思って変えてみました。
イベントの追加:
周りを見回す行動を追加して、見回したときにイベントがランダムに起こるようにしました。食料が手に入ったり、見える範囲が広がることがあります。プログラムコードが同じような記述が繰り返し出てきてキレイじゃないし、処理が丸見えなんですが取り合えずで作ってみました。
なんか、あんまり面白くないですね。
やりこみ要素とかが無いからでしょうか。
次回予告
次は迷路をランダムなものに変えようと思います。
下の記事を参考にします。
#PowerShell #テキストゲーム #ローグライク #プログラミング初心者
#プログラミング入門