目次 [追加]
オブジェクト指向シナリオ
本記事では、TRPG、特にそのシナリオを、近年主流となっているプログラミングの技術・思想の一つである「オブジェクト指向」を使って分析・記述してみたいとおもいます。
これによって「スッキリした!」「どんどん作れるようになった!」というところまで行けると良いのですが、とりあえずはオブジェクト指向の紹介と、「これは使えるかもしれない」という期待をもたせられるだけの説明をすることを目標としたいとおもいます。
また、本記事を読むことでオブジェクト指向の概念をつかむ勉強になるかもしれませんが、説明に正確を期しているわけではありませんので却って邪魔になるかもしれません。「プログラムに手を出すつもりはないけど、オブジェクト指向の概念は気になる」という方がいらっしゃいましたので、そういった方の参考になれば幸いです。
また、本記事は2014年夏コミ発行予定の『TRPGシナリオ作成大全 Vol.4』(http://scenario.trpg.me/)への掲載記事の草稿でもあります。本記事に触発されて「自分もなにか書いてみたい」という方がいらっしゃいましたら、お気軽にご連絡下さい。
なぜオブジェクト指向を使うか
そもそもオブジェクト指向ってなんでしょう? なんのために考えられたのでしょうか? その短いようで長い歴史を紐解くと様々な派生ができていて断言しづらいのですが、現在の僕の理解からすると、オブジェクト指向とは、作ったモノ(この場合はシナリオ)の構成要素(シーンとか、登場人物とか)を交換可能にするための技術です(とか書くと偉い人に怒られそうですが、そんな感じ)。
「交換可能である」とは、バリエーションを作れる、あるいは既存のモノを安全に(矛盾を起こすことなく)修正可能である、ということでもあります。
交換できないものと交換できるもの
例えば、車の部品の多くは、交換可能ではありません。シートが壊れたから別の車種の車に付いているシートを取り付けられるかというと、サイズが違っていて無理なことが多いでしょう。色や質感も、他のシートや内装から浮いてしまうでしょう。自作の留め具や表装を使ってカスタマイズする場合も、強度や耐水性、抗菌、紫外線による色あせ、急停止時の応力など、元々の仕様に慎重に合わせないと思わぬところで不具合が出てくるかもしれません。
一方で、パソコンのパーツの多くは交換可能です。サイズやコネクタの規格次第でなんでも、とはいきませんが、買ったパソコンのCPUやメモリ、ハードディスクなどは、交換することができます。また、USBケーブルを経由して、プリンタ、スキャナ、ディスクなど、様々なUSB機器を接続して動かすことができます。
何となくイメージはつきますか?
交換できると良いこと
ところで、TRPGのシナリオの構成部品を交換可能にすると、何がいいのでしょうか? ざっと挙げると、以下の様な良い点があります。
シナリオの見通しが良くなる
シナリオのバリエーションが作りやすい
シナリオ構造の使い回しがしやすい
シナリオクラフトのようなものを自作するときの参考になる
シナリオの構成要素を部品化して他の人と交換できる
ご覧いただくと分かるように、「いま作りたいんだ、シナリオを、すぐに!」という人のお役にはあまり立ちませんね。さらに、これはある程度シナリオを作れる人を対象とした記事です。シナリオ作成初心者向けにはほとんど配慮していませんので、予めご了承ください。
シナリオのバリエーションが作りやすいため、ペアシナリオメイキングでは特に活かせるかもしれません。
オブジェクト指向の特性
オブジェクト指向には実はいろいろなタイプがありますが、ここではクラスベースのオブジェクト指向を前提に説明します。もっと言うと、僕はPHPしかまともに使えないので、PHPのオブジェクト指向がベースになっています。
# この記事で「クラス」と書いた場合、戦士、魔術師といった職業を指す言葉ではなく、オブジェクト指向で使われるクラスを指します。特にそういう規約や慣例があるわけではありませんが、本記事ではクラス名を〈 〉で囲って記述することにします。
クラス
オブジェクト指向言語では、世界を「オブジェクト(もの)」の集合としてモデル化します。その際、「オブジェクト」を直接記述するのではなく、それをモデル化(抽象化)した〈クラス〉として記述します。
なお、本記事では〈クラス〉とオブジェクトは原則として区別せず、本来オブジェクトと表記すべきところでも〈クラス〉として扱ってしまうことにします(なんて乱暴な!)。
オブジェクト指向の〈クラス〉には、「継承」「カプセル化」「多態性(ポリモーフィズム)」の3つの特徴があります。
継承
オブジェクト指向では、ある〈クラス〉の特性を引き継いだ〈クラス〉を作ることができ、これを「継承」と呼びます。「継承」を使うと、少ない記述で沢山のバリエーションを記述することができます。
たとえば、動物の種の分類を、継承を使って記述することを考えてみます。我々人間は、「霊長類」に属していて、「霊長類」は「哺乳動物」に属していることはご存知かと思います。この関係は、〈哺乳動物〉クラスを継承して〈霊長類〉クラスを作ることができ、さらに〈霊長類〉クラスを継承して〈人間〉クラスを作ることができる、というように表すことができます。
この例では〈人間〉クラスを記述する際に、「恒温動物で体毛を持ち」(〈哺乳動物〉クラス)、「5本の指を持ち両目は顔の正面に位置する」(〈霊長類〉クラス)、といった上位で記述されるべき項目は省略(継承)することができます。そして、〈人間〉クラスでは、言葉を使う、火・道具を使う、1500cc弱の脳容量を持つといった人間特有の特徴のみを記述すれば済みます。
哺乳動物(胎生)に属するがカモノハシは卵生である、といったように親クラスの記述を子クラスで上書きして例外を記述することもできます。
継承のもう一つの例として、TRPGでよくある〈キャラクタ〉クラスで考えてみましょう。
あるシステムで、デザイナは〈キャラクタ〉クラスを作ります(実際には〈クラス〉を作っているという意識はないと思いますが)。〈キャラクタ〉クラスは、腕が2本ある、肺呼吸を行う、空は飛べない、能力値が6種類ある、技能をn個持てる、「戦う」「調べる」「交渉する」などの行動が可能……などの特徴を持っています。
このシステムのデザイナは、〈キャラクタ〉クラスの子クラスとして、〈キャラクタ〉クラスを引き継いだ(継承した)〈戦士〉クラス,〈魔術師〉クラス,〈盗賊クラス〉を設定します。
どれも〈キャラクタ〉クラスを継承しているため、「腕が2本ある、肺呼吸を行う、空は飛べない、能力値が6種類ある、技能をn個持てる……」は共通であり、いちいち〈戦士〉や〈魔術師〉の説明には記載しません。
〈戦士〉クラスは重い武器と鎧を身にまとうことができ、剣技技能を習得できる、〈魔術師〉クラスは呪文を使うことができる、〈盗賊〉クラスは隠密系技能を持ち敵の急所を狙うことができる、など、〈キャラクタ〉クラスで説明されていないことだけが子クラスで記述されます。
カプセル化
カプセル化とはデータや処理をブラックボックスにすることですが、TRPGによせて説明するのは難しいですね。
カプセル化は、言ってみれば優秀な部下のようなものです。課長は、優秀な部下加藤くんに「A社の見積もり、よろしくやっておいて」と命令します。加藤くんは優秀なので、それだけでA社向けの見積もりを作って部長の承認をもらって、A社に提出して、メールでフォローまでします。実は課長は、別の部署から移動したばかりで見積の作り方なんて知らないのですが、加藤くんが優秀なので「よろしくやっておいて」というだけで仕事は回ります。このようなとき、加藤くんは、課長に対して見積の処理の仕方を「隠蔽している」と云い、このような状態を「カプセル化」と呼んでいます。
あるとき見積の処理方法が変わって1000万円以上の見積は担当役員の承認が必要になった、という場合でも、課長のやることは「よろしくやっておいて」というだけで、何も変える必要はありません。優秀な加藤くんが、制度の変更に合わせて処理を変えてくれるからです。
この喩え話で分かるように、課長はとても楽です。そして、プログラミングでもこれは重要な事です。見積もり処理が変わった時に、課長のところは無視して加藤くんのところだけを気にすればいいからです。
多態性(ポリモーフィズム)
同じ行動を宣言しても、〈クラス〉によって振る舞いが異なることを「多態性」と呼びます。
プレイヤが「僕のキャラクタは攻撃するよ」と言ったばあい、何が起きるでしょうか?
〈戦士〉の場合:「右手に持った剣で殴る」
〈魔術師〉の場合:「火炎の呪文を唱える」
〈盗賊〉の場合:「急所めがけてナイフを投げる」
このように、「攻撃する」という宣言が出された場合、実際の振る舞いは命令を受けたクラスによって変わっています。このような性質を多態性(ポリモーフィズム)と呼んでいます。
シナリオにオブジェクト指向を適用する
ここまでで、〈クラス〉の三要素の概念を掴んでいただけたと思います。「だからなんなんだ? 名前を付けただけじゃないか」という疑問はあるかもしれませんが、概念自体はそれほど難しくないと思います。
次に、いよいよ本題、オブジェクト指向を活用したシナリオの構成に移ります。
デザインパタン
その前にもうひとつ、「デザインパタン」という概念を紹介します。デザインパタンは、建築分野に端を発する長い歴史がありますが、簡単に言うと「オブジェクト指向を上手く使うための抽象化されたベストプラクティス」ということになります。
先ほど「だからなんなんだ?」という疑問が浮んだように、オブジェクト指向の概念を学んだだけではなかなか良いプログラムが書けるわけでありません。オブジェクト指向をどう上手く使いこなすか、その指針となるのがデザインパタンで、オブジェク ト指向では偉い人が23のパタンを編み出しています。
ただ、元々はプログラミングのために作られたパタンなので、TRPGのシナリオに使えるのはその一部です。以下では、「テンプレートメソッドパタン」と「ストラテジパタン」をシナリオに適用して、交換可能な性質をもたせる方法をご説明したいと思います。
テンプレートメソッドパタン
テンプレートメソッドパタンは、言ってしまえば「穴埋め」です。ネットで時々出てくる「テンプレ」だと考えていいと思います。
例えば、次のようなシナリオの「テンプレート」を見てください。
○○から依頼を受けたパーティは、途中○○を通過して、○○からの襲撃を撃退しながらも○○にたどり着き、○○と対決する。
この○○を埋めていくと、シナリオ(のあらすじ)っぽいものになりますね。このようにシナリオの固有名詞を○○に置き換えたものを「テンプレート」と呼びます。実際には、こんなに大雑把な文章ではシナリオとして使いづらいと思いますので、もっと細かく書くことになると思いますが、考え方としてはこんな感じです。
テンプレートメソッドパタンを使ったシナリオでは、このようにシナリオの一部を○○と書いて作ります。こうして作った穴だらけのシナリオが親クラスに当たり、それを継承した子クラスで「○○」の部分を埋めてシナリオを完成させます。親クラスでは、「後で子クラスを作るときに具体的内容を決める」ということだけ決めておくのです。
たくさんのシナリオを分析していくと、固有名詞を○○に置き換えることで「なんだ、同じシナリオじゃん」となるものが見つかると思います(別に悪いことではありません)。同じパタンのシナリオを見つけてテンプレートにすることができれば、テンプレートを元にして、「○○」の部分を固有名詞で埋めることで安定したシナリオを量産することができます。
「あれ、これは?」と思った方もいらっしゃるかもしれませんが、「シナリオクラフト」もテンプレートメソッドパタンだと考えて差し支えないかと思います。
「テンプレートメソッドパタン」はオブジェクト指向の〈クラス〉の「継承」を活用したパタンです。「テンプレート」が親クラスであり、実際のシナリオがそれを継承した子クラスにあたります。親クラスでは、シナリオの共通部分は決めますが、その一部の決定を親クラスを継承した子クラスに任せています。
ストラテジパタン
さて本記事で紹介するもう一つのデザインパタンが、「ストラテジパタン」です。この記事で一番書きたい、理解していただきたいところが実はここです。
ストラテジパタンは、一見するとテンプレートパタンに似ています。テンプレート的なものがあって、それの穴埋めをしてシナリオを作るという点では同じです。
しかし、単なる文章を埋めるのではなく、〈クラス〉を埋めます。しかもクラスならなんでもいいわけではなく、規定の特性を持った〈クラス〉を埋めなければなりません。
これも例で説明しましょう。次のようなシナリオがあるとします。
村をゴブリンが荒らしまわっていて、村人はたいへん困っています。そこで、「村人{A}はパーティに依頼をします」。パーティがゴブリンを退治すると、「村人{A}はパーティにお礼をします」。
シナリオによって、この{A}を埋めますが、この{A}は〈クラス〉です。「村人」と前に付いているように、村の住人が{A}に入るのですが、名前を決めるだけではダメです。地位、家族構成、能力、性格などを決めても足りません。では、何を決めなくてはいけないのでしょう? もう一度、例で上げたシナリオの文章を見てください。次の二つの文章がありますね。
「村人{A}はパーティに依頼をします」
「村人{A}はパーティにお礼をします」
このシナリオで、村人{A}は、「パーティに依頼をする」「パーティにお礼をする」という二つの役割を負っていることが分かりますね。つまりこのシナリオでは、「依頼者」になるには、「パーティに依頼をする」と「パーティにお礼をする」の二つが設定されているというのが必要条件なのです。
この「パーティに依頼をする」「パーティにお礼をする」のような、〈クラス〉に要求される条件を《インタフェース》と呼んでいます。インタフェースを満たすように〈クラス〉を作ることを「インタフェースを実装する」と呼びます。
このシナリオでは「パーティに依頼をする」「パーティにお礼をする」の二つの条件を持ったインタフェースを《依頼者》インタフェースと呼ぶことにします。
それでは、《依頼者》インタフェースを実装したクラスの例、〈村長〉〈村の無骨な若者〉〈幼い少女〉を見てみましょう。
{A}が村長の場合:
「依頼をする」→「おお旅の方よ、お願いだ、村を救ってはくれないか。多くはないが、報酬を出させていただく」
「お礼をする」→「ありがとう、村は救われた。これは約束の報酬じゃ」
{A}が村の無骨な若者の場合:
「依頼をする」→「すまねえ、お願いを聞いてくれないか。聞いてくれたら、あんたたちが喜びそうな珍しい植物の生えている場所を教えるよ」
「お礼をする」→「ありがとう、本当にありがとう。お礼に、俺が見つけた薬草の場所を教えるよ。付いてきてくれ」
{A}が幼い少女の場合:
「依頼をする」→「お兄ちゃんたち、強いの?お願い、みんなを困らせてるゴブリンをやっつけて」
「お礼をする」→「ありがとう!お兄ちゃん。お兄ちゃんたちが助けてくれたことは、ずっとずっと、忘れないよ」
{A}のバリエーションを増やせば、シナリオのバリエーションが増えることになります。
覚えていますでしょうか。これはクラスの「ポリモーフィズム」という性質を利用しています。「攻撃する」とプレイヤが宣言した時に、戦士か魔術師か盗賊かで、実際どんな攻撃をするかが変わりましたね。
また「カプセル化」の性質も利用しています。シナリオでは、「パーティに依頼をする」「パーティにお礼をする」という、かなりアバウトな指示しか出しません。依頼者オブジェクトは、「パーティに依頼をする」「パーティにお礼をする」の具体的な内容をシナリオから隠蔽しているので、依頼者オブジェクトが村長だろうが若者だろうが少女だろうが構わずにシナリオからはアバウトな指示を出すだけで済んでいるのです。楽ちんですね。
最初に書いたように、オブジェクト指向の目的は「交換可能性をもたせる」ことです。このように、オブジェクト指向では、「インタフェース」「カプセル化」「継承」「多態性」といった技術や性質を活用して、交換可能性を実現しています。
「悪霊の家」にストラテジパタンを適用する
同じくストラテジパタンの活用例として、クトゥルフ神話TRPGのサンプルシナリオ「悪霊の家」をオブジェクト指向的に記述し直し、カスタマイズしやすくしてみます。
『TRPGシナリオ作成大全Vol.2』の記事にあるように、このシナリオの改変ポイントはいくつかありますが、そのうち「ラスボスを変更する」ことにしてみます。記事でも注意していますが、ラスボスを変更した場合、ルールブックの中から代わりのラスボスを選んで、そのデータを置き換えるだけでは足りません。シナリオ中に記載のある目撃情報などの証拠情報や、ラスボスが引き起こすイベントを、ラスボスの変更に合わせて書き換えなければならないのです。
実際のところ、このシナリオを読むと、ラスボスになっているコービットの情報やイベントは、以下のようにシナリオ文中のあちこちに散らばっていることが分かります。
「悪霊の家」は短かめのシナリオですが、それでもラスボスが変更になったので一つの見落としもなく全て書き換えろ、と言われると、けっこう神経を使うことになります。このように、書き換えなければならない情報が散らばっていて、1箇所を書き換えると他の箇所で矛盾を生じる状態は、「交換可能」とは言えません。
ではどうすればいいでしょう?
オブジェクト指向的な答えは、「記述を、ラスボスというクラスにまとめる」です。
そして交換可能性を確保するため、「悪霊の家」のラスボスに以下の様な《インタフェース》を義務付けます。
「悪霊の家」《ラスボス》インタフェース
目撃される
ガブリエラに目撃される
マカリオの二人の息子に目撃される
警告する
攻撃する
現れる
そして、シナリオ中で目撃されたり犠牲者の死体が発見された箇所では、具体的な記述の代わりに、以下のように記述します。
《ラスボス》 . 目撃される
《ラスボス》 . ガブリエラに目撃される
《ラスボス》 . マカリオの二人の息子に目撃される
《ラスボス》 . 警告を出す
《ラスボス》 . 攻撃する
《ラスボス》 . 現れる
このように、《インタフェース名》.「〜する(される)」という形式で表現することにします。シナリオ中には、具体的に「どんな姿をしていたか、何が見えたか、何が残されたか」「どんな攻撃をしてくるか」は記載しません。上のように、「誰が」「何をしたか」だけを記載します。
マスターは、「《ラスボス》. 目撃される」というシナリオ中の記述を見たら、《ラスボス》インタフェースを実装した〈クラス〉を参照してその中の「目撃される」という設定を読み上げます。「悪霊の家」オリジナルでは〈コービット〉クラスがそれにあたります。
こうすることで、シナリオから《ラスボス》を抽象化することができ、《ラスボス》は交換可能性を持つようになります。
悪霊の家のラスボスのバリエーションを考えるシナリオ作成者は、《ラスボス》のインタフェースである「目撃される」「ガブリエラに目撃される」などを具体的に設定(「実装」)しなければなりません。逆に、これさえ設定していれば、シナリオは動作します。
交換可能なシナリオ
さて、本記事の一番初めで、シナリオを交換可能にすると何が良いか、という疑問に対して、「シナリオの要素を部品化して他の人と交換できる」というのを挙げました。ここで見てきた「悪霊の家」の《ラスボス》インタフェースのように、シナリオの構成要素の一部から「インタフェース」を抽出することで、シナリオの部品化の第一歩が踏み出せるのではないでしょうか?
《依頼人》インタフェースは、パーティに依頼するタイプのシナリオであれば、かなり広く使うことができそうです。
一方、「悪霊の家」の《ラスボス》インタフェースは、「ガブリエラに目撃される」などのかなり特殊な実装を含みますので、これを全く別のシナリオで使うのは残念ながら難しそうです。あくまでも「悪霊の家」のバリエーションを作る際に使えるにとどまるでしょう。
しかしながら、「ガブリエラ」の部分をさらにテンプレートメソッドパタン、あるいはストラテジパタンで書き直すとどうでしょうか? 「悪霊の家」のシナリオは、更に広いバリエーションを持てるようになり、《悪霊の家ラスボス》インタフェースを他のシナリオに組み込むことも不可能ではない感じになってきます。
みなさんも、お手元のシナリオをオブジェクト指向的に書きなおしてみてください。
参考文献
「ぼくにもわかるデザインパターン 第2章GoFパターン大カタログ」
http://www.ulsystems.co.jp/technology-topic028-01.html
デザインパタンについて比較的分かりやすく解説してくれています。
PHPによるデザインパターン入門
http://www.doyouphp.jp/book/book_phpdp.shtml
「オブジェクト指向シナリオ」紙魚砂日記
http://simizuna.exblog.jp/1435516
テーマは一緒ですが、本記事とは対象がちょっと違います。