feature image

2017年12月13日 | ブログ記事

非ノベルゲームにおけるシナリオシーンの知見

この記事はtraP Advent Calendar 12月12日の記事です。

今個人的に作っているゲームでストーリー部分を作成した時に得た知見などを書いていきます。ストーリー部分はノベルゲームなどの立ち絵+テキストがあるようなものだと思ってもらえればいいです。

背景

以上を踏まえて、テキストを記述できるスクリプト(と呼べるかわかりませんが…)を設計しました。

仕様

とりあえずサンプルを以下に示します。

@define(tarou, 太郎, left)
@define(hanako, 花子, right)

tarou:

@wave(tarou)
こんにちは

hanako:

@wave(hanako)
こんにちは

tarou:

@change(tarou, laugh)
今日はいい天気ですね。

hanako:

@change(hanako, laugh)
ええそうですね。

sample

まず @define で登場キャラクターを定義します。1番目にid、2番目に表示されるキャラクター名、3番目に表示される位置を指定します。以下キャラクターを指定するときはこのidで指示します。

次の行からは実際のセリフを記述していきます。id: (以下ラベル)から次のラベルまでがそのキャラクターのセリフです。セリフにはテキストの他に@waveなどのアクションと呼ばれるものを書くことが出来ます。[1]

恐らくこれでそこそこの表現力はあるはずです。もし足りなければアクションを追加すれば表現を増やせます。あまりややこしい表現は無理かもしれませんが。

実装

仕様が決まったので早速実装に入りますが、ゲーム側で直接スクリプトを読み込んで処理するのは危険です。というのも人間誰でもミスをするもので、アクション名のスペルミスはもちろん定義していないキャラクターを使おうとする、というような実行時に死ぬようなミスは予め検知したくなります。

ということでエラーチェッカー兼、ゲーム側で読みやすくなるようにJSONに変換するアプリケーションを作りたいのですが、これの使用者(テキスト担当)は初めに述べたようにPCを所持していないので

のいずれかを作成することになります。スマートフォンのアプリは手間がかかるので省くとしてWebアプリかbotかで悩みましたが、生成したファイルをこちらが受け取る手間を考えるとbotの方が良いと判断しました(一度botを作ってみたいというのもありました)。

メンバー間の連絡にはSlackを使っているので(と言ってもLINEから完全に移行できていませんが…)、Slackのbotを作成しました。

slack1

こんな感じにメンションを飛ばすとbotが変換してくれます。

slack2

エラーも指摘してくれます。

botはRubyで実装してHeroku上で動かしています。Herokuは1つのアプリケーションだったら無料で24時間連続稼働できるのでおすすめです。

初めはHUBOTを使用してbotを作成していたのですが改行を含むメッセージを上手く取ることができなかったので、slack-ruby-clientを使用しました。

チェッカーですが、

def_action(:define, [:alphabet, :any, %w(left center right)])
def_action(:wave,   [:id, :varg])
def_action(:change, [:id, :alphabet])
def_action(:show,   [:id])
def_action(:hide,   [:id])

というような感じでアクション名と引数の型か取りうる値を書いておいてそれを満たすかどうかをチェックしています。

あとは変換したファイルをゲーム側で読み込んで書いてある通りに処理すれば目的は達成です。幸い使用しているSiv3DというライブラリにJSONを読み込む機能があるのでそれを使用しました。

実際に使ってもらう

実際の使用感はどうなの?と気になるかと思われますが、自分で使ってみた分にはそこそこ快適でした。"そこそこ"と書いたのはbotという性質上仕方ないのですが、テキストを書く→変換→修正→変換というサイクルが少しやりにくいと感じました。

また、変換結果がメッセージとしてポストされるので、結果をコピーしてから手元のスクリプトファイルにペーストしないとゲームに反映されないというのも上のサイクルをよりやりにくくしていると感じました。

そこで以下のように修正しました。

  1. 編集しにくい
    • ポストしたスクリプトを編集したら再変換するようにした
  2. 変換結果をコピーするのが面倒
    • 変換結果をファイルとしてアップロードするようにした

それぞれ、slack-ruby-clientが対応しているので容易に対応することができました。

1はRealTime::Clientでメッセージを受け取る場合、編集した時は内容がdata.textではなくdata.message.textとなります。編集時はdata.subtypemessage_changedとなるのでそれによってメッセージの内容の取得元を変えれば編集時にもポストと同様の処理をすることができます。

client.on :message do |data|
  text = if data.subtype == 'message_changed'
           data.message.text
         else
           data.text
         end

2はここを見てもらえればいいのですがHerokuで動かす場合は/tmpでないとファイルが書き込めないみたいなので注意してください。Rubyの場合はTempfileを使うことができます。

Tempfile.create("prefix") do |f|
  f.write(scenario.to_json)
  f.close
  web_client.files_upload(
    channels: data.channel,
    as_user: true,
    file: Faraday::UploadIO.new(f.path, 'application/json'),
    title: '変換済みシナリオ',
    filename: 'scenario.json'
  )
end

これらの改良をすることでだいぶ快適になりました。

まとめ

非ノベルゲーム向けの簡単なノベルエンジンとスクリプトを設計、実装しました。変換するプログラムをSlackのBotとして実装しましたが、なかなか使い勝手が良かったので是非とも参考にしていただければと思います。

明日はdainさんとwhiteonionさんです。


  1. @defineをアクションとして扱うのに違和感(C言語などで関数呼び出しで変数宣言するようなものです)を持たれる人もいるかもしれませんが、ここでは簡易さを優先してアクションとしました。 ↩︎

long_long_float icon
この記事を書いた人
long_long_float

プログラミングしてます

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2017年11月14日
IBIS2017参加報告
Keijan icon Keijan
ERC20トークンを用いた宝探しゲーム(真)の提案【アドベントカレンダー2018 10日目】 feature image
2018年11月3日
ERC20トークンを用いた宝探しゲーム(真)の提案【アドベントカレンダー2018 10日目】
Azon icon Azon
2021年5月19日
CPCTF2021を実現させたスコアサーバー
xxpoxx icon xxpoxx
2023年4月27日
Vulkanのデバイスドライバを自作してみた
kegra icon kegra
2024年4月14日
Spotifyのクライアントを自作しよう
d_etteiu8383 icon d_etteiu8383
2021年12月8日
C++ with JUCEでステレオパンを作ってみた【AdC2021 26日目】
liquid1224 icon liquid1224
記事一覧 タグ一覧 Google アナリティクスについて 特定商取引法に基づく表記