コンピュータで自動テストプレイ!
ゲームデザイナーは、可能であれば何度もテストプレイを行いたいと考えています。しかし、プレイヤーはそうではありません。プレイヤーは、未成熟なテスト版ではなく、“完成品”を遊びたいのです。
では私たち(ゲームデザイナー)はどうしたらよいのでしょう?
私の場合プログラマなので、まず「コンピュータでテストすればいいじゃん」という案が浮上します。そうすれば、テストを10,000回実行することも可能なのですから!
どうやったら自動でテストができる?
もし本当に10,000回のテストを実行しようとするなら、 自動的に ゲームがプレイされるソフトウェアを開発する必要があります。
まず第一に、プレイヤーの代わりとなるプログラムが必要です。
これは関数です。プレイヤーとは、彼/彼女が実行可能なアクションからいずれか一つを選択する(あるいは選択しない)関数なのです。
しかし、プレイヤーはゲームを回しているわけではありません。プレイヤーはゲームの流れを切り替えているだけです。 それでは、何がゲームを回しているのでしょうか?それはルールです!
以上を踏まえて、自動テストプレイを可能にするような定義をゲームに対して行ってみましょう。
プログラミングのためのゲーム定義
「ゲームとは、複数のルールを持ち、ゲーム終了までその全てを適用し続けるものである。」
さらに、ゲームを構成する他の要素についても検討してみましょう。
[ルール]
ルールは関数である。ルールは、ゲームの状態(これを「コンテキスト(context)」と呼ぶことにします)を新しい状態に遷移させるものです。
プログラムで示すなら、こんな感じでしょうか…
例) “dealAllCards”という名称でルールを定義した場合
// ルール適用前の状態 print context['deck'].length; // 16 print context['player1']['hands'].length; // 0 next_context = dealAllCards(context); // ルール適用後の状態 print context['deck'].length; // 0 print context['player1']['hands'].length; // 4
この定義において、コンテキストは直前のコンテキストにのみ依存します。
これは、プログラムで並列処理を行うことが可能であることを意味します。
[プレイヤー]
先に述べた通り、プレイヤーとは、彼/彼女が実行可能なアクションからいずれかを選択する関数です。
例)『ババ抜き』のプレイヤーの場合
actions = [ drawCard(prev_player['hand'][0]), // 前のプレイヤーの手札から1枚(左端)引く drawCard(prev_player['hand'][1]), // 前のプレイヤーの手札から1枚(左から2枚目)引く ... ]; selected_action = player1(actions);
パラメータ等を変えることでプレイヤーごとに条件判断の順序・重み付け等を変えれば、個性も表現できそうです。
[コンポーネント]
コンポーネントは定義され、そのインスタンスがプレイにおいて使用されます。
例) トランプの定義
cards = [ { "suit": "spade", "number": 1 }, ... ];
[デッキ、手札、捨て札、ゲームボード上のあらゆるフィールド]
デッキ、手札、捨て札およびその他のあらゆるフィールドはただのラベルに過ぎません。
例)『ババ抜き』におけるフィールド
oldMaidContext = { 'players': [ 'player1': { 'hands': [] // プレイヤー1の手札 }, ... ], 'trash': [] // 捨て札 };
[メカニクス]
少し脱線して、ゲームデザインでいうところのメカニクスはどうでしょうか?いわゆる、「ワーカープレイスメント」とか「デッキ構築型」とか、粒度を小さくして「セットコレクション」とか「勝ち抜け」とか。
これらは基本的に複数のルールをセットにした概念と言えます。どちらかというと、ルールに付けられたタグと考えるとしっくりきます。
例)『ババ抜き』に関連するメカニクス
[勝ち抜け] ルール:手札がなくなったプレイヤーは勝者としてゲームから抜ける。
[デッキ構築型][手札管理][セットコレクション] ルール:プレイヤーごとに手札を有する。
とはいえ…
このようにゲームの定義を行ってはみましたが、この定義に沿って皆が一からテストプレイプログラムを作り始めるのは効率がよくありません。
というわけで、先日テストプレイフレームワークの開発を始めました。
→ TOPに戻る