したらばTOP ■掲示板に戻る■ 全部 1-100 最新50 | |
レス数が1スレッドの最大レス数(1000件)を超えています。残念ながら投稿することができません。

おちゃめくらぶ掲示板

2196御茶目菜子:2014/09/06(土) 01:41:20
ゲームの面白さは乱数で変わる
ナムコ作品で見る乱数の歴史
http://www.4gamer.net/games/042/G004287/20140905040/

先日「ゲーム世界を動かすサイコロの正体 〜 往年のナムコタイトルから学ぶ乱数の進化と
応用」という講演が行われナムコのゲームを「乱数」という視点から振り返っているにょ。
乱数とは何かというのはあえて言うまでもないけど簡単に言えば「でたらめな数」にょ。
とはいえ、その「でたらめ」をコンピュータ(演算)によって作り出すというのは難しいため
コンピュータによって作られた乱数は一般的には「疑似乱数」と呼ばれているにょ。
そのアルゴリズムは多種多様なものが存在するにょ。

そもそもゲームにおいて乱数とはどのような扱いなのかというとこれはもしも乱数がない
場合のことを考えてみると分かりやすいにょ。
例えばパックマンなどのアクションゲームのモンスターの動きはあらかじめ決められた同じ
動きしかできないしゴルフゲームでは風による影響もなく同じ強さで打ったら同じ場所に
ボールは飛んでいくにょ。
さらに言えばオセロゲームを作ったら最初から最終手までの手順が決まっているため
プレイヤーが同じ場所に打てば同じ場所に打って同じ結果になるし、じゃんけんゲームを
作ったらコンピュータが次に何を出すのか100%分かってしまうにょ。
つまり、乱数というのはゲームにおいてゲーム性を左右するものといっても過言ではないにょ。


疑似乱数を作り出す方法には様々な方法があるにょ。

 (1)タイマー値を使う
 (2)テーブル参照を行う
 (3)数式を計算して作る

(1)実行中に常にインクリメントしているタイマーがある場合はそれを使うことで乱数っぽく
することが可能になるにょ。
例えばプチコンでは1フレーム(1/60秒)ごとにインクリメントするMAINCNTLというシステム
変数が存在するにょ。
サイコロとして1〜6の乱数が欲しい場合にはボタンを押したタイミングで MAINCNTL%6+1 を
実行すればいいにょ。
一見すると乱数として使えそうだけど常に押しっぱなしのゲームだと同じタイミングで
同じ値が発生するため使えるかどうかは微妙にょ。
例えばこれをRPGのエンカウントに利用した場合には常に一定のタイミングでエンカウント
してしまうわけだからね。
これはファミコンソフトの「ヘラクレスの栄光」で用いられている模様にょ。
RPGにおいて不用意にエンカウント率を高めるのはユーザーにとってはあまりうれしいもの
ではないけどボタンを押すタイミングだけで決まってしまうためユーザーのプレイスタイルに
よってエンカウント率がやたら高い(低い)というイメージができてしまうにょ。(RPGで
エンカウントするのを乱数で決めるならば敵にエンカウントするごとに何歩歩いたら次に
エンカウントするのかというのを求めれば1歩歩くごとにエンカウントしたりとか全然敵が
出てこないということも防ぐことができる)
ボタン押しっぱなしのゲーム(常に抽選を行うゲーム)とは相性が悪いけど(周期が短く
タイマーの動作が速ければ)ゲームによっては実用になるにょ。
とはいえ「これは乱数か?」と聞かれたら微妙なので個人的には(2)のテーブルと合わせて
使うのがベターといえるにょ。


(2)テーブル参照を行うためにはあらかじめ配列変数などにテーブルを確保しておく必要が
あるにょ。
そんなことが難しい黎明期のゲームでは適当なアドレスのROMの値を読み取ってそれを元に
乱数としていたにょ。
1バイト取り出せば0〜255の乱数を得られるにょ。
しかし、ROMのデータが完全にバラツキがあるという保証はできないにょ。
00かFF連続するなんてこともあるのでどの部分を読み出すかも重要になってくるにょ。
それにROMバージョンが変われば読み出す値も変わるため再現性を求めるならばROMデータを
使った方法はあまり使えないにょ。
とはいえ、乱数のテーブルを自前で用意する(あらかじめ配列変数などに値を入れておく)
ならば自由自在にコントロールできるため万能の疑似乱数になるにょ。
特定の値が出やすくするというのも簡単にできてしまうからね。
10回に1回当たるくじ引きを行う場合には0〜9の10通りの数が均等に発生して0が当たりと
したときにはこのくじが少なくとも1回は当たるための期待値は16回になるにょ。
「1/10だから期待値は10回になる」と考えがちだけど10回引いて2回以上当たる場合もある
ためこのようになっているにょ。(1回当たるまでくじを引き続ける場合には当たる確率が
1/10のくじの体感確率は1/16しかないということ)
これはコンプガチャを見てのように確率の逆数で見た予想期待値と実際の期待値は異なる
ものになっているにょ。(コンプガチャの場合は当たりを引いたら当たりそのものの数が
減るためどんどん当たりを出すのが難しくなっている)

 ◎コンプガチャは規制されるべきなのか?
 http://6407.teacup.com/ochame/bbs/3231

1/10の確率であっても20回くじを引いても当たらないことは十分にあるけどそれだとユーザー
にとっては低確率に感じてしまうため連続でハズレの場合には高確率で当たるテーブルに
変更するなどの措置によって期待値とユーザーの体感値の乖離を減らすことが可能になるにょ。
ただし、周期を65536(2の16乗)にする場合に65536個のテーブルを用意する必要があるにょ。
周期が短くて済む乱数ならば速くて自在にコントロールできるのでこの辺はどのようなものが
必要かによってテーブル参照を使えば良いのではないかと思われるにょ。
「グー/チョキ/チョキ/パー/グー/チョキ」というテーブルを用意すればチョキをたくさん
出すけどパーはあまり出さないというコンピュータの思考ルーチンも簡単にできるにょ。
じゃんけんだとメリットが今ひとつ分からないかもしれないけどシューティングゲームならば
3WAYで発射する弾の確率を変えたりということもできるにょ。


(3)コンピュータの疑似乱数で最もポピュラーなのは計算式によって求めるものにょ。
C言語のrand関数など多くの言語、処理系で用いられているのが「線形合同法」と呼ばれる
ものにょ。
これはこれは簡単に求めることができるため便利だけど最初から備わっているためユーザーが
自分のプログラム内で疑似乱数を求めるルーチンとして線形合同法を使用する機会はあまり
ないのではないかと思われるにょ。(ただし、プチコンを除く)
rand関数ではsrand関数によってシードを与えることで同じ乱数列の乱数を発生させることが
可能になるにょ。
つまり、再現性があるというわけにょ。
これはゲームにおいては敵の動きは乱数にしたいけどゲームの初期段階の動きは固定したい
場合などに使えるにょ。
また再現性のある乱数を元にマップを作ればステージデータ無しであっても同じステージで
プレイ可能になるにょ。
これは私のJUMPING ISLANDで用いられているにょ。
ステージデータは不要であるため1画面プログラムであっても全9面(各ステージ990x256の
サイズ)のステージを用意することができたにょ。

 ◎1画面版 JUMPING ISLAND
 http://ochameclub.web.fc2.com/petitcom/1page.htm#jump

ただし、プチコンではRND関数でシードを与えることができないためこのJUMPING ISLANDでは
独自の線形合同法で求めているにょ。
それについてはプチコン講座の方で詳しく書いているのでそれを参照して欲しいにょ。

 ◎プチコン講座 番外編 プチコンで疑似乱数を作ろう
 http://ochameclub.web.fc2.com/petitcom/rnd.htm

線形合同法の一番の弱点は下位bitがパターン化してしまうということにょ。
これは下位bitを切り捨てて使用すれば概ね克服できる問題だけどXbox360ソフトの
「カルドセプト サーガ」ではサイコロの目が偶数と奇数が必ず交互に出てしまっており
これは線形合同法の問題を考慮せずに使っているためと推測されているにょ。
また線形合同法は与える数字によって周期が変わるけど最大周期の数字を与えても1次元的に
考えると偏りが出て無くても2次元的に考えると偏りが非常に出てしまうにょ。
例えばX座標、Y座標を乱数で求めてそれが画面上にプロットしていくと線形合同法では
画面を隙間なく埋め尽くすことはできず単に直線が描かれるだけになるにょ。
そのため私はカウンタと併用することでこの問題を克服しているにょ。(1024x1024までは
隙間無く埋め尽くすことができるため少なくとも2次元までは問題ないと思う)

上記の線形合同法を改良した疑似乱数は最短ではここまで短くできるにょ。
 Y=(Y+0.1)%1.1X=(X*117+Y)%1
 http://ochameclub.web.fc2.com/petitcom/tips/routine.htm#rand

0〜1の乱数だけどこうすることで下位bitは切り捨てられるため線形合同法のもう1つの弱点を
緩和できているにょ。
0〜5のサイコロを作る場合には(X*4096)%6としてしまうと弱点がまた出てきてしまうため
0 OR X*6として欲しい値の分だけ掛けて整数化すると良いにょ。
疑似乱数には様々なアルゴリズムがあり、一般的なアルゴリズムだと最強なのはメルセンヌ・
ツイスタだけどこれはプチコンで使うには処理が重いためあまり使うことはないのではないか
と思われるにょ。
線形合同法以外ではXorshiftなどが簡単でバラツキのある乱数を発生させることができる
けどプチコンにはシフト命令が無かったり扱える数が524287までだったりするという問題が
あるためXorshiftの簡便性はあまり活かすことはできないにょ。(524287までというのは
線形合同法でも周期を短くするため問題になるけど上記の私のルーチンでは改善によって
周期の短さを克服している)

計算によって得られる乱数というのはちゃんとばらついて発生させるものが良い乱数である
ため例えば0〜100の値が欲しい場合には0だろうと100だろうと大量に発生すれば概ね同じ
確率で発生するにょ。
これがネームバトラーゲームを作ったり、ウィザードリィのようにキャラの初期値がある程度
乱数で決まるゲームの場合だと能力が高いキャラも低いキャラも同じように出てしまうにょ。
平均近くのキャラが一番多くなり極端に高いものや低いものが出ないようにするためには
正規乱数を使うのがベターにょ。
正規乱数を発生させる命令はないため自前で計算して作ることになるけど正確な正規乱数に
拘る必要はなく中間付近の値が出やすくしたいというだけならば複数のサイコロを同時に
振ってやればいいにょ。
つまり、0〜10の乱数を10回発生させてその合計値を求めれば中央付近の値が出やすい0〜100の
乱数を作ることができるにょ。
ただし、回数を重ねれば重ねるほど中央付近に集中しすぎるためある程度中央付近の値が多く
なって極端に高いものや低いものが出にくくするためには私が昔ポケコン用に作った
ADAMを使用すると良いにょ。

 ネームバトル系ゲームの最終兵器!? ADAMの謎に迫る!!
 http://ochameclub.web.fc2.com/E500/TECH/ADAM.HTM

これは上記のサイコロを複数振るのに加えて均等に出るエリアを設定しているだけという
極めて単純なアルゴリズムにょ。
これによって一定の範囲内ばバラツキ良く発生するけど高い値や低い値が出にくくすると
いうことが可能になっているにょ。
これは私のポケコン(PC-E500)用ゲームの「ゼロヨンバトル」で用いられているにょ。

 ゼロヨンバトル
 http://ochameclub.web.fc2.com/CLUB/zero4_battle/index.htm

このゲームはネームバトラー方式で名前によって車の各ギアにおける最高速度と加速度が
決まりそれによって対戦型のゼロヨンレースを行うというものだけどADAMによって逆算が
困難で性能が良いものが非常にレアになっているにょ。


このように「乱数」と一口でいっても様々なものがあり、そのゲームによってどのような
乱数をどのように求めれば良いのかが変わってくるにょ。
ちゃんと適したものにすればゲームはより面白いものに変わるけどそうでない場合は
乱数が悪いためゲームがつまらないものになるという可能性があるため注意が必要にょ。




掲示板管理者へ連絡 無料レンタル掲示板