インディーズゲームの例でのアーケードレベルの生成





この記事では、数日前に私が開発した最も単純なランナーゲームのレベル生成アルゴリズムについてお話したいと思います。 gamedevのテーマと、ゲームレベル、ダンジョン、トラップ、または地形をランダムに生成するアルゴリズムに興味がある場合は、catにようこそ。



ゲームについて



まず、何が何であるかを明確にするために、ゲーム自体について少しお話します。 このゲームは、小さなピクセルの男が左から右に走る筋金入りのランナーです。この小さな男が空中で跳ねたり、計画したり、スパイクから多くのトラップを避けたりするために、ボタンを1つ押す(またはモバイルバージョンの場合は画面をタップする)必要があります。 ゲームの主な仕組みは、トラップの前でタイムリーにバウンドし、小さなハンドルで計画時間を正しく計算することです(はい、アニメーションによると、小さな男が手を振ると、これにより落下が遅くなります)。



第一世代バージョン



ゲームはハッカソン形式で開発されたため、ゲームの最初のバージョンでは、 最も単純な最小動作アルゴリズムが作成されました。これは、プレイヤーが移動すると、前のスパイクからランダムな距離で3種類のスパイクの1つを作成しました。



スパイクの種類:





手裏剣と呼ばれるスパイクは、床と天井の間のランダムな高さに作成されました。 「床の上のスパイク」と「天井の上のスパイク」はその名前に対応し、床と天井に配置されていたため、手裏剣とは異なり、高さは安定していました。



最初のバージョンでは、世代は非常に優れていて面白かったことが判明しましたが、残念ながら、2つの大きなマイナス面がありました。



上記の問題に基づいて、「通過できない」場所の作成を許可せず、プレイヤーを一定の緊張状態に保ち、これがレベルの各セクションで異質で一意になる、優れた十分に開発された生成アルゴリズムを作成することにしました。



最終生成アルゴリズム



基本的な概念




ゾーン


ゾーンにはいくつかのタイプがありますが、簡単にするためにコードを示します。

enum Zones //  { Random_spikes_on_floor, //      Random_spikes_on_floor_and_solid_ceiling, //          Solid_spikes_on_floor, //     Shuriken_walls, //    ( ) Random //   }
      
      





ゲームの開始時に、ゾーンは上記の5つのタイプからランダムに選択されます。 ゾーンの長さには制限があり、プレーヤーが完全に実行すると、ゲームの開始時と同じ方法で次のゾーンがランダムに選択されます。 新しいゾーンを作成すると、新しいランダムな長さが設定されます(主に40〜100メートル)。 また、ゾーンを変更すると、ゾーン間に小さな安全ギャップが作成され、ゾーンが互いに「干渉」しないようにします。







ゾーンの種類ごとに出現する可能性があります。たとえば、新しいゾーンは、30%の確率で「手裏剣の壁」を持つゾーンになります。



ゾーンのタイプは、このエリアで生成されるトラップを決定します。 したがって、各ゾーンには、障害物を克服する独自の特性と方法があり、したがって、(通過できないエリアを作成しないように)生成のための特別なルールがあります。



前述のように、ゲームには0から100まで時間とともに増加するComplexityパラメーターがあり、このパラメーターは各ゾーンでの生成中にトラップの数または場所に直接影響します。 しかし、抽象的なことから具体的な例に移りましょう。



「床にランダムなスパイク」があるゾーン


このゾーンでは、アルゴリズムは、おおよそランダムなシーケンスで、主に床のスパイクからトラップを作成することに基づいています。



最小限の複雑さでの生成の例(難易度= 0)





最大の複雑さで生成する例(難易度= 100)





最初に、ゾーン内での生成の仕組みについて少し説明します。 ゾーンに入ると、可能な(ランダムに選択された)トラップの1つが作成され、選択されたトラップに応じて、新しい遅延が設定されます(このゾーンに新しいトラップが作成されるメートル数)。 プレイヤーがdelayを通過するとすぐに、新しいトラップが作成され、再びランダムに選択されます。 当然、各ゾーンの各タイプのトラップには、発生する可能性があります。



私たちのゾーンの主な原則:床にスパイクを作成するかしないか(ランダム性による)。 このゾーンは、常に同じ高さにある床のスパイクで主に構成されているため、アルゴリズムと問題領域の検出に関して最もシンプルです。 したがって、私たちは、あなたが置くことができるスタッドの数と、定期的なテストではできない数を決定することができます。







上記の画像は、ジャンプの最大高さとホバー時間で、プレイヤーが互いに接近するスパイクを5つまでしか克服できないことを示しています。 したがって、アルゴリズムには条件が必要です。生成されたトラップの前に少なくとも5つのトラップがある場合は、必ず空のスペースを残してください(トラップを生成しないでください)。 これを行うには、現在のトラップの前にどのトラップがあったかを覚えておく必要があります(10を超える番号を覚える必要がないため、サイズ10の列挙型の通常の配列を使用しました)。



このゾーンでは、後続の各トラップ(またはトラップがない場合)が、トラップの幅に等しい遅延で生成されます。 したがって、トラップが連続的に作成される場合、5つの行が連続するまでトラップ間に空きスペースはありません(「5つのスパイクが連続していない」という条件が機能します)。



しかし、生成におけるランダム性の役割を忘れてはなりません。 新しいトラップはそれぞれ作成することも、作成しないこともできます。 ここで、最後に、 複雑さがその役割を果たします。 難易度が高いほど、床が急上昇する可能性が高くなります。

 random = UnityEngine.Random.Range(0f, 100f); //    0  100 if (random < 40f + (Difficulty.Difficulty_of_game() * 0.4f)) // Difficulty.Difficulty_of_game()    { // ... ... } else { // ... ... }
      
      





素晴らしい、床にスパイクを生成するための良いアルゴリズムであることが判明したが、何かが欠けている。 天井に珍しいスパイクを追加して多様性を追加する必要がありますが、トラップを克服する基本的なロジックを破ることはできません。 たとえば、中間の5つのスパイクの真上にある天井にスパイクを加えた場合、プレーヤーは5つのスパイクを連続して克服する必要があるため、ジャンプすることができません。 したがって、天井のスパイクは、このような「フロア」トラップの大きなグループの端に沿ったどこかにあるはずです。



アルゴリズムに、「天井のスパイク」の作成を、70%〜100%の確率で(複雑さに応じて)追加します。

 if ((Last_traps[1] == Traps.None) || (Last_traps[2] == Traps.None) || (Last_traps[3] == Traps.None)) { // ...      ... } else { // ...  ... }
      
      





つまり、最後から2番目、前から2番目、または前から2番目のトラップが存在しない場合(地面にスパイクはありません)、天井にスパイクを作成できますが、そうでない場合はできません。



OK、1つのアルゴリズムの準備ができています。 残りの4つを確認する必要があります!



「床にランダムなスパイクがあり、天井に固体スパイクがある」ゾーン


このゾーンは、本質的に「床にランダムなスパイクがあるゾーン」の洗練されたバージョンです。



違い:



難易度= 0(最小)





難易度= 50(中)





難易度= 100(最大)





前のゾーンとアルゴリズムに大きな違いはありません。ただし、天井にはランダムなスパイクは生成されませんが、「シュリケン」が発生します。また、さまざまな難易度では、「手裏剣」が表示される可能性が異なります。 「手裏剣」は、床にスパイクのない場所の上に30%から60%の確率で(複雑さに応じて直線的に)表示されます(スパイクの上に作成すると、通過できない場所が発生する可能性が非常に高くなります)。



さらに、「シュリケン」は複雑さに応じて異なる高さに表示される場合があります。 スクリーンショットをよく見ると、「手裏剣」が低いほど、ジャンプ時に彼を傷つけないことが難しくなることが明らかになります。 これに基づいて、高さの複雑さへの依存を作成しました。



難易度[0-50) -「手裏剣」の高さを作成します。

難易度[50-80) -50%高い作成; 50%の高さで作成

難易度[80-100] -中程度の高さで作成します。



「床にしっかりしたスパイク」があるゾーン


このゾーンは、「床にランダムなスパイクがある」最初のゾーンに非常に似ていますが、次の2つの違いがあります。



難易度= 0(最小)





難易度= 50(中)





難易度= 100(最大)





このゾーンの主な強調点は、プレーヤーが常に最大値、つまり5つのスパイクにジャンプする必要があるという事実に基づいています。 ただし、ゲームの複雑さはさまざまであるため 、3つのゾーンバリエーションが導入されました(スクリーンショットは上記を参照)。



難易度[0-25) -イージーゾーン、3つのスパイクが連続。

難易度[25-75) -中間ゾーン、4つのスパイク。

難易度[75-100] -困難なゾーン、5つのスパイク。



予想外の非常に難しい場所はないため、このゾーンはおそらく最も単純です。ゾーン全体で同じ状況が繰り返されます(行のN個のスパイク、スペース、行のN個のスパイク、スペースなど)。 難易度75では問題が始まりますが、時間を少しでも間違って計算して早めにジャンプするとスパイクが発生するためです。



ここの天井のスパイクは、最初のゾーンと同じ原理に従って生成されますが、最初のゾーンとは異なり、スパイクなしでは小さすぎる島のためにそれらに走ることは不可能であるため、恐ろしく多様性を除いてここでは役に立ちません。



手裏剣の壁エリア


ここでは、おそらく最も通過が難しいゾーンになります。 その主な原理は、サーカスで「火の輪」を使うトリックに似ています。スパイクを打つことなくスパイク間を飛行する必要があります。 さまざまな問題のスクリーンショットを見てみましょう。



難易度= 0(最小)





難易度= 50(中)





難易度= 100(最大)





前のゾーンと同様に、複雑さには3つのバリエーションがあります。



難易度[0-40) -イージーゾーン、幅が主に2つの「シュリケン」の穴。

難易度[40-90) -中央のゾーンは「簡単」なゾーンよりもはるかに複雑です。基本的に幅が1の「手裏剣」の穴があるため、それを克服するためのさまざまなオプションがあります。

難易度[90-100] -難易度ゾーンでは、通過オプションが常に同じであるため、穴の幅は常に「手裏剣」1つで、「中」よりも少し複雑です。



このような壁を生成する基本原理:各壁の間には常に一定の距離があり(ランダム性とは無関係)、現在の複雑さによって異なります 。 壁間の距離は常に8.5 mから7.5 m( 複雑度が高く、距離が小さい)であり、ゾーンのあるサブタイプから別のサブタイプ(たとえば、イージーゾーンからミドルゾーン)に移動すると、壁間の距離は8.5 mから7.5に再び減少します。 m。したがって、ゾーン内の複雑さ 39.99では「明るい壁」がありますが、それらの間の距離は7.5メートルであり 40-「中壁」の複雑さではありますが、距離は8.5メートルです。



壁のさまざまな組み合わせで距離がテストされ、スパイクを打たずに快適に着陸して再びジャンプできる最小距離は7.5メートルであることがわかりました。 8.5メートルから徐々に減少したため、ゾーンのサブタイプ内に少なくともある程度の合併症がありました。



次に、ゾーン内で次にどの壁が決定されるかについて説明します。 すべてが非常に単純です。複雑さごとに、「shurikens」の特定の壁のセットがあり、このセットからランダムな壁が選択されるたびに:







ランダム生成ゾーン


以前の4つのゾーンを作成したとき、すべてが正常でしたが、何かが欠けていました。 私の最初のバージョン(完全なランダム)には欠陥がありましたが、それでも独自の魅力がありました。 したがって、私は別のゾーンを作成することにしました。これは本質的に、最初のバージョンのコピーですが、以前の欠点(通過できない退屈な場所)はありません。







古い世代の改良バージョンを作成するために、既存のトラップからゾーンを作成し、特定のルールとチャンスを設定しました。



トラップ間の距離は、多くのテスト(最も重大なケースを含む)によって取得されましたが、リリース後、「手裏剣」の壁の作成で1つの横棒が見つかりました。 。



おわりに



その結果、ゲームでトラップを生成するためのかなり完全で重要なアルゴリズムを取得しました。



読んでくれてありがとう! 質問がある場合、またはエラーを見つけた場合は、コメントに必ず記入してください。 ここでゲームを無料でプレイできます-niceplay-games.com/games/hardmode-on.html



All Articles