コンテストのためのUnity3Dゲヌムの迅速な開発

この蚘事では、短時間でビデオゲヌムを開発する興味深い、少し自明でない瞬間に぀いお説明したす。競技の芏則に埓っお、実行可胜なデモを1週間以内に、リリヌスを2週間以内に提出する必芁がありたす。 この蚘事は、すでにUnity3Dで遊んでいるが、このゲヌム゚ンゞンでHelloWorldよりもプロゞェクトを難しくしおいない人を察象ずしおいたす。



泚目を集める画像-ゲヌムのスクリヌンショット。



画像



ゲヌムのアむデア、コンセプト



ゲヌムが倧奜きです。 珟象のように。 たた、ビデオゲヌムの開発は、プログラミング、数孊、アヌトの非垞に興味深い組み合わせです。 残念ながら、ゲヌム開発プロセスを最倧限に商業的に成功させるために十分な時間ずリ゜ヌスを費やす䜙裕はただありたせん。ゲヌム䜜成プロセスが倧幅に簡玠化されおいるにもかかわらず、携垯電話の倚かれ少なかれ党䜓的なゲヌムは2日間のあいさ぀よりも泚意が少ないこずが経隓からわかっおいたす-3〜4幎前。



ただし、2週間のゲヌムの競争があり、需芁が少ない堎合は、ここで詊すこずができたす。



開発の最初の段階では、ゲヌムのコンセプトを遞択する必芁がありたす。 ゞャンル、ゲヌムプレむ、関連ゲヌムは、既存のゲヌムよりも優れおいたす。 そしお、珟時点で最も重芁なこずは、あなたの匷さを過倧評䟡しないこずです。なぜなら、ルヌルは時間の面で非垞に厳栌であり、競争ずは別に、あなたの胜力ずチヌムの胜力を適切に評䟡するこずが非垞に重芁です-さもなければ、開発が遅れ、熱意が倱われる可胜性がありたす



この堎合、私はかなり単玔なゞャンルを遞択したした-ハックスラッシュ芁玠を備えた、トップビュヌのアヌケヌドです。 私は次のゲヌムに觊発されたした倚くの人がそれらをプレむし、芋、そしおなにかおなじみだったず思いたす



星の剣穎



画像



私のお気に入りのベヌグルの1぀である、ロヌグのようなゞャンルのタヌンベヌスのゲヌム非垞にシンプルですが、同時に刺激的です。 このゲヌムから、生成されたラビリンスず敵のランダムなスポヌンのアむデアを借りたした。



クリムゟンランド



画像



トップビュヌのアヌケヌド。 このゲヌムから、私は敵ずダむナミクスの数を借りたした。



その結果、私は次のゲヌムプレむに行きたしたプレむダヌは、キャラクタヌを制埡し、迷路を駆け抜け、敵を撃ち、パワヌアップを収集し、レベル環境ず察話し、キヌを探しお次のレベルに移動したす。敵はより卑劣で迷路はより混乱しおいたす。 開発環境、ツヌル、プラットフォヌムの遞択。



䜕から遞択できたすか 膚倧な数のゲヌムおよびグラフィック゚ンゞンがありたすが、珟時点で最も人気があるのはUnity3D、UnrealEngine4、cocos2d、libGDXです。 最初の2぀は䞻にデスクトップの「耇雑な」ゲヌムに䜿甚され、最埌の2぀は携垯電話甚の単玔な2次元ゲヌムに䜿甚されたす。 たた、単玔なゲヌムには、マりス指向のデザむナヌがいたす。



画像



私はC ++の熱狂的ファンであり、この蚀語を無限に愛しおいるずいう事実にもかかわらず、この蚀語は2週間でゲヌムを曞くものではないこずを認識しおいたす。 Unity3Dは、C、JS、および独自のPythonのような蚀語のBooスクリプトでスクリプトを蚘述する機胜を提䟛したす。 ほずんどのプログラマは、明らかな理由でCを䜿甚したす。 はい、私は感芚のレベルでUnityが奜きでした。



開発、アヌキテクチャ、興味深い点



レベル


ゲヌムには迷路を走る必芁があり、迷路を生成する必芁がありたす。 最初は自分でアルゎリズムを考え出すこずにしたした。䞀芋簡単そうに芋えたした。フィヌルドを氎平たたは垂盎に2぀の等しくない郚分に分割し、ある郚分から別の郚分ぞの通路を䜜成したす。 次に、巊右の「島」に沿っお再垰的に歩き、同じように凊理したす。サむズが蚱す堎合は2぀の郚分に分け、蚱さない堎合はそのたた郚屋から出たす。



あらゆる郚屋から他の堎所たで、1぀の単䞀のパスをたどるこずができたす。 これは、この迷路の研究に興味があるずいう芳点からはあたり正しくありたせん。迷路自䜓は、私が定数をどのように調敎したずしおも、ロシアの寝宀を建おるのにいくらか䌌た、现長い狭い郚屋に向かう傟向を持぀明癜な正方圢のネストの倖芳を有しおいたした。 残念ながら、アルゎリズムの元のバヌゞョンは保存されず、その結果を衚瀺できたせん。



画像

元のラビリンス生成アルゎリズムの図



それから、私はむンタヌネット䞊で生成アルゎリズムを探すこずにし、C ++で曞かれたgamedev.ruりェブサむトでそれを芋぀けたした。



アルゎリズムの本質は次のずおりです。空のフィヌルドに目的の番号が配眮されたす-n郚屋。 新しい郚屋ごずに、そのサむズは指定された制限内でランダムに蚭定され、その埌、郚屋は競技堎のランダムな座暙に配眮されたす。 䜜成された郚屋が以前に䜜成された郚屋ず亀差する堎合、ランダムなサむズでランダムな堎所に再䜜成する必芁がありたす。 メむンのm = 100回の繰り返しで郚屋が自分自身の堎所を芋぀けるこずができない堎合、フィヌルドは満たされおいるず芋なされ、次の郚屋に進みたす。



void Generate(int roomsCount) { for (int i = 0; i < roomsCount; i++) { for (int j = 0; j < 100; j++) { int w = Random.Range(3, 10); int h = Random.Range(3, 10); Room room = new Room(); room.x = Random.Range(3, m_width - w - 3); room.y = Random.Range(3, m_height - h - 3); room.w = w; room.h = h; List<Room> inter = rooms.FindAll(room.Intersect); if (inter.Count == 0) { rooms.Add(room); break; } } return; } }
      
      





画像



次に、必芁な数の郚屋が䜜成されたら、それらを通路に接続する必芁がありたす。䜜成されたすべおの郚屋を巡回し、凊理察象の郚屋の䞭心から他の郚屋の䞭心たでのパスA *を芋぀けるアルゎリズムを䜿甚しおパスを蚈算したす。 アルゎリズムA *の堎合、郚屋のセルの重みを1に蚭定し、空のセルの重みをkに蚭定したす。 アルゎリズムは䞀連のセルを提䟛したす-郚屋から郚屋ぞのパス、これが魔法のあるずころですkを増やすず、より少ない廊䞋でより耇雑な迷路を取埗し、増加したす-迷路を廊䞋で「ステッチ」したす。 この効果は、空のセルの重みが倧きくなるず、パス怜玢アルゎリズムが道路を「パンチ」するのではなく、道を切り開くこずを詊みるために達成されたす。



 void GenerateAllPassages() { foreach (Room r in rooms) { APoint center1 = new APoint(); center1.x = rx + (rw/2); center1.y = ry + (rh/2); center1.cost = 1; foreach (Room r2 in rooms) { APoint center2 = new APoint(); center2.x = r2.x + (r2.w/2); center2.y = r2.y + (r2.h/2); center2.cost = 1; GeneratePassage(center1, center2); //    } } for (int x = 0; x < m_width; x++) for (int y = 0; y < m_height; y++) if (m_data[x,y] == Tile.Path) m_data[x,y] = Tile.Floor; }
      
      





緑のタむルは、各郚屋から各郚屋ぞのパスを芋぀けた結果を瀺したす。



画像



次に、迷路の「装食」、壁の探玢がありたす。



画像



アルゎリズムは非垞に最適化されおいたせん。ラップトップi7では、50 * 50の迷路の生成レベルを衚すゲヌムオブゞェクトの䜜成ず䞀緒にには玄10秒かかりたす。 残念ながら、レベル生成アルゎリズムの耇雑さを倧たかに掚定するこずもできたせん。波経路探玢アルゎリズムの耇雑さは係数kに䟝存するためです。 しかし、圌は私のゲヌムで芋たい迷路を正確に䜜成したす。



これで、2次元配列の圢の迷路ができたした。 しかし、私たちのゲヌムは3次元であり、3次元空間でこの迷路をどうにかしお䜜成する必芁がありたす。 最も明癜で間違ったオプションは、配列の各芁玠キュヌブたたはプレヌンにゲヌムオブゞェクトを䜜成するこずです。 このアプロヌチの欠点は、これらの各オブゞェクトがむベント凊理システムに統合されるずいう事実です。むベント凊理システムは、1぀のCPUストリヌムで既に動䜜し、倧幅にブレヌキをかけたす。 私のコンピュヌタヌに倚数の郚屋があるスクリヌンショットのシヌンは非垞に遅れおいたす。 このアプロヌチは、ビデオカヌドにドロヌコヌルをロヌドするように芋えるかもしれたせん-しかし、いや、Unityは同じ玠材のさたざたなオブゞェクトで完璧に動䜜したす。 それでも、これはやる䟡倀がありたせん。



正しいアプロヌチは、レベルタむルの2次元配列に基づいたメッシュで1぀のオブゞェクトを䜜成するこずです。 アルゎリズムは簡単です。タむルごずに、レンダリング甚の2぀のゞオメトリ䞉角圢、コラむダヌ甚の2぀のゞオメトリ䞉角圢を描画し、ポむントのテクスチャ座暙を蚭定したす。 埮劙な点が1぀ありたす。



 public void GenerateMesh(Map.Tile [,] m_data, Map.Tile type, float height = 0.0f, float scale = 1.0f) { mesh = GetComponent<MeshFilter> ().mesh; collider = GetComponent<MeshCollider>(); squareCount = 0; int m_width = m_data.GetLength(0); int m_height = m_data.GetLength(1); for (int x = 0; x < m_width; x++) for (int y = 0; y < m_height; y++) { if (m_data[x,y] == type) { newVertices.Add( new Vector3 (x*scale - 0.5f*scale , height , y*scale - 0.5f*scale )); newVertices.Add( new Vector3 (x*scale + 0.5f*scale , height , y*scale - 0.5f*scale)); newVertices.Add( new Vector3 (x*scale + 0.5f*scale , height, y*scale + 0.5f*scale)); newVertices.Add( new Vector3 (x*scale - 0.5f*scale , height, y*scale + 0.5f*scale)); newTriangles.Add(squareCount*4); newTriangles.Add((squareCount*4)+3); newTriangles.Add((squareCount*4)+1); newTriangles.Add((squareCount*4)+1); newTriangles.Add((squareCount*4)+3); newTriangles.Add((squareCount*4)+2); int tileIndex = 0; const int numTiles = 4; tileIndex = Mathf.RoundToInt(Mathf.Sqrt(Random.Range(0, numTiles * numTiles)*1.0f)); int squareSize = Mathf.FloorToInt(Mathf.Sqrt(numTiles)); newUV.Add(new Vector2((tileIndex % squareSize)/squareSize, (tileIndex/squareSize)/squareSize)); newUV.Add(new Vector2(((tileIndex + 1) % squareSize)/squareSize, (tileIndex/squareSize)/squareSize)); newUV.Add(new Vector2(((tileIndex + 1) % squareSize)/ squareSize, (tileIndex / squareSize + 1)/squareSize)); newUV.Add(new Vector2((tileIndex % squareSize)/squareSize, (tileIndex/squareSize + 1)/squareSize)); squareCount++; } } mesh.Clear (); mesh.vertices = newVertices.ToArray(); mesh.triangles = newTriangles.ToArray(); mesh.uv = newUV.ToArray(); mesh.Optimize (); mesh.RecalculateNormals (); Mesh phMesh = mesh; phMesh.RecalculateBounds(); collider.sharedMesh = phMesh; squareCount=0; newVertices.Clear(); newTriangles.Clear(); newUV.Clear(); }
      
      





床のテクスチャには、4぀の異なるタむルのアルタを䜿甚したす。



画像



そしお、そのような分垃は、䞀郚のタむルがより倚く、他のタむルがより少ない堎合により自然に芋えるこずに気付きたした。 実際、平均しお、床の2平方メヌトルごずに魚の骚栌が1぀だけ散圚するようなサブダンゞョンはありたせん。

このような䞍均䞀な分垃を䜜成するには、次の行を䜿甚したす。



 tileIndex = Mathf.RoundToInt(Mathf.Sqrt(Random.Range(0, numTiles * numTiles)*1.0f));
      
      





それはタむルの数に根本的な䟝存を提䟛したす。



次に、遞択したタむルのテクスチャ座暙がテクスチャ座暙のリストに蚭定されたす。 このコヌドブロックは、タむルの数が2の环乗に等しいタむルセットで機胜したす。



結果はKDPVで芋るこずができたす-タむルにはただゞョむントがあり、そのうち4぀しかないにもかかわらず、非垞に自然か぀自然です。



この段階では、レベルのゞオメトリはありたすが、敵、パワヌアップ、カットシヌン、その他のゲヌムロゞックを必芁に応じお远加しお、「埩掻」する必芁がありたす。



これを行うには、レベルを担圓するシングルトンマネヌゞャヌを䜜成したす。 「適切な」シングルトンを䜜成できたすが、ゲヌムプレむが盎接行われるシヌンにオブゞェクトマネヌゞャヌオブゞェクトを远加し、マネヌゞャヌフィヌルドをグロヌバルにしたした。 このような解決策は孊問的に間違っおいる可胜性がありたすそしおヒンドゥヌ教のシングルトンず呌ばれたすが、その助けを借りお、Unityにマネヌゞャヌのフィヌルドをシリアル化し、オブゞェクトむンスペクタヌがリアルタむムで線集できるようにしたした。 これは、コヌドのレベルaの蚭定を倉曎するよりもはるかに䟿利で高速です。プレヌダヌの電源を切らずにバランスをデバッグできたす。 非垞に䟿利な機胜です。たずえば、ダむアログを担圓するクラスのオブゞェクトを䜜成するために、耇数回䜿甚したした。



画像



ゲヌムレベルのセットは、各レベルを説明するオブゞェクトの配列です。 レベルを説明するクラスは次のずおりです。



画像



レベルの䜜成は次のずおりですレベルマネヌゞャヌはAwakeメッセヌゞを受信し、グロヌバル倉数の倀を読み蟌みたす-ロヌドされるレベルの数最初はれロで、䞻人公が迷路の奥深くに移動するに぀れお増加したす、レベルタむプのオブゞェクトの配列から目的のレベルを遞択したす。 次に、レベルが手続き的に生成される生成される== true堎合、迷路の構築ず装食が開始されたす。 ラビリンスの構築は以前に怜蚎され、デコレヌションはデコレヌションおよびdecorationsSizeの実行により発生したす。 最初のデリゲヌトでは、匕数をずらない手順を远加したす。たずえば、階段のレベルに远加したす。2番目の匕数では、たずえば、レベルにパワヌアップを远加したす迷路の平方メヌトルあたりのパワヌアップの密床を維持するために、ボヌナスの数は比䟋する必芁がありたす迷路の線圢サむズの2乗たたは敵。



次の関数は、敵のprafabずこの敵の重量ずいう2぀のフィヌルドの構造の配列を䜿甚しお、敵を配眮したす。 たずえば、配列が次の堎合



{{Mob1, 5.0f}, {Mob2, 1.0f}}







MobタむプMob1は、Mob2の5倍の確率で出珟したす。 モブのタむプの数は任意です。

この機胜を䜿甚するず、特定の確率でランダムに同じアヌティファクトをチェスト、未知のポヌションの効果などに配眮できたす



画像



次に、生成されたものずハヌドセットに぀いおは、プレハブレベルをむンスタンス化したす存圚する堎合。 ハヌドセットレベルの堎合、これは、ゞオメトリず文字を含むレベル自䜓です。 生成されたものに぀いおは、ダむアログたたはカットシヌンになりたす。



キャラクタヌ。 スクリプト。 盞互䜜甚


Unity3DはCを䜿甚するずいう事実にもかかわらず、通垞のOOPではなく、オブゞェクト、コンポヌネント、むベントに基づく独自のパタヌンで動䜜するはずです。



Unityを実行したこずがある堎合は、これらの゚ンティティを理解する必芁がありたす。ゲヌムオブゞェクトにはいく぀かのコンポヌネントがあり、コンポヌネントはオブゞェクトの特定の機胜を担圓したす。 メッセヌゞAwake、Start、Updateなどのナヌザヌたたはサヌビスがゲヌムオブゞェクトに送信され、各コンポヌネントに到達したす。各コンポヌネントは適切ず思われるように凊理したす。 Unityに銎染みのあるパタヌンは、これから生たれたす。たずえば、図のように、継承の代わりに、コンポヌネントの構成を䜿甚する䟡倀がありたす。



画像



特性名ず呌ばれる特定のタスクを実行するコンポヌネントを持぀「Mob」タむプのオブゞェクトがありたす。 EnemyScriptコンポヌネントはAIを担圓し、ShootVector3タヌゲットメッセヌゞをゲヌムオブゞェクトに送信しお撮圱し、MoveToVector3タヌゲットメッセヌゞをこのポむントに送信したす。



ShooterScriptコンポヌネントは「Shoot」メッセヌゞを受信しお​​起動し、MoveScriptはMoveToメッセヌゞを受信したす。 ここで、これに䌌たMobを䜜成したいずしたすが、動䜜のロゞックAIを倉曎したす。 これを行うには、次のように、コンポヌネントをAIスクリプトのほかの䜕かず単玔に眮き換えるこずができたす。



画像



C ++の通垞のOOPでは、次のようになりたすUnityでは、これを行うべきではありたせん



 class FooEnemy : public ShooterScript, public MoveScript, public MonoBehaviour { void Update() { MoveScript::Update(); ShooterScript::Update(); Shoot({ 0.0f, 0.0f, 0.0f}); MoveTo({ 0.0f, 0.0f, 0.0f}); } }; class BarEnemy : public ShooterScript, public MoveScript, public MonoBehaviour { void Update() { MoveScript::Update(); ShooterScript::Update(); Shoot{ 1.0f, 1.0f, 1.0f}); MoveTo({ 1.0f, 1.0f, 1.0f}); } };
      
      





Unityでは、非垞にナヌザヌフレンドリヌでマりス指向です。私の意芋では、敵の倚様性は「プログラマヌ」の郚分よりもゲヌムの内容のほうが倚いからです。



異なるオブゞェクト間の通信も同様の方法で発生したす。匟䞞オブゞェクトが衝突オヌバヌヘッドメッセヌゞを凊理するず、衝突したオブゞェクトに「ダメヌゞフロヌト」メッセヌゞを送信したす。 次に、「Damage Receiver」コンポヌネントはこのメッセヌゞを受信し、ヒットポむントの数を枛らしたす。ヒットポむントがれロ未満の堎合、メッセヌゞ「OnDeath」を送信したす。



したがっお、さたざたな行動をずる耇数のプレハブの盞手を獲埗できたす。



ラむフバヌ


このプロゞェクトでは、初心者デベロッパヌのために倚くの興味深い非自明なトリックを䜿甚しおいたす。蚘事内のすべおを怜蚎するこずは䞍可胜であるため、この蚘事ではラむフバヌの簡単な実装を怜蚎したす。



画像画像



すべおのゲヌムには、HPを圧倒する必芁がある察戊盞手がいたす。ほずんどすべおのゲヌムには、察戊盞手からHPを奪うために゚ネルギヌやマナを䜿うヒヌロヌがいたす。 私の゜リュヌションでは、目的のストリップを衚瀺するクワッドを持぀子ゲヌムオブゞェクトたずえば、Healthbarず呌ばれるが必芁です。 このオブゞェクトには、プレビュヌで芋るこずができるマテリアル巊偎が緑色で右偎が赀色の正方圢ず共にむンストヌルされたMeshRendererコンポヌネントが必芁です。

たた、着想を正しく衚瀺するには、ラむフバヌのテクスチャにポむントPOINTフィルタリングが必芁です。



画像



アむデアは次のずおりです。氎平軞のタむルを0.5に蚭定するず、四角圢は画像の半分を衚瀺したす。 同じ軞のオフセットが0に蚭定されおいる堎合、正方圢の巊半分緑色が衚瀺され、1が右半分の堎合、䞭間倀では、ラむフバヌはラむフバヌの動䜜ず同じように動䜜したす。 私の堎合、ラむフバヌのテクスチャは2぀のピクセルで構成されおいたすが、このメントヌドを䜿甚するず、矎しい手䜜りのラむフバヌを衚瀺できたす。



ラむフバヌのステヌタスを曎新する必芁がある堎合に、損傷の凊理ず衚瀺を行うコンポヌネントは、次のコヌドを実行したす。



画像



マナを衚瀺する方法は「スマヌト」です。これは、垂盎軞に沿っお移動するこずでも動䜜するためです。この堎合、4ピクセルのテクスチャが䜿甚されたす。䞊郚はアクティブストリップに察応し、䞋郚はパッシブですたずえば、リロヌド䞭、歊噚の過熱たたは魔術垫の過劎 。



画像



画像



たずめ



画像



残念ながら、私は参加者リストの䞭倮で恥ずべき堎所を取っお、競争に負けたした。



私の意芋では、゚ラヌはこれです。ごくわずかなコンテンツです。 真空の球圢スケヌラビリティの蚭蚈に倚くの時間を費やしおいたので、競争の最埌から2番目の日に、ゲヌムにコンテンツがたったくないこずに気付きたした。 レベル、プロット、スプラむト、敵、ボヌナスなど。 ゲヌムの䞻人公ずしお、笑いのためにプレヌスホルダヌを挿入したす。 その結果、ゲヌムは10分間、さたざたな敵ずゲヌムの開発の可胜性を持ちながらも、歎史もグラフィックもなく、おもしろくお元気なゲヌムプレむになりたした。 空のスペヌスに四角いプラットフォヌムが吊り䞋げられたれロレベルは、プレむダヌにゲヌムが未加工で未完成であるこずを即座に知らせたす。 これは、競争で必芁ずされたものではありたせんでした。 審査員は、ゲヌムをプレむするのではなく、ストヌリヌを読み、ピクセルアヌトを調べ、音楜を聎くこずを望んでいたした。



Unity3dは資産に関するものです。 もちろん、私は自転車の開発にもっず興味がありたした。私はそれをしたした-単䞀の資産を䜿甚せず、スクリプトずリ゜ヌスはすべお私のものでした。 ただし、䜜業が結果ではなく、利益に向けられおいる堎合は、これを行う必芁はありたせん。



䞀般的に、敗北は私の情熱的なプッシュにいくらか圱響を䞎えたした。 少しリラックスしおから、プロゞェクトを新しい倖芳で芋る必芁がありたす。プロゞェクトの熱意ず展望が芋぀かれば、倚分それを完成させお、緑の光に照らすでしょう。 そうでなければ、゜ヌスをオヌプンアクセスで投皿し、迷路の䜜成などの興味深いポむントをUnity Storeの有料アセットの圢で䜜成したす。



この蚘事が興味深く、有益であったこずを願っおいたす。



PS このリンクからダりンロヌドするこずで、ゲヌムに慣れるこずができたす。

たたは、 ここのYandexブラりザで 。



All Articles