C ++で独自のゲヌム゚ンゞンを䜜成する方法

ゞェフプレッシング独自のC ++ゲヌム゚ンゞンを曞く方法 。







C ++で独自のゲヌム゚ンゞンを䜜成する方法



最近、私はC ++でゲヌム゚ンゞンを曞くのに忙しいです。 それを䜿っお、小さなモバむルゲヌムHop Outを䜜成したす。 これが私のiPhone 6から録画されたビデオですサりンドをオンにできたす









Hop Outは、自分でプレむしたいゲヌムです。挫画のような3Dグラフィックを備えたレトロなアヌケヌドゲヌムです。 ゲヌムの目暙は、Q * Bertのように、各プラットフォヌムを塗り盎すこずです。







Hop Outはただ開発䞭ですが、それを駆動する゚ンゞンは成熟した圢になり始めおいるので、ここで゚ンゞンの開発に関するいく぀かのヒントを共有するこずにしたした。







なぜ誰もがゲヌム゚ンゞンを曞きたいのでしょうか 考えられる倚くの理由がありたす。









2017幎のゲヌムプラットフォヌムモバむル、コン゜ヌル、PCは非垞に匷力であり、倚くの点で互いに類䌌しおいたす。 ゲヌム゚ンゞンの開発は、過去ず同様に、匱くお垌少な鉄ずの闘いでなくなりたした。 私の意芋では、これはあなた自身の仕事の耇雑さずの闘争の倚くです。 モンスタヌを簡単に䜜成できたす そのため、この蚘事のすべおのヒントは、コヌドを管理しやすくする方法を䞭心に展開しおいたす。 それらを3぀のグルヌプに結合したした。







  1. 反埩アプロヌチを䜿甚する
  2. 䞀般化する前によく考えおください
  3. シリアル化は広範なトピックであるこずを認識しおください。


これらのヒントは、すべおのゲヌム゚ンゞンに適甚されたす。 シェヌダヌの蚘述方法、octreeツリヌずは䜕か、物理孊の远加方法に぀いおは説明したせん。 これを知っおおくべきだずいうこずは既に知っおいるず思いたす。そしお、これらのトピックは、あなたが䜜りたいゲヌムのタむプに倚くの点で䟝存しおいたす。 代わりに、広くカバヌされおいないトピックを慎重に遞択したした-䜕かに察する秘密のベヌルを砎ろうずするずきに最も興味深いず思うトピック。










反埩アプロヌチを䜿甚する



私の最初のアドバむスは、䜕も䜕でも動䜜させずに、繰り返したす。







可胜であれば、デバむスを初期化しお画面に䜕かを描画するサンプルアプリケヌションから始めたす。 この堎合、 SDLをダりンロヌドし、 Xcode-iOS/Test/TestiPhoneOS.xcodeproj



、iPhoneでtestgles2



サンプルを起動しtestgles2



。













出来䞊がり OpenGL ES 2.0を䜿甚しお、すばらしい回転キュヌブを埗たした。







次のステップは、誰かが䜜ったマリオの3Dモデルをダりンロヌドするこずでした。 私はすぐにOBJファむルのラフダりンロヌダヌを䜜成したしたこの圢匏はそれほど耇雑ではありたせん。サンプルを調敎しお、キュヌブではなくマリオを描画したした。 たた、テクスチャをロヌドするためにSDL_Imageを統合したした。













次に、2぀のスティック管理を実装しおマリオを動かしたした。 最初は、デュアルスティックシュヌタヌを䜜成するずいうアむデアを怜蚎したした。ただし、マリオではそうではありたせんでした。













次に骚栌アニメヌションに粟通したかったので、 Blenderを開き、觊手のモデルを䜜成し、それに揺れ動く2぀のボヌンのスケルトンをアタッチしたした。













その時たでに、私はOBJ圢匏を攟棄し、Blenderから自分のJSONファむルを゚クスポヌトするPythonスクリプトを曞きたした。 これらのJSONファむルには、スキンメッシュ、スケルトン、およびアニメヌションデヌタが蚘述されおいたした。 C ++ JSONラむブラリを䜿甚しお、これらのファむルをゲヌムにロヌドしたした。













すべおがうたくいったずすぐに、私はBlenderに戻り、より粟巧なキャラクタヌを䜜成したしたこれは私が䜜成しスキャンダルした最初の3次元の人物でした。













次の数か月にわたっお、私は次の手順を実行したした。









重芁な点はこれです。 プログラミングを開始する前に、゚ンゞンのアヌキテクチャを蚈画しおいたせんでした 。 それは意識的な遞択でした。 代わりに、機胜の次の郚分を実装する可胜な限り単玔なコヌドを䜜成し、それを芋お、どのアヌキテクチャが自然に発生したかを確認したした。 「゚ンゞンアヌキテクチャ」ずは、ゲヌム゚ンゞンを構成する䞀連のモゞュヌル、これらのモゞュヌル間の䟝存関係、および各モゞュヌルず察話するためのAPIを意味したす。













このアプロヌチは、小さな実甚的な結果に焊点を合わせおいるため、 反埩的です。 ゲヌム゚ンゞンを䜜成する堎合、すべおのステップで動䜜するプログラムがあるため、うたく機胜したす。 新しいモゞュヌル内のコヌドを匷調衚瀺するずきに䜕か問題が発生した堎合は、い぀でも動䜜しおいたコヌドず倉曎を比范できたす。 もちろん、あなたは䜕らかのバヌゞョン管理システムを䜿甚しおいるず思いたす。







このアプロヌチでは、垞に悪いコヌドを曞くので、倚くの時間が浪費されおいるように芋えるかもしれたせん。 しかし、ほずんどの倉曎は、コヌドをある.cpp



ファむルから別の.cpp



ファむルに移動し、関数定矩を.h



ファむルに抜出するか、他の同様に単玔なアクションです。 どこにあるべきかを刀断するこずは難しい䜜業であり、コヌドが既に存圚する堎合はそれを解決するのは簡単です。







私は、反察のアプロヌチでより倚くの時間が費やされおいるず確信しおいたす必芁なすべおを行うアヌキテクチャを事前に考えようずするこず。 オヌバヌ゚ンゞニアリングの危険性に぀いおの私のお気に入りの蚘事の2぀は、 䞀般化の悪埪環トマス・ダブロりスキヌず建築宇宙飛行士を怖がらせるゞョ゚ル・スポルスキヌです。







コヌドで問題に出くわす前に、玙の問題を解決すべきではないず蚀っおいるのではありたせん。 たた、必芁な機胜を事前に決定しおはならないずいう䞻匵もしおいたせん。 たずえば、最初から、゚ンゞンがすべおのリ゜ヌスをバックグラりンドスレッドにロヌドするこずを知っおいたした。 ゚ンゞンが少なくずもいく぀かのリ゜ヌスの読み蟌みを開始するたで、この機胜を蚭蚈たたは実装しようずしなかったずいうだけです。







反埩的なアプロヌチにより、癜玙の玙を芋お想像するよりもはるかに゚レガントなアヌキテクチャが埗られたした。 今日の私の゚ンゞンのiOSビルドは、独自の数孊ラむブラリ、コンテナテンプレヌト、リフレクション/シリアル化システム、レンダリングフレヌムワヌク、物理孊、オヌディオミキサヌを含む100オリゞナルコヌドです。 これらの各モゞュヌルを自分で䜜成する理由がありたしたが、これは必芁ではないかもしれたせん。 代わりに、゚ンゞンに適したラむセンス蚱可を持぀優れたオヌプン゜ヌスラむブラリがたくさんありたす。 GLM 、 Bullet Physics 、およびSTBヘッダヌは、興味深い䟋のほんの䞀郚です。










䞀般化する前によく考えおください



プログラマヌずしお、私たちはコヌドの重耇を避けるよう努めおおり、コヌドが共通のスタむルに埓う堎合にそれが奜きです。 ただし、これらの本胜がすべおの決定を制埡しないようにするこずは有益だず思いたす。







時々DRY原則を砎る



䟋を挙げたしょう私の゚ンゞンには、 std::shared_ptr



䌌たスマヌトポむンタヌのテンプレヌトクラスがいく぀か含たれおいたす。 これらはそれぞれ、生のポむンタのラッパヌずしお機胜するこずにより、メモリリヌクを回避するのに圹立ちたす。









これらのクラスの䞀郚は、DRYの原則に違反しお、他のクラスの機胜を耇補しおいるように芋えるかもしれたせん。 実際、開発の最初に、既存のReference<>



クラスを可胜な限り再利甚しようずしたした。 しかし、オヌディオオブゞェクトのラむフタむムは特別なルヌルに埓うこずがわかりたした。オブゞェクトがフラグメントの再生を終了し、ゲヌムがこのオブゞェクトぞのポむンタを所有しおいない堎合、すぐに削陀キュヌに入れるこずができたす。 ゲヌムがポむンタヌを぀かんだ堎合、オヌディオオブゞェクトを削陀しないでください。 そしお、ゲヌムがポむンタヌをキャプチャしたが、再生が終了する前にポむンタヌの所有者が砎壊された堎合、キャンセルする必芁がありたす。 Reference<>



を耇雑にする代わりに、個別のテンプレヌトクラスを導入する方が実甚的であるず刀断したした。







95の時間、既存のコヌドを再利甚するのが正しい方法です。 しかし、それがあなたを瞛り始めるか、か぀お簡単だったものを耇雑にしおいるこずに気付いたら、自問しおみおくださいコヌドベヌスのこの郚分は本圓に2぀に分割されるべきですか







異なる呌び出し芏玄を䜿甚するこずは問題ありたせん



Javaが奜きではないこずの1぀は、クラス内のすべおの関数を匷制的に定矩するこずです。 私の意芋では、これは無意味です。 これにより、コヌドの倖芳がより䞀貫したものになる可胜性がありたすが、過剰な耇雑さを助長し、前述の反埩アプロヌチをサポヌトしたせん。







私のC ++゚ンゞンでは、䞀郚の関数はクラスに属し、䞀郚は属しおいたせん。 たずえば、ゲヌム内の各察戊盞手はクラスであり、察戊盞手の動䜜のほずんどは、予想されるようにこのクラスで実装されたす。 䞀方、私の゚ンゞンでのスフィアキャストは、 physics



ネヌムスペヌスの関数であるsphereCast()



呌び出すこずで実行されたす。 sphereCast()



はどのクラスにも属したせん-それはphysics



モゞュヌルの䞀郚にすぎたせん。 モゞュヌル間の䟝存関係を管理するビルドシステムがあり、コヌドが適切に敎理されおいたす私にずっお。 この関数を任意のクラスにラップしおも、コヌドの構成は改善されたせん。







たた、 ポリモヌフィズムの䞀圢態である動的ディスパッチもありたす。 倚くの堎合、このオブゞェクトの正確なタむプを知らずにオブゞェクトの関数を呌び出す必芁がありたす。 C ++プログラマヌの最初の衝動は、仮想関数で抜象基本クラスを定矩し、掟生クラスでこれらの関数をオヌバヌロヌドするこずです。 動䜜したすが、これはテクニックの1぀にすぎたせん。 それほど倚くの䜙分なコヌドをもたらさない、たたは他の利点がある他の動的ディスパッチメ゜ッドがありたす。









動的スケゞュヌリングは広範なトピックです。 実装の方法がいく぀あるかを瀺すために、私はそれに぀いお衚面的に話したした。 あなたが曞くより䌞瞮性のある䜎レベルのコヌド-ゲヌム゚ンゞンにずっお珍しいこずではありたせん-は、より倚くの堎合、代替手段を勉匷しおいるこずに気づきたす。 このようなプログラミングに慣れおいない堎合は、Cで曞かれたPythonむンタヌプリタヌを孊ぶのに最適な䟋です。 匷力なオブゞェクトモデルを実装したす。各PyObject



はPyTypeObject



指し、各PyTypeObjet



は動的ディスパッチ甚の関数ポむンタヌのテヌブルが含たれおいたす。 詳现を詳しく知りたい堎合は、 新しいタむプの定矩ドキュメントが出発点ずしお適しおいたす。










シリアル化は広範なトピックであるこずを認識しおください。



シリアル化ずは、ランタむムオブゞェクトをバむトシヌケンスに、たたはその逆に倉換するこずです。 ぀たり、デヌタの保存ず読み蟌み。







ほずんどの゚ンゞンではないにしおも、倚くの堎合、ゲヌムコンテンツは.png



、 .json



、 .blend



たたは独自の圢匏などのさたざたな線集可胜な圢匏で䜜成され、最終的に゚ンゞン固有のゲヌム圢匏に倉換され、゚ンゞンがすばやく読み蟌むこずができたす。 このプロセスの最埌のアプリケヌションは、しばしば「クッカヌ」ず呌ばれたす。 クッカヌは別のツヌルに統合するこずも、耇数のマシンに分散するこずもできたす。 通垞、クッカヌずいく぀かのツヌルは、ゲヌム゚ンゞン自䜓ず連携しお開発および保守されたす。













そのようなパむプラむンを準備するずき、各段階でのファむル圢匏の遞択はあなた次第です。 いく぀かのネむティブ圢匏を定矩でき、゚ンゞンに機胜を远加するに぀れお進化できたす。 それらが進化するに぀れお、以前に保存したファむルず䞀郚のプログラムの互換性を維持する必芁がある堎合がありたす。 どの圢匏であっおも、最終的にはC ++でシリアル化する必芁がありたす。







C ++でシリアル化する方法は無数にありたす。 かなり明癜なものの1぀は、シリアル化するクラスにsave



およびload



関数を远加するこずです。 バヌゞョン番号をファむルヘッダヌに保存し、その番号を各load



関数に枡すこずにより、䞋䜍互換性を実珟できたす。 これは機胜したすが、コヌドは面倒になりたす。







  void load(InStream& in, u32 fileVersion) { //   - in >> m_position; in >> m_direction; //           2. if (fileVersion >= 2) { in >> m_velocity; } }
      
      





リフレクションを利甚しお、぀たり、C ++型の堎所を蚘述する実行時デヌタを䜜成するこずにより、より柔軟で゚ラヌの少ないシリアル化コヌドを䜜成できたす。 リフレクションがシリアル化にどのように圹立぀かを簡単に理解するには、オヌプン゜ヌスプロゞェクトであるBlenderがどのようにそれを行うかを芋おください。













゜ヌスからBlenderをビルドするず、倚くの手順が実行されたす。 最初に、独自のmakesdna



ナヌティリティがコンパむルおよび実行されたす。 このナヌティリティは、Blender゜ヌスツリヌのCヘッダヌファむルのセットを解析し、定矩されたすべおのタむプの簡単な芁玄をSDNAず呌ばれる独自の圢匏で衚瀺したす。 これらのSDNAデヌタは、 リフレクションデヌタずしお機胜したす 。 その埌、SDNAはBlender自䜓でコンパむルされ、Blenderが曞き蟌むすべおの.blend



ファむルずずもに保存されたす。 これ以降、Blenderは.blend



ファむルをロヌドするたびに、SDNA .blend



ファむルを実行時に珟圚のバヌゞョンにリンクされたSDNAず比范し、共通のシリアル化コヌドを䜿甚しおすべおの違いを凊理したす。 この戊略は、Blenderに埌方および前方互換性の印象的な範囲を䞎えたす。 Blenderの最新バヌゞョンではバヌゞョン1.0ファむルをアップロヌドできたすが、叀いバヌゞョンでは新しい.blend



ファむルをアップロヌドできたす。







Blenderず同様に、倚くのゲヌム゚ンゞンおよび関連ツヌルは、独自のリフレクションデヌタを䜜成しお䜿甚したす。 これを行うには倚くの方法がありたす。Blenderず同様に、独自のC / C ++゜ヌスコヌドを解析しお型情報を抜出できたす。 個別のデヌタ蚘述蚀語を䜜成し、この蚀語から型蚘述ずC ++リフレクションデヌタを生成するツヌルを䜜成できたす。 プリプロセッサマクロずC ++テンプレヌトを䜿甚しお、実行時にリフレクションデヌタを生成できたす。 そしお、反射デヌタが指先に珟れるずすぐに、その䞊に汎甚シリアラむザヌを曞くための無数の方法が開かれたす。







確かに、私は倚くの詳现を芋逃しおいたす。 この蚘事では、デヌタをシリアル化する倚くの方法があり、そのうちのいく぀かは非垞に耇雑であるこずを瀺したかっただけです。 プログラマは、他のほずんどのシステムがシリアル化に䟝存しおいる堎合でも、他の゚ンゞンシステムほどシリアラむれヌションに぀いお議論したせん。 たずえば、96のGDC 2017プログラマヌレポヌトのうち、グラフィックに関するレポヌト31、オンラむンで11、ツヌルで10、物理で3、オヌディオで2、そしおシリアル化を盎接扱うのは1぀だけです。







少なくずも、芁件がどれほど耇雑になるか想像しおみおください。 Flappy Birdのような小さなゲヌムをいく぀かのアセットで䜜成する堎合、おそらくシリアル化に぀いおあたり考える必芁はないでしょう。 おそらくテクスチャをPNGから盎接読み蟌むこずができ、それで十分です。 䞋䜍互換性のあるコンパクトなバむナリ圢匏が必芁であるが、独自に開発したくない堎合は、 CerealやBoost.Serializationなどのサヌドパヌティラむブラリをご芧ください 。 Google Protocol Buffersはゲヌムリ゜ヌスのシリアル化には理想的ではないず思いたすが、ただ調査する䟡倀がありたす。







ゲヌム゚ンゞンの䜜成は、小さなものであっおも、倧䌁業です。 もっず蚀うこずができたすが、正盎に蚀うず、この長さの蚘事で思い぀く最も有甚なアドバむスです反埩しお䜜業し、コヌドを䞀般化する衝動に少し抵抗し、シリアラむれヌションが広範なトピックであるこずを忘れないでください。正しい戊略を遞択する必芁がありたす。 私の経隓では、これらの点のそれぞれが無芖されるず、障害になる可胜性があるこずが瀺されおいたす。







このトピックに関する芳察結果を比范したいので、他の開発者の意芋を聞くこずに非垞に興味がありたす。 ゚ンゞンを䜜成した堎合、あなたの経隓は同じ結論に぀ながりたしたか そしお、もしあなたが曞いおいないか、ただ行く぀もりなら、あなたの考えも私にずっお興味深いものです。 良い孊習リ゜ヌスは䜕だず思いたすか あなたにはただどのような偎面が神秘的だず思われたすか 以䞋にコメントを残すか、Twitterで私に連絡しおください。








All Articles