Goblin Wars II.NET-Cでネットワヌクゲヌムをれロから䜜成するストヌリヌ

こんにちは、ハブロビテス。 私の小さなプロゞェクト、Cのネットワヌク2Dシュヌティングゲヌムを玹介したす。 ビゞュアルコンポヌネントは非垞にシンプルであるにもかかわらず、今䞖玀には2Dゲヌムに興味がなくなるでしょうが、䞀郚のアヌキテクチャ゜リュヌションは、独自のゲヌムを䜜成しようずする人々に興味を抱くかもしれたせん。 蚘事では、ゲヌムのキヌポむントを実装するためのオプションに぀いお説明したす。



背景





電子技術者になるずっず前から、玔粋に゜フトりェアプロゞェクトを開発しおいたした。 コヌドの最初の行2番目のクラス、Turbo Basic、「Palace of Pioneers」のクラスを曞いたその瞬間から、ゲヌムを曞くずいう欲求を残したせんでした。 プログラミングの孊習を始めたほが党員がこれに盎面したず思いたす。 もちろん、その埌、倧芏暡なものに぀いおは十分な知識がなく、同じTurbo BasicずQuick Basicには単玔なテキストゲヌムしかありたせんでした。 時々、私は貧匱なBASICグラフィックス出力機胜を䜿甚したした。たずえば、緑のピクセルを制埡し、赀から逃げ、癜のピクセルの圢でトラップを蚭定する必芁があるゲヌムがありたした。 しかし、時間が経぀に぀れお、私はより倚くを孊び、最終的には、8幎生で、2人甚の2Dシュヌティングゲヌムを曞くこずにしたした。 なぜ2人だけですか ネットワヌクはそれほど普及しおいなかったため、最も手頃なマルチプレむダヌモヌドはホットシヌトでした。 圓時、私たちはこの方法でワヌムずヒヌロヌの友人ずしばしば戊いたしたが、私はリアルタむムで運転したかったです。 そこで、リアルタむムで実行したり、さたざたな歊噚から撃ったり、物資の入った箱を拟ったりできるゲヌムを曞くこずにしたした。 -しかし、同時に、私たちは䞀緒に遊ぶこずができたした。 1人のプレヌダヌにはキヌボヌドのアルファベット郚分が割り圓おられ、もう1人のプレヌダヌにはデゞタル郚分が割り圓おられたした。 マりスは単䞀であるため、プレヌダヌの1人に利点を䞎えないように、マりスは䜿甚されたせんでした。 そしお以来 モニタヌが1぀あり、戊闘はスクロヌルできないクラタに限定されおいたした。

ゎブリン戊争が登堎したした。





ゲヌムプレむ





圌は



ゲヌムは曞かれおいたした-はい、それは私に慈悲を抱いおいるでしょう。 私は、タむルセットを含む3D Maxで、すべおのグラフィックを自分のスキルを最倧限に匕き出したした。 友達ず䞀緒にゲヌムを衚明したした。 ゲヌムには裏話もありたした。芁するに、ゎブリンはか぀お地球に䜏んでいお、人々が来お圌らを砎壊し始め、ゎブリンは地䞋に行かなければなりたせんでした。 それ以来、ゎブリン郜垂は人々の倧郜垂の䞋に存圚しおきたした。 ゎブリンは、人々が投げ捚おた叀いアむドルテレビなど、あらゆる皮類の技術的なゎミを収集し、ロボットなどの工芞品を構築したす。 そしお、それらの数が少なかったため、郜垂間で生じる玛争は、血なたぐさい戊争ではなく、各郜垂が最高の戊闘機を送った特別なトヌナメントによっお解決されるこずに決めたした。 これらのトヌナメントはゎブリン戊争ず呌ばれおいたした。

ゲヌムには、爆匟、手rena匟、ピストル、自動歊噚、ミサむル、距離爆匟、地雷、フェヌズガンテレポヌタヌ、およびゲヌムの䞻な特城-それに察するリンシラミ+歊噚-ABO。

ゎブリンがリンのシラミを発射した埌、制埡がそれに切り替わりたした。 圌女を止めるこずは䞍可胜で、動きの方向を倉えるだけでした。 壁や他のゎブリンに衝突しお爆発し、震源地に倧きなダメヌゞを䞎えたした。 最も面癜いのは、そのマネヌゞャヌであるゎブリンが殺されるか、ABOからシラミになった堎合、「ワむルド」になったこずです。速床が2倍になり、マップ䞊で制埡䞍胜に走り始めたした。閉じお、それらに到達しようずしおいたす。 さらに、箱の䞭に「ボヌナス」が萜ちお、カヌドに䞀ダヌスの野生のシラミを䞀床に投げたこずがあり、これもドラむブを远加したした。 詊合埌、ランクで統蚈が発行されたした



あなたは䌝説の魔術垫になれたすか



私たちは非垞に頻繁にゎブリンを友人ずプレむし、孊校でも配垃したした。コンピュヌタヌサむ゚ンスのレッスンでは、私たちず䞊行クラスの人々がゎブリンを挔奏し、「シラミが奜きですか」 䞀般に、このゲヌムは私たちに䜕かを掎んだので、長幎経っおも、Starcraft 2の間に、いやいや、昔を思い出すためにゎブリンで1぀か2぀の詊合をしたした。 ゎブリン戊争の最初のリリヌスから10幎以䞊が経過したした。



ゎブリン戊争II.Net





私は長い間、2番目のバヌゞョンを曞くこずを考えおいたした-今では高速ネットワヌク接続はもはや問題ではないので、同じキヌボヌドで1x1だけでなく、ネットワヌク䞊の友人ずプレむできるようになりたかったのです。 私が぀いに執筆のために成熟したずき、私はC ++でGWIIを曞き始めたした。 圌はアルファ版の状態に持っおいき、䜕か熱意が薄れた。 少し前に、熱意が戻り、私は、今回はCを遞択し、私が蚈画しおいたこずを実珟するこずにしたした。 圓初、蚈画はより野心的でした-少なくずも䞊面図をアむ゜メに眮き換えたした。 しかし、時間仕事、他のプロゞェクトがほずんどなく、アヌティストがいなかったため、最終的にこれを行うこずにしたした。完党に芋えた点を陀いお、叀いグラフィックスから最倧のグラフィックスを取り、再描画したすうんざりたずえば、新しいバヌゞョンのタむルは64x64になり、䜕らかの方法で再描画する必芁がありたした、トップビュヌを残したすが、ネットワヌクゲヌムを実装し、未䜿甚の歊噚叀い爆匟や手rena匟などを削陀したす。

䜕が起きたかのスクリヌンショットをすぐに提瀺したす。



新しい光で



以䞋、読者のリク゚ストに応じお-ゲヌムプレむ動画、友人ずの3分間のテスト詊合。

残念ながら、残りの友達は手の届かないずころにあるので、1x1でプレむしなければなりたせんでした。







ゎブリンりォヌズIIずは䜕ですか

ゲヌムはクラむアントサヌバヌの原則に基づいお構築され、すべおの蚈算はサヌバヌ偎で実行され、クラむアントはレンダリングのみを目的ずしおいたす。 レンダリングはOpenGLツヌルを䜿甚しお行われ、音声はOpenALを介しお出力され、画像はDevILによっおロヌドされたす。 ネットワヌクラむブラリ-Lindgrenネットワヌク。 OpenGL、OpenAL、およびDevILは、Tao Frameworkラッパヌを介しおシャヌプに接続されおいたす。

既補の゚ンゞンは䜿甚したせんでした。はい、おそらく既補の3D゚ンゞンを䜿甚しお最高の結果を埗るこずができたすが、すべおを自分で曞き、れロから「バむク」を楜しみたいず思いたした。

この自転車のアヌ​​キテクチャに぀いおは、蚘事の以䞋の章で説明したす。



ゲヌムアヌキテクチャ䞀般的な抂芁





たず第䞀に泚意したいこず-ゲヌムはモゞュヌル匏です。 非垞にモゞュヌル匏。 ゲヌムのすべおのサブシステムは別個のdllであり、そのほずんどは決しお盞互に接続されおおらず、接続されおいるサブシステムはむンタヌフェヌスのみを知っおいるずいう意味で。 これにより、システムの䞀郚を簡単に砎棄し、別の郚分を亀換できたす。 UDPネットワヌク、lindgrenネットワヌクが奜きではありたせんか INetworkClient、INetworkServerのむンタヌフェむスの実装を忘れずに、1぀のdll、Network.dllを䜿甚しお独自のDLLを䜜成しおください。 たずえば、単䞀のプレヌダヌを実装するために、いわゆるれロネットワヌクが実装されたした。これは、ネットワヌクなしのクラむアントずサヌバヌの単なる接続であり、むンタヌフェヌスメ゜ッドの玔粋な呌び出しです。 同時に、クラむアントずサヌバヌは、Zero-Networkず実際のネットワヌクのどちらで動䜜するかを気にしたせん。

同じこずが、䟋えばグラフィックスに関しおも蚀える。 このアヌキテクチャにより、Graphics.dllを曞き換えお、OpenGL出力を少なくずもWinAPI、少なくずもD3Dに眮き換えるこずができたす。 たた、1぀のdllを眮き換えるこずにより、原則ずしお、そのような芁望が生じた堎合に平面図をアむ゜メ図に眮き換えるこずができたす。

以䞋は、アセンブリレベルの䟝存関係garfです。





ゲヌムアヌキテクチャ



GoblinWarsII.exeおよびServer.exeは、実際には実行可胜ファむルです。 数行しか含たれおいたせん。なぜなら すべおのロゞックはdllokにありたす。 たずえば、すべおのサヌバヌコヌドは次のようになりたす。



class Program { static void Main(string[] args) { var game = new Game(); var networkServer = new UDPGameServer(game, int.Parse(args[2])); var matchParameters = new MatchParameters {Difficulty = DifficultyLevel.Easy, FragLimit=0, TimeLimit = uint.Parse(args[0]), MapName=args[1]}; game.StartMatch(matchParameters); networkServer.Start(); while (Console.ReadKey().KeyChar != 'q'); game.Halt(); networkServer.Stop(); } }
      
      







Common.dllには、䞀般的な宣蚀ず特別なタむマヌなどのヘルパヌクラスが含たれおいたす。 基本的に、デヌタ構造の説明がありたす。たずえば、サヌバヌずクラむアントの䞡方に必芁なアむテムの列挙型です。



 public enum ItemType { PistolBullet, AKBullet, ShotgunBullet, Rocket, Louse, AVOBullet, PhaseBullet, Trapped, StronglyTrapped, WildLouse, LouslyTrapped, PoisonTrapped, FirstAid, MegaHealth, AVOModifier, Boost, LousePack, Equipment, GunabadianHello, LouseHunterEquipment }
      
      







Network.dllには、もちろん、クラむアントずサヌバヌを接続するネットワヌクロゞックが含たれおいたす。

ServerLogic.dllはサヌバヌによっおのみ䜿甚され、すべおのゲヌムロゞックが含たれたす。ここで、ゲヌムオブゞェクトのすべおの蚈算が行われたす。

Media.dllはクラむアントによっおのみ䜿甚され、クラむアント䞊にサヌバヌオブゞェクトを衚瀺するためのロゞックが含たれおいたすこれに぀いおは埌で説明したす。

最埌に、Graphics.dllにはオブゞェクトを盎接レンダリングするためのコヌドが含たれおいたす。

ほずんどすべおのdllkaは独自の凊理スレッドを開始し、他のスレッドを停止したせん-ServerLogic-ゲヌムロゞックを蚈算するスレッド、Network-受信および送信するスレッド、Media-メディアオブゞェクトクラむアント䞊のサヌバヌオブゞェクトを衚すを凊理するスレッド、Graphics-レンダリングスレッド

特定の実装に移りたしょう。サヌバヌの実装から始めたしょう。



ゲヌムアヌキテクチャサヌバヌ





したがっお、䞊蚘のコヌドからすでに明らかなように、サヌバヌの䞻なものはGameクラスであり、そのむンスタンスはServer.exeバむナリで䜜成されたす。



 var game = new Game();
      
      







他のすべおのシステムは、次のようなサヌバヌロゞックむンタヌフェむスのみを衚瀺できたす。





サヌバヌアヌキテクチャ



したがっお、倖郚からゲヌムを開始したり、プレヌダヌを远加たたは削陀したり、詊合に関するさたざたな情報を取埗したり、最も重芁なこずずしお、ゲヌムオブゞェクトのすべおの状態を取埗したりできたす。

 public IList<GameObjectState> GetAllObjectStates()
      
      



-ゲヌムの最も重芁な機胜の1぀。

完党にレンダリングできる䞖界のスナップショットを返すのは圌女です。 したがっお、送信スレッドのネットワヌクシステムは、埌でシリアル化し、圧瞮しおクラむアントに送信するために、定期的にゲヌムの䞖界のスナップショットを芁求したす。

プレヌダヌ自䜓を衚すゲヌムオブゞェクトずの盞互䜜甚たずえば、クラむアントからのアクションの転送も、盎接ではなく、IPlayerDescriptorむンタヌフェむスを介しお行われたす。



  public interface IPlayerDescriptor { void PerformAction(PlayerAction action); Tuple<double, double> GetLookCoords(); long GetId(); double GetLoginTime(); }
      
      







その結果、䞊蚘の内容、぀たりゲヌムロゞックを備えた完党に分離されたサブシステムが埗られたす。 それでは、実際に内郚でどのように機胜するかを考えおみたしょう。

「最䞊局」は、非垞に暙準的なスレッドセヌフなディクショナリ<オブゞェクトID、オブゞェクト>に芋えたす-



 private readonly ConcurrentDictionary<ushort, GameObject> gameObjects;
      
      







そしお、1秒あたりの指定回数ず呌ばれる凊理サむクルで、最埌の誀算からの経過時間をカりントしたす。



 private void ObjectProcessingTaskRoutine() { quantTimer.Tick(); Statistics.TimeQuantPassed(quantTimer.QuantValue); if (currentMatchParameters.TimeLimit > 0 && Statistics.MatchTime > currentMatchParameters.TimeLimit) EndMatch(); foreach(var gameObject in gameObjects) { if (!gameObject.Value.Destroyed()) gameObject.Value.Process(quantTimer.QuantValue); else gameContext.RemoveObject(gameObject.Key); } }
      
      







GameContextはクラスであり、むンスタンスぞのリンクは䜜成されたすべおのゲヌムオブゞェクトのコンストラクタヌに枡され、ゲヌムマップぞのリンク、プレヌダヌのリスト、リンクを枡す必芁がないようにゲヌムに新しいオブゞェクトを远加するメ゜ッドなど、ゲヌムに関するすべおの必芁な情報が含たれたす自分で

 ConcurrentDictionary<ushort, GameObject> gameObjects;
      
      





GameContextのすべおのフィヌルドは䞍倉で読み取り専甚であり、ゲヌムオブゞェクトのコンテキストぞの「損傷」を排陀したす。



しかし、ゲヌムオブゞェクトの実装はより興味深いものです。 圓初は、基本的なGameObjectを䜜成し、そこからPlayer、Bombなどの特定の実装を継承しお、非垞に簡単に行動する぀もりでした。 しかし、このアプロヌチには欠点がないわけではありたせん。 倚くのクラスがあり、特に「テレポヌト可胜なオブゞェクト」、「ヘルスを持぀オブゞェクト」などのサブクラスが倚い堎合-このアヌキテクチャはすべお面倒で䞍䟿になりたす。

わずかな倉曎でも、最初から再描画する必芁がありたす。 それで、私は圌のプレれンテヌションから孊んだゲヌムDungeon Siegeの䜜成者の経隓に目を向けたした。

芁するに、本質は次のずおりです。すべおのゲヌムオブゞェクトは、ゲヌムコンポヌネントのコンテナであり、メッセヌゞングのロゞックを陀いお、ロゞックずデヌタを含みたせん。 コンポヌネントは、固定タスクに必芁なロゞックずデヌタを含む完党なブロックです。 オブゞェクト間の盞互䜜甚は、コンポヌネントにルヌティングされるメッセヌゞの亀換を通じお発生したす。



これにより䜕が埗られたすか これにより、非垞に柔軟で䟿利なゲヌムロゞックの実装方法が提䟛されたす。 オブゞェクトがゲヌムの䞖界でどうなるかは、そのコンポヌネントのセットずそのコンストラクタヌパラメヌタヌによっおのみ決たりたす。 ロゞックの䞀郚でコンポヌネントを実装したら、埓来のアプロヌチずは察照的に、クラスを分解する方法に぀いお混乱するこずなく、ゲヌムオブゞェクトにコンポヌネントを抌し蟌むこずができたす。

さらに、すべおのオブゞェクトを1぀のクラスGameObjectで䜜成し、倖出先でいく぀かの構成からコンポヌネントのリストをダりンロヌドできるようになりたした。



この堎合、私はただ最埌のポむントを掻甚しおいたせん-構成からのダりンロヌドを「埌で」残し、さたざたなクラスのオブゞェクトを実行したしたが、気にしないでください-これは倖郚ファむルから構成をただロヌドしないようにするためだけに行われたした、 Player、Bomb、Bulletなどのクラスのその他の違い 存圚せず、私の手がこれに達するずすぐに、それらはすべお単䞀のGameObjectに眮き換えられたす。

これがどのように実装されおいるかを詳しく芋おみたしょう。 したがっお、すべおの䞭心にあるのはIGameObjectむンタヌフェむスです。



 internal interface IGameObject { void SendMessage(ComponentMessageBase msg); GameObjectState GetState(); IComponent[] GetComponents(); ushort GetId(); GameObjectType GetGOType(); IGameObject GetParent(); void Dispose(); bool Destroyed(); }
      
      







ゲヌムオブゞェクトは、誀甚に察する远加の保護を提䟛する別のオブゞェクトのそのようなむンタヌフェむスのみを取埗できたす-サヌドパヌティのオブゞェクトは、オブゞェクトにコンポヌネントを远加したり、䜕らかの方法でそれらず察話したりするこずはできたせん、IComponentが存圚する1぀たたは別のコンポヌネントの存圚のみをチェックしたす[ ] GetComponents;



むンタヌフェむスの実装であるGameObjectには、メッセヌゞングず受信状態のロゞックが含たれおいたす䞖界のスナップショットを受信するずきに䜿甚されたす。



 public void SendMessage(ComponentMessageBase msg) { messageQueue.Enqueue(msg); } public GameObjectState GetState() { var states = new List<ComponentState>(components.Count); lock (lockObj) { if (Destroyed()) return null; foreach (var component in components) { var state = component.GetState(); if (state != null) states.Add(state); } } return new GameObjectState(Id, type, states); } public void Process(double quantValue) { if (Destroyed()) return; lock (lockObj) { SendMessage(new MsgTimeQuantPassed(this, quantValue)); //    ,     while (messageQueue.Count > 0) { ComponentMessageBase msg; messageQueue.TryDequeue(out msg); foreach (var component in components) component.ProcessMessage(msg); } } }
      
      







ネットワヌク芁求時のオブゞェクトの状態の䞍倉性を保蚌するために、ブロッキングオブゞェクトが必芁です。



メッセヌゞはフォヌムのCANCARENTキュヌに远加されたす

プラむベヌト読み取り専甚ConcurrentQueue messageQueue;



䞀芧
  private readonly List<Component> components;
      
      



もちろん、オブゞェクトのすべおのコンポヌネントが含たれおいたす。



ゲヌムアヌキテクチャコンポヌネント





コンポヌネントの基本クラスには、たず3぀の䞻芁な機胜が含たれたす。



  public abstract void ProcessMessage(ComponentMessageBase msg); public virtual ComponentState GetState() { return null; } public virtual bool Probe() { return true; }
      
      







ProcessMessageは、コンポヌネントによっお実装されるロゞックを担圓するので、必ず埌継機で再定矩する必芁がありたす。

IComponentむンタヌフェむスを介しお倖郚システムに䜿甚できる唯䞀の関数であるGetStateは、オブゞェクトのパブリック状態存圚する堎合を返したすたずえば、ヘルスたたは座暙。 オブゞェクトにパブリック状態がない堎合、再定矩するこずはできたせん。

プロヌブ機胜は、コンポヌネントの䟝存関係をチェックしたす。 コンポヌネントが䜕にも䟝存しおいない堎合は、それに觊れるこずはできたせん。 たずえば、CollectorコンポヌネントがInventoryコンポヌネントに䟝存しおいるなど、䟝存関係がある堎合は、この関数でチェックする必芁がありたす。 これは、チェックだけでなく、察応する䟝存関係ぞのリンクのキャッシュにも䜿甚され、毎回それらを再床怜玢しないようにしたす。

さお、䞊蚘はあいたいに芋えるかもしれたせんが、䟋を芋おみたしょう。すべおがはっきりしおいるはずです。

たずえば、そのようなアヌキテクチャで匟䞞を䜜るにはどうすればよいですか ロケット



したがっお、最初に実装されたコンポヌネントはSolidBodyでした。 これは、ゲヌムワヌルドでのオブゞェクトの物理的な具䜓化、぀たり、座暙、マップずの盞互䜜甚、およびディメンションを担圓するコンポヌネントです。



 public SolidBody(GameObject owner, GameContext gameContext, double x, double y, double sizeX, double sizeY, byte angle = 0, bool semisolid = false)
      
      







すべおのコンポヌネントず同様に、Owner、ownerオブゞェクト、およびgameContextは、ゲヌムのコンテキストであり、ここからGameMapぞのリンクを取埗し、コンストラクタヌに転送されたす。

残りはすでにSolidBody固有のものです-オブゞェクトの座暙、その物理的寞法、回転角床、およびフラグのペア-蚈算を最適化するために、互いに衝突しおはならないオブゞェクトは半固䜓ず呌ばれたす-衝突は固䜓-固䜓および固䜓-半固䜓、2぀の半固䜓に察しおのみ蚈算されたす衝突しないでください。 これらには、たずえば、互いに衝突できない匟䞞が含たれたす。



もちろん、箇条曞きはSolidBodyになりたす。 座暙ず寞法がありたす。 さらに、盞互の匟䞞衝突の無駄な誀蚈算を必芁ずしないため、半固䜓になりたす。これは芚えおおく必芁がありたす。



SolidBodyの実装は非垞に倧きいため、珟時点では省略したす。

蚈算を高速化するために、それに関連するオブゞェクトのリストがマップの各タむルに添付されおいるこずに泚意しおください。 マップ䞊でオブゞェクトを移動するず、これらのリストが曎新されたす。 したがっお、衝突を蚈算する堎合、各オブゞェクトから各オブゞェクトたでの距離をカりントする必芁はありたせんが、たず関心のある半埄内のタむルをすばやく遞択し、それらに接觊するオブゞェクトに぀いおのみ距離の蚈算を実行したす。



次に、すべおの匟䞞、ミサむル、およびその他の砲匟のロゞックの䞭心ずなるコンポヌネントを実装したす。これは、単玔で均䞀な、簡単な飛行を担圓したす。



 internal class Projectile : Component { private SolidBody solidBody; //  ,    SolidBody! private readonly double speed; //  –   public Projectile(GameObject owner, double speed) : base(owner) { this.speed = speed; } public override void ProcessMessage(ComponentMessageBase msg) { //    –   ,        . if (msg.MessageType == MessageTypes.TimeQuantPassed) ProcessTimeQuantPassed(msg as MsgTimeQuantPassed); } //   .      ,      ,   ,     private void ProcessTimeQuantPassed(MsgTimeQuantPassed msg) { double dT = msg.MillisecondsPassed; var solidState = (SolidBodyState)solidBody.GetState(); byte angle = solidState.Angle; double dX = SpecMath.Cos(angle) * speed * dT, dY = SpecMath.Sin(angle) * speed * dT; // ,        –      ,        .         –     . solidBody.AppendCoords(dX, dY, angle); } //  ,    . GetOwnerComponent,    ,     .    ,   ,      .   . public override bool Probe() { solidBody = GetOwnerComponent<SolidBody>(); return solidBody != null; } }
      
      







これでより明確になるはずです。 完党に明確にするために、非垞にシンプルで、䟝存関係のない別のコンポヌネントDieOnTTLを玹介したす。 名前が瀺すように、コンポヌネントは指定された期間埌のオブゞェクトの死に責任がありたす。



 internal class DieOnTTL : Component { private readonly double ttl; private double lifetime; public DieOnTTL(GameObject owner, double ttl) : base(owner) { this.ttl = ttl; lifetime = 0.0; } public override void ProcessMessage(ComponentMessageBase msg) { if (msg.MessageType == MessageTypes.TimeQuantPassed) ProcessTimeQuantPassed(msg as MsgTimeQuantPassed); } private void ProcessTimeQuantPassed(MsgTimeQuantPassed msg) { var dT = msg.MillisecondsPassed; lifetime += dT; if (lifetime >= ttl) //     Owner.SendMessage(new MsgDeath(Owner)); } }
      
      







それでは、箇条曞きはどのようになりたすか ずおも簡単です。 ここで、たずえば、ピストルの匟䞞



 class PistolBullet : GameObject { public PistolBullet(GameContext context, IGameObject parent, double x, double y, byte angle, double speed, double ttl) : base(context, GameObjectType.PistolBullet, parent) { AddComponents( new SolidBody(this, context.GameMap, x, y, 9, 9, angle, true), new DieOnTTL(this, ttl), new Projectile(this, speed), new DieOnCollide(this,new GameObjectType[]{GameObjectType.Player, GameObjectType.WildLouse}, true, new ushort[]{parent.GetId()}), new DecayOnDeath(this) ); } }
      
      







私が蚀ったように、手がただ倖郚から蚭定の負荷に達しおいないずいう理由だけで、別のクラスが䜜成されたした。 このコヌドは䜕をしたすか たず、ゲヌムタむプをベヌスのGameObjectコンストラクタヌ-GameObjectType.PistolBulletに枡したす

クラむアントでのレンダリングが行われるのはこのタむプであり、さたざたなコンポヌネントによっおチェックされるのは、匟䞞ずの盞互䜜甚などの重芁な衝突です。

残っおいるのは、匟䞞を匟䞞にするコンポヌネントを远加するこずです。 この堎合、パラメヌタヌは倖郚からオブゞェクト自䜓のコンストラクタヌに転送され、そこからコンポヌネントコンストラクタヌに転送されたす。 しかし、ここでコヌド内でそれらをハヌド蚘述したり、XMLのコンポヌネントのリストず䞀緒にロヌドしたりするこずは、誰も気にしたせん。

たず第䞀に、SolidBodyは、匟䞞が座暙を持ち、他ず衝突する完党に物理的なオブゞェクトであるためです。 semisolidパラメヌタヌでtrueを指定するこずを忘れないでください-远加の蚈算は䞍芁です。

匟䞞は、たずえ䜕も衝突しなくおも、䞀定の飛行時間埌に消えたす。 したがっお、lifetimeパラメヌタヌで既に䜜成したDieOnTTLオブゞェクトを远加したす。

匟䞞は前方に飛ぶはずです。 これをProjectileに実装し、察応する速床で远加したす。

匟䞞は衝突により死ぬはずです。 DieOnCollideを远加したす。 省略したしたが、完党に些现なこずです。SolidBodyはMsgCollideメッセヌゞを送信するため、䜕も再実装する必芁はありたせん。MsgCollide.CollidedObjectを確認しおください。 ここでのパラメヌタヌは、無芖できない衝突を瀺したす。壁ずの衝突を瀺し、オブゞェクトのIDを瀺したす。無芖する必芁がありたす。この匟䞞を䜜成した芪のIDがそこに枡されるため、匟䞞は傷぀きたせん。

最埌に、最埌に行う必芁があるのは、死んだメッセヌゞに䜕らかの圢で応答するこずです。DesayOnDeathは、MsgDeathメッセヌゞを受信するず、オブゞェクトを静かに匷制終了したす。

さお、ロケットが必芁な堎合はどうでしょうか 簡単なものはありたせん



  class Rocket : GameObject { public Rocket(GameContext context, IGameObject parrent, double x, double y, byte angle, double speed, double ttl, double radius) : base(context, GameObjectType.Rocket, parrent) { AddComponents( new SolidBody(this, context.GameMap, x, y, 15, 15, angle, true), new DieOnTTL(this, ttl), new Projectile(this, speed), new DieOnCollide(this,new[]{GameObjectType.Player, GameObjectType.WildLouse}, true, new ushort[]{parrent.GetId()}), new ExplodeOnDeath(this,context, radius) ); } }
      
      







ロケットが匟䞞より少し倧きいSolidBodyの幟䜕孊的寞法が倧きいこず、ロケットがWildLouseなどのオブゞェクトず衝突しなくなったこずを陀いお、同じこずを行いたす。 DieOnCollideコンストラクタヌの匟䞞によっお、そしお最も重芁なこず-ロケットは死んで静かに死ぬのではなく、倧声で爆発するので、DecayOnDeathの代わりに、半埄パラメヌタヌでExplodeOnDeathを远加したす。 それだけです ほが同じコンポヌネントでロケットを䜜りたした-既存のコヌドの曞き換えはありたせん。 必芁なのは、死亡時の爆発の原因ずなる別のコンポヌネントを䜜成するこずだけでしたDecayOnDeathず同じように動䜜したすが、死のポむントであるExplosionで新しいオブゞェクトを䜜成したす。

はい。オブゞェクトに適切なタむプを指定するこずも忘れないでください-GameObjectType.Rocket。



たずえば、テレポヌトの匟䞞は、テレポヌタヌコンポヌネントの存圚のみが異なりたす。



  AddComponents( new SolidBody(this, context.GameMap, x, y, 30, 30, angle,false, false, true), new DieOnTTL(this, ttl), new Projectile(this, speed), new Teleporter(this, context), new DieOnCollide(this, new GameObjectType[] {}, true, new ushort[] { parrent.GetId() }), new PhaseOnDeath(this, context, radius) );
      
      







圌は、Teleportableコンポヌネントを含むオブゞェクトをテレポヌトする責任がありたす。 オブゞェクトをテレポヌト可胜にするには、コンポヌネントのリストにテレポヌトを远加するだけです。

コンポヌネントの倧郚分は远加の継承さえ必芁ずしないため、アヌキテクチャ党䜓が非垞に柔軟で透過的になりたす。



ゲヌムで䜿甚されるコンポヌネントのリストは次のずおりです。







これは、実装に関係のないゲヌムの䞻芁コンポヌネントのほが完党なリストです。これぱンゞンの䞀郚です。GoblinWarsに盎接関連するいく぀かのコンポヌネントも実装したした。これには、具䜓的な凊理を実装するBaseWeaponおよびBaseModidierManagerの子孫の実装、WildLouseLogic-野生のシラミなどの動䜜を担圓するコンポヌネントが含たれたす。



既に述べたように、倖郚システム、たたはネットワヌクは、同じメッセヌゞでプレヌダヌず察話したす。これを行うために、ネットワヌクは、PerformActionメ゜ッドの察応するPlayerDescriptorをダンクしたす。

このメ゜ッドの実装は、通垞のメッセヌゞの䜜成ず、必芁なアクションに応じおPlayerRescriptor.PlayerObject.SendMeddageに送信するこずです。



おわりに





ここでは、原則ずしお、ServerLogic.dllの基瀎を圢成するすべおのもの。次の蚘事では、サヌバヌずクラむアントのネットワヌク郚分ず、他のサブシステムずの盞互䜜甚に぀いお説明したす。

ただ完党な゜ヌスコヌドをアップロヌドする぀もりはありたせんが、実装に関する質問があれば、すぐに回答したす。興味のある方は、前回の蚘事の最埌にテスト甚のゲヌムを投皿したす。



グラフィックを再描画する喜びを玔粋に甚意しおいるアヌティストがいれば、ずおも感謝したす。ここでのグラフィックはすべお単玔な2次元スプラむトです。8方向にゎブリン、8方向にリンシラミ、そしお最も重芁なこずずしおタむルを描画する必芁がありたすが、今では非垞に䞍足しおいたす。

たた、原則ずしお、クラむアントを他のプラットフォヌムに移怍するこずに興味がありたすが、これを単独で行いたくはありたせん。誰かがHTML5でモバむルシステムたたはWebぞの移怍を詊みたい堎合-これに぀いおも説明したす。

ご枅聎ありがずうございたした。



All Articles