読者です 読者をやめる 読者になる 読者になる

Just $ A sandbox

プログラミングとかPCとかの技術的なメモ

ノベルゲームシナリオ論

※ 以下は全て個人の感想です。

長さは「正義」

長いゲームは飽きられやすいけれど、その点さえ解決できれば長さは完全に正義である。
長時間プレイしてくれたプレイヤーは大抵どのキャラにも相応の愛着が沸いているので、キャラクターらしささえ損なわなければどんなエンディングでも(ヒロイン死亡とかそういうのじゃない限り)そんなに文句はおきない。
あとはどうやって長時間飽きさせずにプレイさせるかというところで、若干邪道な方法に、ノベル部分以外にミニゲーム的な要素を加えてそっちをめちゃくちゃ面白くする(場合によってはそちらをメインにしてノベル部分がむしろおまけでもよい)というやつ。
商業ゲームではこの方法のものをたまに見る。ミニゲームが面白いからついやっちゃう的な。アレとかアレとか。

安易な選択肢の導入

ノベルゲームというからにはゲーム性がないといけないということで選択肢を導入しているゲームは割とよくある。
けれど、選択肢によってシナリオが分岐し、それによってエンディングまで変わる必要性はどこにあるの、っていいたくなることはよくある。
選んだ選択肢でTRUE ENDとかBAD ENDとか別れてしまうのであれば、実質製作者の決めた選択肢を選ぶことを強要されているので自由度が増してる感じが全くしない。無駄に周回プレイを強要させるのは基本的に悪手だと思う。
あとは、どうでもよさそうな選択を1回間違えるだけで結末が大きく変わったり事実がねじ曲げられる系とか。プレイヤーからしたら意味不明だと思う。

ただし例外的に選択肢を導入することに意味のある場合が少なくとも3つはあると思う。もしかしたらもっとあるかも。
1つ目は、選択肢を選んだ結果が平等になる場合。商業のいわゆるキャラゲー(ストーリーよりキャラクターとの会話とかキャラクターに関するエピソードを楽しむやつ)ならこういうのは結構よくある。要はプレイヤーはどのキャラとくっつくかが選べるだけで、それ以外にシナリオ的な差異は発生しない。この場合は周回プレイを強要しないし、どれを選んでも望んだ結末(選んだキャラとくっつく)が得られるのでそういう意味ではエンディングが平等なので平和だ。
2つ目は、選択肢にメタ的な意味がある場合。一番安易なものとしてよくある「ループもの」ノベルゲームなら、周回プレイをさせることにすら意味がある場合がある。そういう感じで選択肢を選ばせることにも意味を持たせられれば十分選択肢を出す理由になる。ただしこれもシナリオの書き方の問題で、何度も何度も似たようなエンディングを通らないと真のエンディングに到達しないみたいなのはそれはそれで問題な気がする。
3つ目は、選択肢を選ぶ行為がシミュレーション要素を含んでいる場合。シナリオ攻略のために選択肢があるわけじゃなくて、プレイヤーの行動コマンドとして選択肢が使われている場合。アレとかね。これはちゃんとゲーム性があるのでいいと思う。この方針で真面目に遊べるものを作るのはかなり大変だと思うけどそれはまた別の話だ。

いずれにせよ、本当にこのゲームには選択肢がいるの?というのは作る側にとっては結構大事な問だと思う。
あとはエンディングは本当にそれだけ必要なの?BAD ENDになった後は最初からやらせる必要性があるの?とか。
製作者の自己満足を「プレイ自由度」とか「ゲーム性」って言葉でごまかしてないかと。

説明セリフ

慣れの問題だと思うけど説明セリフがどうも気になるので気をつけたい。(自戒を込めて)
そもそもそのイベント自体、キャラクターの性格を説明するためのものだよね?ってのがプレイヤーに伝わってしまっているやつ。
主人公とクラスメイトが謎の三文芝居をやったあと、ト書きで「こいつはいつもこんな調子だ。」とか説明するやつ。
キャラギャルゲーとかに顕著。アレとかね。

会話の発散

会話の進みは2人の時と3人以上の時で全く違うという気がする。
2人会話は、会話イベントの目的が決まっていると一直線な会話になりやすい。のであまりコレばかりだと単調になりやすい。
3人以上のキャラクターがいると、各人が好き勝手しゃべるので全然話が目的の方向に収束しない。ので、ページを稼ぎたい場合は無理にでも人を増やすのはかなり効果的だと思う。

情景描写

ノベルゲームでの情景描写は絵との乖離が発生しやすいので注意が必要だけれど、人間には五感があるので視覚以外の情報をプレイヤーに伝える意味での情景描写は結構重要だと思う。
特にその場所の匂いと現在吹いている風の様子を描写するのは強力だと思う。
割とどこでもやりやすいことと、適当書いても他の記述と矛盾しにくいので。

ループものも飽和している

上の記述と矛盾しているような気もするけどループものは正直すでに飽和しているので、このジャンルで斬新さで勝負するのはもう難しい気がする。
というかループ設定持ち出すと他のループものと比較されやすいので安易に使うのは危険かもしれない。
時系列がバラバラの話が1つにまとまるみたいな手法をループ以外で実現できると、同じような方向性でもまた印象が変わりそう。


終わり。
意見は人それぞれだと思います。

Monadic functor(後で調べる)

$G : \mathcal{C} \to \mathcal{D}$がmonadic functorということは、圏同値の差を無視してforgetful T-algebra functor $G ^ T : \mathcal{C}^T \to \mathcal{C}$と同じだと思えるってことだ.
ここから何か分かったりしないんだろうか.

MonadPlusとNearSemiringで反例探し

d.hatena.ne.jp

上の記事を読んでちょっと考えたこととかをまとめる.

NearSemiringとは和についてモノイド, 積について半群で, 0が左吸収元である左分配的集合.(wikipedia流儀; 関係ないけど以下に出てくる例はHaskellMonadで, Monad則からreturnが積の単位元になるのでNearSemiringより少し強い)
まず元の記事にあるように, MonadPlus mに対し演算mplus及び>>=によってNearSemiringの構造が入るらしい.

当然最初の疑問として, そもそもbind>>=は左右で要求する型が違うので, そもそもどこ上の演算と見てるんだよという話である.
これはmplus>>=a -> m a上などに拡張してやると定義自体は普通にできる.

class NearSemiring m where
  (<+>) :: m a -> m a -> m a
  zero :: m a
  (<*>) :: m a -> m a -> m a
  one :: m a

newtype S m a = S { unS :: a -> m a }

instance MonadPlus m => NearSemiring (S m) where
  (S ma) <+> (S mb) = S $ \x -> ma x `mplus` mb x
  zero = S $ const mzero
  (S m) <*> (S k) = S $ \x -> m x >>= k
  one = S return

上の定義によって, MonadPlus mのもとでS m *上に演算<+><*>が定まる.
これが実際にNearSemiringの構造を与えることは適当に式を変形すればできると思う.
例えば右分配則だけやると以下(ただし以下ではS xxを自然に同一視する).

(m1 <+> m2) <*> k = \x -> (m1 x `mplus` m2 x) >>= k  (<+><*>の定義)
  = \x -> (m1 x >>= k) `mplus` (m2 x >>= k)  (MonadPlusの右分配則)
  = (\x -> m1 x >>= k) <+> (\x -> m2 x >>= k)  (<+>の定義)
  = (m1 <*> k) <+> (m2 <*> k)  (<*>の定義)

さてこれでまともな演算が定義できた.
あとはQuickCheck辺りを使えば, 具体的なmに対して左分配則が成り立たないような反例を見つけてくれる.

実際に動かして発見できた反例は以下.

[0,0] <*> ([0] <+> [1]) ≠ ([0,0] <*> [0]) <+> ([0,0] <*> [1])

---> [0,1,0,1] /= [0,0,1,1]

ところで, 記事で紹介されている論文には上のようなことはざっと見た限り載っていなさそうだった.(ちゃんと読んでないので書いてあったらすいません)

論文で扱っているNearSermiringはもう少し違う感じのやつで, 例えば以下のようにして定めたDCはMonadPlusになり, よってNearSemiringの構造が入る. (コードは論文より引用)

newtype Ran f g x = Ran { unRan :: forall y. (x -> f y) -> g y }
newtype Exp f g x = Exp { unExp :: forall y. (x -> y) -> (f y -> g y) }
newtype DC f x = DC { unDC :: Ran (Exp f f) (Exp f f) x }

instance Monad (DC f) where
  return x = DC $ Ran $ \f -> f x
  DC (Ran m) >>= f = DC $ Ran $ \g -> m (\a -> unRan (unDC $ f a) g)

instance MonadPlus (DC f) where
  mzero = DC $ Ran $ \k -> Exp $ \c x -> x
  mplus (DC (Ran a)) (DC (Ran b)) = DC $ Ran $ \sk -> Exp $ \f fk -> unExp (a sk) f $ unExp (b sk) f fk

rep :: Monad m => m a -> DC m a
rep x = DC $ Ran $ \g -> Exp $ \h m -> x >>= \a -> unExp (g a) h m

abs :: MonadPlus m => DC m a -> m a
abs (DC (Ran f)) = unExp (f $ \x -> Exp $ \h m -> return (h x) `mplus` m) id mzero

さてせっかくなのでこうして定義されたDCに対しても, 前述の仕方でNearSemiring型クラスのインスタンスにし, 右分配則が成り立たない反例を探してみよう.
QuickCheckで探した所以下の例が見つかった. (ただし以下の例ではabsとrepを用いてm aDC m aを同一視している)

[0,0] <*> ([0] <+> [0]) ≠ ([0,0] <*> [0]) <+> ([0,0] <*> [0])

--> [0,0,0,0] /= [0,0,0,0,0,0]

というわけでQuickCheck様様という話でした. おしまい.

参考文献

コード