プレイヤーをいらいらさせる:乱数の正しい使用

画像






RPGファンとチャットをした場合、ランダム化された結果と戦利品、およびそれらがどれほど厄介であるかについての苦情がすぐに聞こえます。 多くのゲーマーが不快感を表明しており、一部の開発者は革新的なソリューションを思いついていますが、ほとんどの場合、依然として私たちは猛烈な忍耐力テストを受けなければなりません。



しかし、より良い方法があります。 乱数を使用して別の方法で乱数を生成すると、プレイヤーを混乱させることなく、「理想的な」レベルの難易度を作成するエキサイティングなゲームプレイを作成できます。 しかし、これに入る前に、乱数ジェネレーター(またはRNG)の基本を見てみましょう。



乱数ジェネレーターとその応用



乱数はどこにでもあり、ソフトウェアにバリエーションを追加するために使用されます。 一般的な場合、RNGは通常、混chaとしたイベントのモデル化、不整合の実証、または人工的なリミッターとして使用されます。



ほとんどの場合、あなたは毎日、乱数またはそのアクションの結果とやり取りします。 それらは、科学実験、ビデオゲーム、アニメーション、アート、およびほとんどすべてのコンピューターアプリケーションで使用されています。 たとえば、RNGはほとんどの場合、携帯電話の単純なアニメーションで実装されます。



RNGについて少し説明したので、RNGの実装を見て、それらを使用してゲームを改善する方法を見つけましょう。



標準乱数ジェネレーター



ほぼすべてのプログラミング言語には、他の機能の中でも、標準のRNGがあります。 彼の仕事は、2つの数値の範囲でランダムな値を返すことです。 さまざまなシステムでは、標準のRNGはさまざまな方法で実装できますが、一般的なケースでは同じ効果があります。間隔から乱数を返します。各値は同じ確率で選択できます。



ゲームでは、サイコロをシミュレートするためにジェネレーターがよく使用されます。 理想的には、各結果が同じ回数発生する状況でのみ使用する必要があります。



希少性やさまざまな程度のランダム化を試してみたい場合は、次の方法がより適しています。



重み付き乱数と希少性スロット



このタイプのRNGは、希少アイテムシステムを備えたRPGの基盤です。 特に、ランダム化された結果が必要な場合に使用されますが、一部の値は他の値よりも低い頻度でドロップアウトする必要があります。 確率を研究するときの例は、多くの場合ボールの袋です。 重み付きRNGを使用すると、バッグに3つの青いボールと1つの赤いボールを含めることができます。 必要なボールは1つだけなので、赤または青のいずれかを取得しますが、より高い確率で青になります。



なぜ重み付けランダム化が重要なのでしょうか? ゲーム内のSimCityイベントを例としてみましょう。 各イベントが重み付けのない方法で選択された場合、各イベントが実行される確率は統計的に同じになります。 つまり、同じ確率で、新しいカジノを開くように提案されたり、地震が発生したりします。 重みを追加することで、これらのイベントを比例した確率で発生させ、優れたゲームプレイを提供できます。



種類と用途



同一アイテムのグループ化



コンピュータサイエンスに関する多くの書籍では、この方法は「バッグ」と呼ばれています。 名前はそれ自身を物語っています-クラスまたはオブジェクトは、文字通りの意味でバッグの視覚的表現を作成するために使用されます。



実際、次のように機能します。オブジェクトを配置できるコンテナ、「バッグ」にオブジェクトを配置する機能、「バッグ」からアイテムをランダムに選択する機能があります。 ボールを使用した例に戻ると、バッグには青、青、青、赤のボールが含まれていると言えます。



このランダム化方法を使用すると、各プレイヤーのゲームプレイを平均するために、結果の発生頻度をおおよそ設定できます。 結果を「非常に悪い」から「非常に良い」までスケールに単純化すると、プレイヤーが不必要な結果の不要なシーケンスを取得できる場合と比較して、はるかに快適なシステムが得られます(たとえば、「非常に悪い」結果が連続して20回)。



ただし、統計的に一連の質の悪い結果を取得することはまだ可能ですが、これは単にその可能性が低下したということです。 不要な結果の量を減らすためにもう少し進む方法を見ていきます。



バッグクラスの擬似コードがどのように見えるかの簡単な例を次に示します。



Class Bag { //    ,    Array itemsInBag; //      Constructor (Array startingItems) { itemsInBag = startingItems; } //   ,   (      ) Function addItem (Object item) { itemsInBag.push(item); } //       random,     Function getRandomItem () { return(itemsInBag[random(0,itemsInBag.length-1)]); } }
      
      





希少性スロットの実装



レアリティスロットは、落下するオブジェクトの頻度を指定するための標準化方法です(通常、ゲームデザインとプレイヤーの報酬を作成するプロセスを簡素化するために使用されます)。



ゲーム内の個々のアイテムの頻度を設定する代わりに、それに対応するレアリティを作成します。たとえば、レアリティ「標準」は特定の結果の確率20〜X、レアリティレベル「レア」-確率1〜Xを表します。



この方法は、バッグ自体の機能を大きく変えることはありませんが、開発者側の効率を高めるために使用でき、指数関数的に多数のアイテムに統計的確率をすばやく割り当てることができます。



さらに、レアリティをスロットに分割することは、プレイヤーの認識を変えるのに役立ちます。 プレイヤーが興味を失うことがないように、イベントをどのくらいの頻度で発生させるべきかを理解するために、数字をいじり回す必要なく迅速にできます。



以下に、レアリティスロットをバッグに追加する方法の簡単な例を示します。



 Class Bag { //    ,    Array itemsInBag; //   ,   Function addItem (Object item) { //     Int timesToAdd; //    //(       , //  ) Switch(item.rarity) { Case 'common': timesToAdd = 5; Case 'uncommon': timesToAdd = 3; Case 'rare': timesToAdd = 1; } //         While (timesToAdd >0) { itemsInBag.push(item); timesToAdd--; } } }
      
      





可変周波数の乱数



ゲームでの事故に対処する最も一般的な方法のいくつかについて話しましたので、より複雑なものに移りましょう。 可変周波数を使用する概念は、上記の例のバッグと同様に始まります。特定の数の結果があり、それらを発生させる頻度を知っています。 実装の違いは、結果が発生したときに結果の確率を変更することです。



なぜこれが必要なのですか? たとえば、ピックアップゲームを考えてみましょう。 取得したアイテムに10個の結果があり、9個が「普通」、1個が「まれ」である場合、確率は非常に単純です。プレーヤーは通常のアイテムを90%の確率で受け取り、まれなアイテムは10%の確率で受け取ります。 この問題は、バッグから数回引っ張る場合に発生します。



一連の一般的な結果が得られる可能性を見てみましょう。





つまり、9:1の初期比率は理想的なように見えましたが、実際には、平均結果にのみ対応しています。つまり、10人のプレイヤーのうち1人がレアアイテムを獲得するために2倍を費やします。 さらに、4%のプレイヤーは3倍の時間をかけてレアアイテムを獲得し、1.5%の敗者は4倍の時間をかけます。



可変周波数がこの問題をどのように解決するか



解決策は、オブジェクトにランダム間隔を実装することです。 これを行うには、各オブジェクトの最大および最小のレアリティを設定します(このメソッドを前の例に接続する場合は、レアリティスロット)。 たとえば、通常のアイテムに最低1、最高9の希少度を与えましょう。まれなアイテムの最低と最高は1です。



さて、上記のシナリオによれば、10個のアイテムがあり、そのうちの9個は普通のコピーであり、1個はまれです。 最初のプルでは、​​90%の確率で通常のアイテムを入手できます。 可変周波数では、通常のオブジェクトをストレッチした後、そのレアリティを1減らします。



この場合、次のストレッチでは、合計9つのオブジェクトがあり、そのうちの8つが通常のものであるため、通常の89%のストレッチの確率が得られます。 通常のアイテムでの結果ごとに、このアイテムのランダム性が低下し、バッグに2つのアイテム(通常のアイテムとレアのアイテム)が残るまで、レアなアイテムを描画する可能性が高くなります。



したがって、35%の確率で10個の通常のアイテムを連続して引き出すのではなく、5%の確率しかありません。 連続して20個の通常のオブジェクトを引っ張るなどの境界結果の確率は0.5%に低下し、その後さらに低下します。 これは、プレイヤーに永続的な結果をもたらし、プレイヤーが常に悪い結果をもたらす境界ケースから私たちを守ります。



可変周波数クラスの作成



最も単純な可変周波数の実装は、バッグからアイテムを取得するだけでなく、バ​​ッグからアイテムを取得することです。



 Class Bag { //    ,    Array itemsInBag; //      Constructor (Array startingItems) { itemsInBag = startingItems; } //   ,   (      ) Function addItem (Object item) { itemsInBag.push(item); } Function getRandomItem () { //pick a random item from the bag Var currentItem = itemsInBag[random(0,itemsInBag.length-1)]; //    ,     If (instancesOf (currentItem, itemsInBag) > currentItem.minimumRarity) { itemsInBag.remove(currentItem); } return(currentItem); } }
      
      





このような単純なバージョンにはいくつかの問題がありますが(たとえば、バッグが徐々に正規分布状態に変化するなど)、ランダム化の結果を安定させることができる小さな変更が表示されます。



アイデア開発



可変周波数の基本的な考え方について説明しましたが、独自の実装では、さらに多くの側面を考慮する必要があります。





退屈しない乱数



多くのゲームは依然として標準の乱数生成を使用して複雑さを作り出しています。 この場合、半分のプレイヤーが予想される結果からいずれかの方向に逸脱するシステムが作成されます。 これを無視すると、失敗が繰り返される結果が多すぎる境界ケースが発生する可能性があります。



結果の散布の間隔を制限することにより、より全体的なゲームプレイを提供し、より多くのプレイヤーがそれを楽しむことができます。



まとめると



乱数生成は、優れたゲームデザインの柱の1つです。 ゲームプレイを改善するには、統計を注意深く確認し、最適なタイプの生成を実装してください。



All Articles