ポルゼンヌのゲーム製作 ホーム » スポンサー広告 » 考察 »ウディタでのシードの仕様について

スポンサーサイト  

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

category: スポンサー広告

tb: --   コメント: --

ウディタでのシードの仕様について  


製作技術的な話です

次回作は戦闘で技能が手に入り、それにランダムエンチャントとしてたまに特殊効果が付いて来るというシステムです。
技能が手に入る確率が低すぎるとランダムエンチャの意味が薄れるので、戦闘での成績が高ければそこそこの確率で技能が手に入るようにしています。

ですが、実際に戦闘に使用する技能は3つだけなので、かなりの数が余ってしまいます。
そこで、いくつかの要らない技能をランダムで別の技能に変換するガチャのようなものを作ることにしました。

しかしながら、ウディタはプレイヤーがセーブデータを容易に保存しておいたり複製したりできます。なのて、普通にガチャシステムを作ると目当ての物が手に入るまでリセットし続けるゲームになってしまいます。
(正確には、セーブする→ガチャを引く→リセット→乱数を使用するイベント(戦闘など)を実行する→セーブする→以降繰り返しという手順)

これを防ぐためにシードを利用します。シードというのはシステム変数の一つで、ウディタでの擬似乱数はこの値を元に導かれています。
私自身詳しくはなかったので、これを機に理解を深めようと思い、色々とウディタ上で試してみました。

ウディタにおけるシードでは次の仕様があるようです。



①同じシード値の状態で同じ乱数計算式を使用すると、必ず同じ結果を導き出す

t1.png

例えばシード値10000のときに乱数0~10の計算結果が10だったのなら、どのタイミングのどのセーブデータでもシード値に10000を入れて0~10を計算すれば必ず10になります。

②一度でも乱数を使用すると、シードには別の値が代入される

t2.png

この仕様のおかげで、例えば0~9の計算を連続で10回繰り返しても見かけ上はランダムに数値が出てくるというわけです。もしシード値がそのままだと10回とも同じ数値が出てきます。
逆に言えば乱数を使用しない限りシードは変化しないので、例えばウディタのデフォルト状態ではロード後の乱数が一定になり、何度ロードし直しても同じ場所で敵とエンカウントして、同じ敵からクリティカルを食らって死ぬということが起きます。
これを防ぐためには乱数を無駄遣いするという方法があります。例えば並列実行イベントで1フレーム毎に乱数を使用すれば、全くタイミングで全く同じ入力をしない限り結果は別になります。しかしこの場合プレイヤーの操作が入る余地のない処理は恒常的になってしまいます。
常に変化する値を元に導かれる計算結果をシードに直接入れる方が無難な方法かもしれません。具体的には現在の秒数などが一般的です。この値を入れるタイミングはロードの直後だけで大丈夫ですが、結局ロード直後かの判定に並列処理が必要です。

③次に代入されるシード値の算出には現在のシード値が用いられる

t3.png

つまり、最初のシード値を決めれば、以降のシード値の並びは固定ということです。
例えばシード値10000のときに乱数を使用してシード値168070000になったとしたら、同様のことをどのセーブデータで何度やっても同じになるということです。当然、次にそのシード値168070000により発生する乱数も固定であり、その次に代入されるシード値も固定になります。
そのため、イベント開始時のシード値とキー入力の内容とタイミングさえ保存しておけば、イベント内で乱数を使用していても全く同じリプレイを再現することができます。

④ゲーム初回起動時、シードにはランダムに値が放り込まれる (計算式は不明)

そのため、同じゲームを同じ手順で最初からプレイしても結果は変わってきます



これらのことを踏まえると、ガチャに使う専用のシード値をゲーム起動時に保存して、更に今までガチャを引いた回数も保存しておいて
ガチャを始める前に現在のシード値に専用のシード値を代入し、今まで引いた回数分乱数を無駄遣いした後にガチャとして乱数を使用
すれば
ガチャ直前でリセットしても、一度戦闘を挟んでも、全く変わらない結果を生み出すことができることが分かります。

具体的にはこんな処理になりました。

ガチャ

結果的にはゲーム開始時に4,6,3,2,8…のようにガチャの結果を無限に作り出しておいて、それをガチャを引くたびに読み込んだのと変わらない処理をしていることになりますね。

注意しなくてはならないのは、ガチャを引く前にシード値を代入してから実際にガチャの結果となる乱数を計算するまでの間に、他の用途で乱数を発生させてはいけないということです。
並列実行イベントで乱数を使用していた場合やガチャの演出のエフェクトなどに乱数を使用する場合は、その間に入り込むことのないようにしなければなりません。
ガチャを引く処理を始めたら先に計算を済ませておき、それから演出やウェイトを入れるようにした方が良さそうです。

また、これらの方法を取れるシステムは限られています。
例えばギャンブルなどのシステムで使おうとすると、確かに結果は変わりませんが、プレイヤーがその結果を元に選択を変えることができてしまうので結局リセットゲーになってしまいます。
次に相手が何のカードを出してくるか既知ですし、負けが確定しているなら賭け金を下げればいい話です。
あくまで引く、引かないの選択肢しか存在しない、ガチャやくじ引き向きの処理と言えます。
応用すれば、例えば装備品取得時点で装備品情報としてシード値を保存しておくことで、50%の確率で効果が上昇する強化書を1回目、2回目…と使った結果がどうなるかを固定にできたりもすると思います。


ともかくこれでリセットゲーにならないガチャができましたが、そこまで重要なものにしないつもりです。
余った技能の売る以外の使い道になればいいと考えています。
あまりにこれで良い技能が出てきすぎると、最も弱い雑魚相手にとにかく技能を集めてガチャを回し続けるゲームになりそうだからです。
特殊効果目当てだとしても、欲しい技能を落とす敵相手に戦う方が効率が良いようになるようにしたいと考えています。

といってもまだシステムもマップもろくに出来ていませんし、ストーリーも殆ど決まっていないので、細かいバランス調整はまだまだ先の話です。
まず戦闘の重さが現状だとどうにもならないと感じたので、処理そのものを根底から大幅に改変しようと思っています。
見た目的に何の変化も生まれないのでモチベーションとしては辛いものがありますが、こういうのは早い段階からやっておいたほうが被害が少ないので、なんとか頑張っていきたいと思います。


考えてみれば、わざわざ回数分ループしなくても乱数使用後に現在のシード値を保存しておいて、次はそれを使用すればいいだけの話でした。
処理としては殆ど同じことをしていることになりますが、回数が増えても処理数が増さないのでこちらの方がよさそうです。

category: 考察

tb: --   コメント: 0

コメント

コメントの投稿

Secret

プロフィール

最新記事

最新コメント

カテゴリ

▲ Pagetop

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。