虎の穴開発室ブログ

虎の穴ラボ株式会社所属のエンジニアが書く技術ブログです

MENU

Google Apps Scriptでダンジョンゲームを作る

こんにちは!!虎の穴ラボ 新規開発チームのgodanです。

本記事は 虎の穴ラボ Advent Calendar 202212日の記事です。
アドベントカレンダーを書いてると年の瀬が迫っているのを実感します。

昨日はT.Mさんで「AWSのコンテナツール、Finchを動かしてみる」でした。Finchのロゴは個人的に結構好みなので気になっていました。自分もブログを読みながら試してみたいと思います。

Google Apps Scriptとは

Google Apps Script(通称: GAS)はGoogleのプロダクトで使用することができるJavaScriptプラットフォームです。
Googleが提供しているGmailやスプレッドシート、フォームを始めとしたサービスの自動化や拡張を自分で作成することができます。
提供されているAPIは幅広く、開発環境もオンライン上で提供されているなどプログラミング初学者でも触りやすくなっているのが特徴です。

公式ページ: Google Apps Script: Google Workspace を自動化、統合、拡張。

スプレッドシートではシートのデータを取得したり、背景に色を塗ったり、画像を操作したり、様々なことがAPIとして提供されています。
これだけ色々提供されているとゲームが作れそうですね……?作ってみよう!となった結果を今回お話しようと思います。

ゲーム 概要

疑似3Dで描写されたダンジョンを彷徨い自力で脱出するシンプルな3Dダンジョンゲームになっています。移動は画面下にある矢印ボタンを押すことで移動します。
かんたんな戦闘も実装していて、ゆくみちを阻むモンスターとスプレッドシートバトルをしながら脱出を目指します。

実際に実装されたスプレッドシートはこちらになります。実際にプレイする際はコピーしてお使いください。

docs.google.com

実装してみる

ここからは実装についてお話します。全ては書ききれないため操作部分とマップデータ、モンスター画像の処理について触れていきます。
戦闘部分ついては先日虎の穴ラボで行われた「Google Apps Script LT会」でお話しましたのでご興味があればぜひYoutubeのアーカイブをご参照ください。 また、実際のソースコードはスプレットシートに付属していますのでぜひGASのコードを御覧ください。

www.youtube.com Re:Re:GASで始めるゲーム開発 - Speaker Deck

操作について

操作部分はスプレッドシートの図形を用いました。


スプレッドシートでは図形にスクリプトの呼び出しを設定することができます。GASで実装した関数をここから呼び出しています。
移動の処理を共通化してmove('forward')と呼び出したいところですが、スクリプトの割り当てでは引数を用いることができないので今回はturning_leftgo_forwardなどのアクションごとに関数を作りました。

go_forward()の内容です。冗長な部分は省略しています。

function go_forward() {
    const spreadSheet = SpreadsheetApp.getActive()
    const conf_sheet = spreadSheet.getSheetByName("conf_sheet")
    const map_sheet = spreadSheet.getSheetByName("map")
    const map = map_sheet.getRange(1, 1, 21, 25).getValues()
    let direction = parseInt(conf_sheet.getRange(3, 2).getValue())
    let current_location_x = parseInt(conf_sheet.getRange(1, 2).getValue())
    let current_location_y = parseInt(conf_sheet.getRange(2, 2).getValue())

    if (direction == 1) {
        try {
            forward = map[current_location_y - 1][current_location_x]
        } catch (err) {
            forward = "#"
        }
        if (forward != "#")
            conf_sheet.getRange(2, 2).setValue(current_location_y - 1)
        else
          setMessage("壁で進めない")

    } else if (direction == 2) {
    (中略)
    }
    if (forward == "!")
        setMessage("Congratulation!!ゴールです")
    draw()
}

プレイヤーの現在地や向いている向きはその都度スプレッドシートから呼び出し、処理が終わったらシートに記載しています。冒頭の2行目から10行目でシートから現在位置やマップデータを読み込んでいる部分です。
その後プレイヤーの前方に道が存在するか確認した上で描写を行うdraw()関数を呼び出しています。

もちろん、GASでもMySQLやBigQueryなどのデータベースを活用することができますが、「GASとスプレッドシートで完結する」という今回のレギュレーションから外れているので使用しませんでした。

マップデータ

マップデータもスプレッドシート上で管理しています。

壁がある部分を#、ゴール箇所を!として扱いました 。
シートでは見やすくするために条件付き書式で壁の部分に色を塗っているおかげで、マップデータがビジュアル的にもわかりやすくなっています。
スプレッドシートはマップエディタとして非常に優秀でした。

モンスターの描写

今回ランダムエンカウント方式でモンスターを出すようにしました。
ダンジョンの中を歩いてると一定の確率でモンスターに行く手を阻まれます。今回は画像を表示することで実現しました。


モンスター素材提供: 【Rド】

実装するのに困った点としてGASで画像を追加するには公開されたURLを用意しないといけません。今回は素材の2次配布にあたるためモンスター画像のオープンなURLを用意できません。そのため、画面外に画像を予め用意することにしました。

画像の移動は次のように操作することができます。

// シートにある画像を取得
image_objects =  sheet.getImages();
// シート 13, 10に移動
image_objects[0].setAnchorCell(sheet.getRange(13,10));  

もちろん別シートへの移動もできるのですが、現在のスプレッドシートではリロードしないと移動元のシートから画像が消えません。 ブラウザをリロードするまで倒したモンスターが消えないので、シートをまたいだ移動は使用出来ませんでした。ゲームを作るにおいてはかなり痛恨の仕様です。そのうち直ることに期待したいです。

おわりに

ここまで読んでくださった方はGASでゲームを作りたくなったのではないでしょうか? GASでのゲームの作り方を説明していたので最後に不便だった点をいくつかまとめてご紹介させてください。

  • 実行が遅い
  • ある程度素早く読み書きできるデータベースがない
  • 描写が直感的にできない
  • 画像や図形などを操作する関数が不十分
  • 処理が遅くてたまにバグる
  • 複数人が一つのシートでプレイするとバグる

まだまだいっぱいありますが、GASでゲームを作成してみたところかなり不便なのがわかりました。
落胆してはいけません。ダンジョンゲームを作るおすすめの方法があります。
実はUnityというゲーム制作に特化したツールが存在します!ダンジョンゲーム作成ツールがUnity アセットストアで販売しています! assetstore.unity.com

ちょうど虎の穴ラボ Advent Calendar 2022の2日目の記事がUnityのチュートリアル的な記事になっています!ぜひこちら読みながらチャレンジしてみてください。

toranoana-lab.hatenablog.com

GASはぜひ事務作業などの効率化にお使いください。ゲームはUnityやUnreal Engineで作ろう!
明日はかなざわさんで「Atlantis + Cloudflare tunnelでTerraformの自動実行環境を導入する」です。お楽しみに!

P.S.

採用

虎の穴では一緒に働く仲間を募集中です!
この記事を読んで、興味を持っていただけた方はぜひ弊社の採用情報をご覧下さい。
yumenosora.co.jp

LINEスタンプ

エンジニア専用のメイドちゃんスタンプが完成しました!
「あの場面」で思わず使いたくなるようなスタンプから、日常で役立つスタンプを合計40個用意しました。
エンジニアの皆さん、エンジニアでない方もぜひスタンプを確認してみてください。 store.line.me