[Game A Week]1週間でゲームを作った話[GameMaker]

# 作ったもの
![ss15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868961/3b23e3d5-255b-e726-d21b-053032ba95da.png)

[MUGEN DUNGEON](https://studio-baku.net/mugen_dungeon/v1/)
無限に生成される迷路で永遠に階段を降りるゲームです。
作者である僕はB50Fくらいでギブアップしました。

## ことの経緯
現在あるゲーム制作サークルで開発に関わっています。
プログラマではなくドッターとしての参加です。

まだ企画の立ち上げ段階でアイドリング時間が少しあり、この空いた時間で小さなゲーム作れるのでは？と思ったことがきっかけです。

以前に読んだ[GAME A WEEKに関する記事](https://qiita.com/2dgames_jp/items/6a23207fd0057df92552)を思い出し、やるタイミングを探していたのもあります。


以下、毎日の終わりに書いていた日誌と共に振り返った内容です。
1日あたりの作業時間は1〜3時間です。

記事の最後に1週間でゲームを作るときに役に立つかもしれないメモも載せておきます。
自分がこの1週間で気付いたことを自戒として書いています。次回のための自戒です。

## 1日目 - とにかく作り始める
何となく迷路のようなダンジョンの階段を降り続けるゲームが作りたいと思ったので、
GameMakerで新規プロジェクトを作成し、プロジェクト名を「MUGEN DUNGEON」としました。
ダンジョンの綴りがいつまで経っても分からないので何度も[codic.jp](https://codic.jp/)で調べています。


Roomサイズは320px * 240pxに設定しました。
サイズが小さい理由としてはデバッグ時の処理速度を少しでも早めるためです。

同様の理由でメインの処理が作り終わるまではとにかく小さく作るようにして、グラフィックは白黒の二色、凝ったエフェクトも無し、日本語フォントやサウンドもすべて後回しにしました。

![ss1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868961/152a7908-2da2-f543-ee25-6e39ca6c9c81.png)

確認処理をスムーズにするためEscキーが押されたときに`game_end()`を呼び出すようにしました。
F5で起動し、Escキーで終了できる状態になりました。

マップを表現するため二次元配列で床を作りました。
`array[y][x]`は何となく直感に反しますが慣れるしかないので慣れました。
![ss4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868961/24320027-7c85-8f56-8295-1a3f0c676de2.png)

階段を作り、プレイヤーがその座標まで移動できたらマップ自体を再生成する処理を作りました。
1日目としては上々の進み具合だと思います。

## 2日目 - デバッグメッセージとマニュアルは大事
マップに壁を設定しプレイヤーが抜けられないように処理を加えました。
コリジョンは使用せず座標ごとに壁かどうかを判定するお手軽処理です。

階段の生成と壁との接触判定がうまくいかずに悩んでいました。
たまに壁をすり抜けたり詰まったり、マップ外に階段が生成されてる様子でした。

何となく怪しい箇所に検討はつくものの確証がなかったので、
1日目はすっ飛ばした`show_debug_message()`処理を入れて配列の状態を出力しました。

どうも乱数で数値が想定より1つ多く生成されてるらしい。
で、マニュアル読んだらあっさり解決。

僕はなぜか、
`irandom(10)`としたときに0〜9までのいずれかの整数を返すものだと思い使用していたけど、
正しくは`irandom(10)`のときは0〜10のいずれかの整数を返すらしいです。
もしかすると常識なのかもしれない。
大事なことは大抵マニュアルに書いてあります。
[GameMakerまとめWiki - irandom()](https://www.wikihouse.com/GameMaker/index.php?irandom())

![ss5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868961/e89a7f4b-ffe0-a9c4-6e27-ef44991f1beb.png)

ゲーム中の制限時間として10秒を設定しました。
この10秒以内にどれだけ階段を降りられるか頑張るというのが「MUGEN DUNGEON」の根幹となるルール部分です。

ポーションを配置しました。これを取得すると3秒ほど制限時間が回復する仕様です。
![ss6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868961/99b56630-8ed3-f80e-8427-c7f7dfd51632.png)

これにより、そのまま階段へ突き進むか、少し遠回りでもポーション取ってから先に進むかという選択肢が生まれました。
ここまで作ってみて、単純ながら(あるいは単純だからこそ)それなりにゲームとして成り立っているように見えます。

迷路の生成アルゴリズムとして「穴掘り法」を調べ始めました。

## 3日目 - アルゴリズムは便利
迷路生成のためのアルゴリズムをいくつか比較して「穴掘り法」を使用することに決めました。
![ss8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868961/b0d61392-30e2-3381-2cce-608bee5443a0.png)


アルゴリズムをテストするためのテストRoomを作成しそこで調整していきます。
スタート地点をランダムとして、いくつかの行き止まりの中からランダムに1つ「階段」を配置するように設定してみました。

「階段」と「ポーション」だけだと味気ないので「宝箱」や「お金」といったパラメータを追加することを思いつきました。
それらを配置する場所を決めるため、ある地点Aに接する壁の数から「行き止まり」「分かれ道」を判定するようにしました。

壁が3個だと「行き止まり」
壁が2個だと「通路」
壁が1個だと「分かれ道」

![ss9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868961/c2823a15-51dd-d157-c955-3d7837f6550c.png)


「ポーション」が生存のために必要だったのに対して、別に取らなくても先に進める「お金」などがプレイヤーにとって報酬になれば新しい選択が生まれるように思います。

「宝箱」や「お金」が報酬として魅力的であるためには、さらに要素を増やす必要がありそうです。
「宝箱」を収集要素、「お金」を何かプレイヤーのパワーアップアイテム購入に充てるなどのアイデアが生まれました。

## 4日目 - ソースコード書く場所がまずかった
一週間の折り返し地点。
迷路生成のテストも終わりテストRoomから本番用のRoomにソースコードを移植していきます。
オブジェクトに紐付けてGMLを書くスタイルだとソースコードの移動が地味に面倒でした。
きっと他にいい移植方法があるハズだと思いながらも今回はワークスペースのタブを二つ開き単純にコピペしました。
![ss10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868961/40d48a11-cad8-41b5-9d58-c77441d47414.png)

## 5日目 - 要素の追加1
「宝箱」が迷路内に生成されるよう実装しました。
取得したときの処理は未作成です。中身も考えていません。
![ss11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868961/bf46bced-981a-5caf-69d9-5754bef5b79b.png)

あと2日でどこまで作れるのかということが気になって集中が途切れるので、最低限実装したいものを手書きメモに書き出しました。

## 6日目 - 要素の追加2
「宝箱」「お金」の取得処理を実装しました。
フリーのBGMとSEを探してプロジェクトに読み込みました。
![SS14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868961/624304d5-6757-6d3f-ddbf-9f8584229b76.png)


他の作業はほとんど進まずに6日目を終えます。

## 7日目 - 駆け込み実装
最終日。
ここまで体感としては3日くらい。
なのに1ヶ月くらい作業していたような気がするので、確実に時間の感覚がおかしくなっています。
作業していない間も頭の中では実装の方法だったりを考えているせいだと思います。

![ss15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868961/6852fb69-f78b-09b6-5c44-64d522c94f5a.png)


タイトル画面、メインのプレイ画面、ゲームオーバー画面の切り替えを一気に実装しました。
ハイスコアとして到達した階数をjsonファイルにセーブするように設定しました。
これらの処理は他のプロジェクトでも実装したことがあったので、今回は30分かからずに実装できました。
別のプロジェクトからオブジェクトをそのまま持ってくるような方法があれば更に楽ができそうです。

各シーンと各動作にBGM・SEを付け終えたので今回のGame A Weekについては完了としました。


# 振り返ってみて
勢い任せでスタートして、ほぼそのままの勢いでゴールできました。
ゲームとして面白いとは言えないゲームですが自分の中ではとても満足しています。

期限で区切ってそこを完了とできたことが大きいと感じています。
とかく趣味での個人開発はいくらでも期限が伸ばせてしまうので、Game A Weekの1週間という鉄のルールには救いがあります。

作り終えたプロジェクトを改良するか、次のGame A Weekを始めるかはいったん保留とします。

# 1週間でゲームを作るときに役に立つかもしれないメモ
### 完璧な物は作れない
絶対に無理です。最初から諦めましょう。
でも作りましょう。

### とにかく小さく作る
大は小を兼ねるかもしれないけど、やることは小の積み重ねです。
あちこちに根を張るような大きなプログラムを一気に作ろうとすると、1つのエラーを修正するだけで日が暮れてやる気がなくなります。
小さな動作を1つずつ確認しながら進むのが結局は近道です。

### 作りながら考える
考え終わってから作ると間に合いません。
とりあえず走りながら次の曲がり角をどっちに曲がるのかを考えましょう。
転ばないように気をつけても必ず転びます。

### 綺麗なコードを目的にしない
コードの美しさはゲームの動作に影響しません。
変数名がローマ字であろうが、マジックナンバー使ってようが誰にも迷惑がかかりません。
遠い親戚のようなインスタンス変数を直接書き換えたって誰にも怒られません。
動作さえすれば正義です。誰にも見られません。やりたい放題です。

こんな汚いソースコードでいいんだろうか？と悩んだときは、[GameMaker日本語コミュニティー](https://discord.com/invite/QWGc5xTvX2)の汚いコードチャンネルを見て落ち着きましょう。

ただ、綺麗なソースコードに救われる場面は多々あります。

### 時間は戻らない
無慈悲です。
あのときYouTubeを開かなければと何度だって後悔します。
キーひとつで実行と終了ができるようにしたり、よく使う動作のショートカットキーを調べるなどしておけば、ショート動画1つ見るくらいの余裕はあるかもしれません。

### 諦めて、受け入れて、自分を褒める
あと1日あれば！って、きっと明日も言います。
7日目の23時59分に、ここが自分の実力だと受け入れましょう。
8日目は頑張った自分を褒めましょう。
ダメだったところは次回に活かせるので自分を責める必要はありません。
うまくいかなかった部分が多ければ多いほどラッキーです。
よく頑張った！