بسم الله الرّحمن الرّحیم

آموزش ساخت بازی چندنفره 1: مفاهیم پایه (7097 downloads)

معرّفی

ساخت بازی‌های چند نفره (مولتی پلیر) کار سختی است، البتّه کانستراکت 2 بسیاری از پیچیدگی‌های این کار را برای شما آسان کرده است. برای این‌که بتوانید به نحو احسن از قابلیّت چند نفره‌ی کانستراکت 2 استفاده کنید باید با نحوه‌ی کار بازی‌های آنلاین، مشکلاتی که در این زمینه پیش می‌آید و نحوه‌ی حلّ آن‌ها آشنا شوید.

اگر از چیزهایی که در این آموزش ذکر می‌کنیم استفاده‌ی اشتباه شود، بازی دچار باگ‌ها و مشکلات عجیب و غریبی می‌شود. با این که شاید خیلی دوست داشته باشید هر چه سریع‌تر بازی چند نفره بسازید، ما به شدّت به شما توصیه می‌کنیم قبل از شروع کار هر چهار آموزش ساخت بازی چند نفره را مطالعه کنید. چون که ساخت بازی چند نفره یک ویژگی پیشرفته است، ممکن است برای تازه‌کاران کمی مشکل باشد.

اتّصال

موتور چندنفره‌ی کانستراکت 2 بر پایه‌ی WebRTC DataChannels ساخته شده است. در کانستراکت 2 بازی‌کن‌ها به جای این‌که از طریق یک سرور به هم وصل شوند، به طور مستقیم به یکدیگر متّصل می‌شوند.

در این حالت اوّلین کسی که به بازی ملحق می‌شود هاست[1] (Host) نام می‌گیرد. بقیّه‌ی کسانی که به بازی ملحق می‌شوند فقط به هاست متّصل می‌شوند. بازی‌کن‌هایی که هاست نباشند پیر (Peer) نام می‌گیرند. هاست به عنوان سرور بازی عمل می‌کند. تفاوت اصلی بین هاست و سرورهای مرکزی این است که هاست می‌تواند یکی از بازی‌کن‌ها باشد در حالی که سرور همیشه آنلاین توسّط سازنده‌ی بازی راه اندازی شده است. درضمن هاست خودیک شرکت کننده‌ی فعّال در بازی است، ولی سرور خود جزو بازی نیست و فقط بازی را برای بازی‌کن‌ها اجرا می‌کند.

چندنفره برپایه سرور مرکزی
اتصال همتا به همتا

البته باز هم می‌توانید بازی‌تان را با سرور مرکزی هم بسازید، به این صورت که بازی‌تان را طوری طرّاحی کنید که هاست یکی از شرکت کننده‌ها در بازی نباشد، و آن را روی یک سرور اجرا کنید. امّا اگر بخواهید این کار را انجام دهید مجبورید هزینه‌ای را نیز برای سرور پرداخت کنید. امّا اتّصال همتا به همتا (peer to peer) خیلی ارزان‌تر برایتان در می‌آید.

یک پیر برای این‌که بتواند به هاست وصل شود باید بداند که هاست در کجا قرار دارد و چگونه می‌تواند این کار را انجام دهد. برای این کار باید آدرس IP را هم پیدا کند.

سال‌هاست که استفاده از نسخه‌ی 4 آیپی (IPv4) در اینترنت دوام یافته است. این باعث می‌شود که چندین کاربر پشت یک آیپی مخفی بمانند. این کار به وسیله‌ی برگردان نشانی شبکه (NAT)[2] انجام می‌شود. مثلاً در خانه یا محلّ کار شما یک مودم اینترنت دارید که تعدادی رایانه یا موبایل و… برای اینترنت به آن وصل شده اند، در این حالت گونه‌ای از NAT باعث می‌شود آدرس آیپی تمام آن‌ها با هم یکی شود، در حالی که آن‌ها از پورت‌های مختلف به آن مودم وصل شده‌اند. NAT انواع دیگری نیز دارد، بعضی از انواع NAT باعث یکی شدن آیپی‌های یک منطقه، ارائه دهندگان خدمات اینترنتی (ISPها)، و شبکه‌های تلفن همراه می‌شوند. متأسفانه این یعنی ممکن است در بعضی از موارد امکان اتّصال نباشد، مخصوصاً اگر هاست و پیر هر دو به وسیله‌ی NAT پشت یک آیپی مخفی شده باشند.

وضع شبکه و NAT

مثلاً یک پیر را در نظر بگیرید که می‌خواهد به هاست متّصل شود و هاست پشت یک NAT محدود مثل تصویر بالا باشد. در این صورت به خاطر یکی بودن نشانی آیپی این سه پورت، پیر نمی‌داند که باید به Port A وصل شود یا Port B یا… . این باعث می‌شود که در بعضی از موارد دو بازی‌کن نتوانند به یکدیگر متّصل شوند، و در این موارد باید نقش هاست را بازی‌کن دیگری انجام دهد.

نسخه‌ی 6 آیپی (IPv6) با تعداد نشانی‌های بسیار بیشتر از IPv4 به تدریج اینترنت را می‌پوشاند. در این صورت هر دستگاه متّصل به اینترنت یک آیپی منحصر به فرد خواهد داشت و دیگر نیازی به NAT وجود ندارد، و در نتیجه مشکلی در اتّصال نخواهیم داشت.

 

[1] هاست به معنی میزبان می‌باشد.

[2] NAT: Network Address Translation

سیگنال دهی

همان طور که گفته شد یک پیر برای این‌که بتواند به هاست وصل شود باید آیپی آن را پیدا کند و تشخیص دهد که چگونه می‌تواند به آن وصل شود. از طرفی هاست می‌تواند هرکسی باشد، هر جایی روی این کره‌ی خاکی باشد، در نتیجه فهمیدن این‌که پیر به کجا باید وصل شود تقریباً غیر ممکن است. بنابراین برای این‌که بازی‌کن‌ها بتوانند همدیگر را پیدا کنند، یک سرور مرکزی به نام سیگنالینگ سرور (signaling server) ایجاد شده است.

سیگنالینگ سرور هاست اصلی بازی‌ها نیست: اوّلین بازی‌کنی که وارد اتاق بازی می‌شود نقش هاست بازی را دارد و داده‌های بازی را به پیرها می‌رساند. سیگنالینگ سرور فقط یک سرور مرکزی است که بازی‌کن‌ها برای پیدا کردن همدیگر وارد آن می‌شوند. وقتی یک پیر می‌خواهد به هاست ملحق شود، سیگنالینگ سرور اطّلاعاتی مثل نشانی‌های آیپی و جزئیّات اتّصال را دریافت و به دو طرف ارسال می‌کند. اوّلین باری که پیر بتواند با موفّقیّت به هاست متّصل شود، سیگنالینگ سرور دیگر در اتّصال دخالت نمی‌کند و دو طرف به صورت مستقیم با هم ارتباط برقرار می‌کنند.

سیگنالینگ سرور

سیرا در آدرس wss://multiplayer.scirra.com یک سیگنالینگ سرور عمومی را میزبانی می‌کند. (wss پروتکلی برای اتّصال ایمن WebSocket است. چون داده‌های سیگنالینگ از طریق WebSocketها ارسال می‌شوند. خود بازی‌ها با استفاده از WebRTC کار می‌کنند.)

اصطلاحات مربوط به سیگنالینگ

سیگنالینگ سرور نباید بازی‌کن‌های یک بازی را به بازی دیگری که هیچ ربطی به آن ندارد وصل کند، و باید به بازی‌کنان اجازه دهد که در گروه‌های مختلف یک بازی را به صورت همزمان بتوانند بازی کنند، برای این کار بازی‌کن‌ها به یک اتاق (room) در یک نمونه‌ی (instance) بازی ملحق می‌شوند.

سیگنالینگ سرور ابتدا بازی‌کن‌های هر بازی را از بازی دیگر جدا می‌کند. بازی‌تان باید یک نام منحصر به فرد جهانی در سرور داشته باشد تا هر کسی در بازی شما دقیقاً به همان بازی در سیگنالینگ سرور متّصل شود. این کار باعث می‌شود که بازی‌کن‌ها اشتباهی به بازی‌های دیگر نامربوطی که کلاً عملکردشان با بازی شما فرق می‌کند وصل نشوند. برای هر بازی که می‌سازید باید از یک اسم در سیگنالینگ سرور استفاده کنید. برای این‌که اسمی که انتخاب می‌کنید منحصر به فرد باشد در اسم بازی‌تان نام خودتان یا شرکتتان را هم بنویسید. مثلاً اگر اسم بازی‌تان Asteroids است، به جای این‌که در سیگنالینگ سرور اسم بازی‌تان را “Asteroids” خالی بنویسید، بنویسید “MyStudio-Asteroids” یا “JohnSmith-Asteroids” (مثلاً JohnSmith اسم خودتان و MyStudio اسم شرکتتان است). در ضمن این اسمی که انتخاب می‌کنید هیچ جا نمایش داده نمی‌شود و فقط در سیگنالینگ سرور به کار می‌رود، بنابراین به خاطر منحصر به فرد شدن می‌توانید هر جزئیّات دیگری را هم که خواستید به این اسم اضافه کنید و لازم نیست نگران باشید.

بعد سیگنالینگ سرور بازی‌کن‌های نمونه‌های مختلف یک بازی را از هم جدا می‌کند. مثلاً شما بازی‌تان را در یک نمونه‌ی پایدار منتشر کرده‌اید و می‌خواهید بازی‌کن‌ها آن را بازی کنند، و یک نمونه‌ی آزمایشی نیز از بازی‌تان ایجاد کردید تا کسانی که قرار است بازی را تست کنند از آن استفاده کنند و همچنین نمونه‌های دیگری نیز از بازی‌تان ساخته‌اید. این باعث می‌شود که تست‌کنندگان نسخه‌ی آزمایشی به اشتباه به بازی‌کن‌های نسخه‌ی پایدار وصل نشوند. چون شاید نسخه‌ی آزمایشی مکانیزم و خصوصیّاتی متفاوت از نسخه‌ی پایدار داشته باشد. حتّی نسخه‌های بازی هم می‌تواند فرق کند، مثلاً بازی‌کن‌های نسخه‌های v1.0، v1.1، v1.2 و… اشتباهی به یکدیگر وصل نمی‌شوند. حتّی می‌توانید نمونه‌هایی برپایه‌ی مکان زندگی بازی‌کن‌ها داشته باشید، مثلاً بازی‌کنان اروپا، آمریکای شمالی و آسیا هر کدام فقط به بازی‌کن‌های واقع در منطقه‌ی زندگی خودش بتواند وصل شود. این دو می‌توانند با هم ترکیب شوند. یعنی اروپایی‌های نسخه‌ی 1.1 به اروپایی‌های نسخه‌ی 1.2 وصل نمی‌شوند و…

در انتها بازی‌کن‌ها می‌توانند به یک اتاق ملحق شوند. یک اتاق نماینده‌ی گروهی از بازی‌کنان است که دارند با هم بازی می‌کنند. بازی‌کن‌ها نمی‌توانند سایر بازی‌کنانی را که در آن اتاق نیستند مشاهده کنند. اوّلین بازی‌کنی که وارد اتاق شود هاست می‌شود، بعد سیگنالینگ سرور هاست را از ورود هر بازی‌کن دیگری به آن اتاق مطّلع می‌کند. بعد آن‌ها به هم متّصل می‌شوند و شروع به بازی کردن می‌کنند.

در شیء Multiplayer کنستراکت 2، همه‌ی اکشن‌ها، کندیشن‌ها واکسپرشن‌هایی که به سیگنالینگ سرور ربط داشته باشند در یک گروه به اسم Signalling قرار می‌گیرند. بقیّه‌ی آن‌ها به خود بازی‌ها مربوط می‌شوند.

هرج و مرج اینترنت

خوب. همان طور که گفتیم بعد از این‌که سیگنالینگ سرور نقش خود را ایفا کند در بازی دخالتی نخواهد کرد و نقش هاست بازی بر عهده‌ی یکی از بازی‌کنان می‌افتد. پیرها فقط به هاست اطّلاعات می‌فرستند ولی هاست می‌تواند به هرکسی اطّلاعات بفرستد. یعنی اگر مثلاً دو تا پیر بخواهند مستقیماً با هم ارتباط داشته باشند باید از طریق هاست اطّلاعات را به هم بفرستند.

اگر قرار بود بازی چندنفره فقط در یک شبکه‌ی محلّی (LAN) مثل شبکه‌های خانگی یا دفتر کار اجرا شود کار ساخت آن خیلی راحت‌تر بود. امّا اینترنت پدیده‌ای بسیار پیچیده‌تر است. بین دو بازی‌کن اینترنتی می‌تواند حدود 10 تا 20 دستگاه شبکه (مثل مودم و روتر) وجود داشته باشد. دستگاه‌هایی که در طول این مسیر وجود دارند برای هر جفت از بازی‌کنان متفاوت است. برای هر پیام ساده‌ای که فرستاده می‌شود، هر دستگاه واقع در مسیر باید یک بسته از اطّلاعات را دریافت کند، بخواند، بفهمد که چیست و به کجا باید فرستاده شود، و سپس آن را مجدّداً به دستگاه بعدی بفرستد. حالا اگر شما به بازی‌کنی متّصل شوید که آن طرف آب زندگی می‌کند، احتمال آن خیلی زیاد است که اطّلاعات از طریق کابل‌های زیر آبی که معمولاً ترافیک بسیار زیادی دارند منتقل شود.

هرج و مرج اینترنت

هر دستگاه واقع در مسیر به طور عجیبی بسته‌های دریافتی را در طیّ فقط چند هزارم ثانیه[1] به دستگاه بعدی منتقل می‌کنند. امّا به خاطر وجود تعداد زیادی دستگاه در مسیر این زمان افزایش می‌یابد. اگر حتّی یکی از این دستگاه‌ها در طول مسیر دیر بارگیری شود باعث می‌شود زمانی که طول می‌کشد تا اطّلاعات ارسال شوند افزایش یابد. این دستگاه‌ها، مثل هر کامپیوتری ممکن است کرش کنند، با کمبود حافظه مواجه شوند، برای نگهداری خاموش‌شان کنند، برق‌شان برود، در ارائه‌ی خدمات دچار باگ شوند و غیره. به خاطر مهندسی پیشرفته‌ای که در این زمینه انجام شده است، در چنین شرایطی روترها بسته‌های اطّلاعات را دوباره می‌فرستند و دستگاه مشکل دار را دور می‌زنند و یا حتّی آن‌ها را از مسیرهای دیگری به مقصد می‌رسانند. همه‌ی این کارها می‌توانند باعث ایجاد تغییرات موقّتی یا دائمی زمان‌بری در مسیر انتقال اطّلاعات شوند.

اگر یک بازی‌کن از لندن در انگلستان بخواهد با یک بازی‌کن از سیدنی در استرالیا بازی کند، اطّلاعات بازی باید حدود 17000 کیلومتر راه را طی کنند. حالا طبق قوانین فیزیکی اگر در نظر بگیریم اطّلاعات در یک خطّ مستقیم و با سرعت نور ارسال می‌شوند، حدود 57 میلی‌ثانیه طول می‌کشد تا اطّلاعات منتقل شوند. از نظر فیزیکی امکان ارسال اطّلاعات از این سریع‌تر غیر ممکن است. درضمن کابل‌های این مسیر کاملاً در یک خطّ مستقیم قرار ندارند، و در این مسافت بسیار طولانی طبیعتاً دستگاه‌های روتر بسیار بیشتری وجود دارند و زمان خیلی بیشتری صرف می‌شود.

 

[1] از این پس به جای عبارت «هزارم ثانیه» از «میلی‌ثانیه» یا همان ms استفاده می‌کنیم.

کیفیّت اتّصال

برای این‌که کیفیّت اتّصال در اینترنت تعیین شود، اندازه‌گیری‌هایی انجام می‌شود. این اندازه‌گیری‌ها در تعیین کیفیّت روند بازی هم مؤثّرند. این اندازه‌گیری‌ها شامل این موارد می‌شود: latency، packet delay variance (PDV)، packet loss و پهنای باند (bandwidth).

LATENCY

به خاطر دستگاه‌های روتر و قوانین فیزیکی، هر بسته‌ی اطّلاعاتی کمی طول می‌کشد تا به مقصد برسد. به مدّت زمانی که این بسته در راه است Latency و گاهی اوقات زمان پینگ (ping time) گفته می‌شود. این زمان در بین دو بازی‌کن از هر جای جهان که باشند معمولاً بین 20 تا 200 میلی‌ثانیه است، البته گاهی اوقات گزارش شده است که Latency از این هم بیشتر بوده است. در حالت عادی نرخ فریم بازی‌ها 60 فریم بر ثانیه است، یعنی هر فریم حدود 16 میلی‌ثانیه نمایش داده می‌شود. حالا اگر Latency بازی ما 100 میلی‌ثانیه باشد، یک پیغام که می‌خواهد از یکی از بازی‌کنان به دیگری فرستاده شود حدود 6 فریم دیرتر به مقصد می‌رسد، اگر این پیغام جوابی هم لازم داشته باشد این دوبرابر می‌شود، یعنی باز 6 فریم دیگر طول می‌کشد تا جواب به مقصدش برسد.

Latency

در بازی‌های اکشن زمان عکس‌العمل خیلی مهم است. بازی‌کنان حرفه‌ای معمولاً می‌توانند به رویدادهای مختلف بازی در عرض چند صدم ثانیه عکس‌العمل نشان دهند. آن‌ها به این تأخیرها بسیار حسّاس می‌شوند. گلوله‌ای را در نظر بگیرید که با سرعت 500 پیکسل بر ثانیه حرکت می‌کند. این گلوله در مدّت 200 میلی‌ثانیه به اندازه‌ی 100 پیکسل حرکت می‌کند که مسافت آن‌چنان کمی نیست.

Latency باعث به وجود آمدن مشکلات وحشتناکی می‌شود. برای این‌که بازی منصافه باشد، باید همه‌ی بازی‌کنان یک چیز یکسان را ببینند و برای عکس‌العمل نشان دادن به رویدادهای بازی فرصت برابری داشته باشند. در عمل هر بازی‌کنی با یک تأخیر زمانی بازی را انجام می‌دهد و این هاست است که برای اتّفاقات اصلی بازی تصمیم می‌گیرد. با این حال تکنیک‌هایی هستند که برای جبران این تأخیر زمانی استفاده می‌شوند و بازی را منصفانه نگه می‌دارند.

(PACKET DELAY VARIANCE (PDV

مشکل دیگر Latency این است که می‌تواند برای هر پیامی متفاوت باشد. اگر دو پیام از طریق اینترنت ارسال شوند، یکی از آن‌ها می‌تواند در عرض 50 میلی‌ثانیه فرستاده شود، و دومی در عرض 70 میلی‌ثانیه. به این مشکل packet delay variance یا به اختصار پی‌دی‌وی (PDV) گفته می‌شود. در کنستراکت 2 پی‌دی‌وی از تفاضل کمترین Latency از بیشترین Latency به دست می‌آید، در مثالی که الآن زدیم مقدار پی‌دی‌وی 20 میلی‌ثانیه بود. پی‌دی‌وی زیاد از Latency زیاد بدتر است. موتور چندنفره‌ی کنستراکت 2 پیش‌بینی می‌کند که چه قدر طول می‌کشد تا پیام‌ها برسند و سعی می‌کند تا تأخیر پیام‌ها را جبران کند. Latency زیاد و PDV کم یعنی پیش‌بینی‌ها به خوبی عمل می‌کنند و تأخیرها به درستی جبران می‌شوند، در نتیجه روند بازی پایداری داریم. Latency کم و PDV زیاد یعنی پیام‌ها به طور غیر قابل پیش‌بینی دریافت می‌شوند، و اصلاحاتی که موتور چندنفره برای جبران تأخیر انجام می‌دهد، نادرست از آب در می‌آیند، در نتیجه شاهد روند بازی بی‌ثباتی خواهیم بود.

PACKET LOSS

ممکن است پیام‌ها به طور کامل از دست بروند. در حالی که دستگاه‌های روتر نهایت تلاش خود را می‌کنند تا پیام‌ها را عبور دهند، اگر سیلابی از تعداد بسیار زیادی پیام به سمتشان بیاید، حافظه‌ی‌شان کم بیاورد، کرش کنند، برقشان برود و غیره اجازه دارند پیام‌ها را دور بریزند. Packet loss درصد پیام‌هایی است که از دست می‌روند. موتور چندنفره به راحتی می‌تواند بسته‌هایی را که به طور اتّفاقی از دست رفته‌اند جبران کند. امّا اگر packet loss خیلی زیاد باشد، روند بازی دچار مشکل خواهد شد. اگر حجم اطّلاعات روتر بخواهد از فضایی که دارد فراتر برود، بعضی از پیام‌ها پردازش خواهند شد و دوباره فرستاده می‌شوند، و بقیّه‌ی پیام‌ها دور انداخته می‌شوند. پیام‌های کوتاه‌تر فرستاده می‌شوند و پیام‌های بزرگ‌تر از بین می‌روند. اگر روترها این کار را نکنند مشکلاتی برایشان پیش می‌آید که لازم نمی‌بینم در این قسمت درباره‌اش حرفی بزنم.

پهنای باند

پهنای باند به سرعت ارسال اطّلاعات ربط دارد. همه‌ی اتّصالات اینترنتی دارای یک حدّاکثر سرعت دانلود و آپلود هستند، که معمولاً در واحد مگابیت بر ثانیه اندازه‌گیری می‌شود. چون هر یک بایت (B) هشت بیت (b) است، اگر سرعتی بر حسب مگابیت بر ثانیه را به شما بدهند با تقسیم آن بر هشت سرعت را بر حسب مگابایت بر ثانیه به دست خواهید آورد (چون اکثر سیستم‌های نرم افزاری، همچنین کنستراکت 2، اطّلاعات را بر حسب بایت اندازه می‌گیرند نه بیت). مثلاً، یک اتّصال با پهنای باند 40 مگابیت بیت بر ثانیه از نظر علمی در هر ثانیه 5 مگابایت اطّلاعات را انتقال می‌دهد. با این وجود سرعت آپلود می‌تواند فرق داشته باشد، و معمولاً بیشتر مصرف اینترنت صرف دانلود می‌شود و آپلود مصرف کم‌تری دارد.

پهنای باند می‌تواند به عنوان دهانه‌ی بطری برای بازی‌های بزرگ محسوب شود. وقتی تعداد بیشتری پیر به بازی ملحق می‌شود، برای این‌که همه‌ی پیرها به روز باشند هاست مجبور می‌شود حجم بیشتری را آپلود کند. بالأخره هاست مجبور می‌شود با سرعتی اطّلاعات را آپلود کند که سرعت آپلودش اجازه نمی‌دهد، در نتیجه Packet loss رخ خواهد داد. این دلیل دیگری است برای فرستادن پیام‌های کوتاه با پایین‌ترین سرعت قابل قبول، چون این کار استفاده از پهنای باند را به حدّاقل می‌رساند.

مبارزه با شرایط نامطلوب شبکه

برای به حدّاقل رساندن مشکل پهنای باند و packet loss، موتور چندنفره داده‌ها را حدّاکثر تا 30 بار در ثانیه، یعنی نصف نرخ فریم بازی در حالت عادی، انتقال می‌دهد.

برای پیرها

به خاطر این‌که اطّلاعاتی مثل مختصّات اشیاء فریم در میان ارسال می‌شوند، ممکن است بازی تکّه‌تکّه اجرا شود و اشیاء نامنظم حرکت کنند، و مشکلاتی با PDV و packet loss داشته باشیم.

برای بهبود روند بازی، موتور چندنفره بین مقادیر ارسالی را درون‌یابی می‌کند (مقدار بین دو داده‌ی متوالی مثل مختصّات X و Y را حدس می‌زند). این درون‌یابی در مورد مکان اشیاء به صورت خطّی انجام می‌شود. برای مثال در یکی از فریم‌های بازی مختصّات شیء دریافت می‌شود، در فریم بعدی مختصّاتی دریافت نمی‌شود و در فریم بعد از آن مختصّات جدید دریافت می‌شود، در آن فریمی که مختصّاتی دریافت نشد، موتور چندنفره میانگین آن دو مختصّات دیگر را به شیء نسبت می‌دهد. در نتیجه بدون نیاز به هیچ داده‌ی بیشتری باز هم حرکت شیء مورد نظر نرم خواهد بود.

امّا موقع رندر شدن یک فریم درون‌یابی شده، موتور چندنفره هنوز نمی‌داندکه مقدار بعدی چه چیزی است، چون آن مقدار در آینده خواهد رسید! به جای استفاده از ماشین زمان، موتور چند نفره این مشکل را با افزودن یک تأخیر 80 میلی‌ثانیه‌ای برای پیرها مرتفع کرده‌است. این یعنی موتور چندنفره از چند به روز رسانی قبل از این‌که رندر شوند پیشاپیش باخبر است. حتّی اگر به خاطر packet loss به روز رسانی بعدی دریافت نشود، موتور چندنفره از به روزرسانی‌های بعد از آن استفاده کرده و چند فریم را پشت سر هم درون‌یابی می‌کند. حتّی اگر وضعیّت شبکه آن قدر خراب باشد که برای 80 میلی‌ثانیه هیچ به‌روزرسانی‌ای دریافت نشود، موتور چندنفره از 2 به‌روزرسانی قبلی کمک گرفته و شیء را در همان راستا در فریم جدید حرکت می‌دهد. البتّه این یک کار حدسی است، ممکن است در همان زمان شیء مورد نظر ناپدید شده و در مکانی دیگر ظاهر شود، و درون‌یابی اشتباه شود.

برای درون‌یابی مقادیر، موتور چندنفره به شما اجازه می‌دهد تا یکی از سه حالت زیر را انتخاب کنید: خطّی[1] (مثل مختصّات اشیاء)، زاویه‌ای[2] (مثل زاویه‌ی اشیاء)، و هیچ[3] (برای داده‌هایی که نباید درون‌یابی شوند، مثل یک مقدار بولی که نشان می‌دهد آیا لیزر روشن است یا نه)

بی‌ثباتیِ LATENCY

همان‌طور که گفتیم Latency می‌تواند تغییر کند. گاهی اوقات Latency در یک دقیقه‌ی اوّل تدریجاً بهبود می‌یابد یا پس از اتّصال، مسیریابی به تدریج اتّصال را بهینه‌سازی می‌کند و روترها سریع‌ترین مسیر ممکن را تشخیص می‌دهند. Latency به طور ثابت اندازه‌گیری می‌شود تا چنین بی‌ثباتی‌هایی تشخیص داده شوند.

اگر Latency کاهش پیدا کند، موتور چندنفره به طور موقّت بازی را کمی سریع‌تر به جلو پیش می‌برد، زیرا کاهش Latency باعث می‌شود که سریع‌تر وقایع بازی را ببینید. از طرف دیگر، اگر Latency افزایش پیدا کند، سرعت حرکت اشیاء بازی کمی کاهش می‌یابد، زیرا افزایش Latency باعث می‌شود وقایع بازی را دیرتر ببینید. این کار برای جلوگیری از تکّه‌تکّه اجرا شدن بازی و این‌که تأخیر بیش از 80 میلی‌ثانیه باعث حرکت نامنظّم اشیاء نشود، ضروری است. این کارها باید به قدری نرم انجام شوند که تقریباً نامحسوس باشند. این ویژگی‌ها باعث می‌شوند که مطمئن شویم در شرایط مختلف اتّصال بهترین عملکرد را دارا خواهیم بود.

برای هاست

هاست نسخه‌ی معتبر بازی را دارد. چون هاست نمی‌خواهد به خودش اطّلاعاتی ارسال کند، Latency اش صفر است. به عبارت دیگر، هاست در بازی «واقعی» شرکت می‌کند، و پیرها تمام تلاششان را می‌کنند تا بازی را همان طور ببینند که هاست دارد می‌بیند. در نتیجه هاست از مزیّت روند بازی خوب برخوردار است.

شاید فکر کنید که هاست هم نیاز دارد تا بین به‌روزرسانی‌هایی که از پیرها دریافت می‌کند، درون‌یابی کند، ولی در حقیقت چنین چیزی اتّفاق نمی‌افتد، چون پیرها نباید به هاست بگویند که کجا هستند. در حقیقت این هاست است که به پیرها می‌گوید باید کجا باشند. دلیل این کار در قسمت بعدی بیان شده است.

[1] linear

[2] angular

[3] none

جلوگیری از تقلّب

اگر پیرها به هاست بگویند که کجا هستند و دارند چه کاری انجام می‌دهند، و هاست به آن‌ها اعتماد کند، می‌توانند تقلّب کنند. می‌توانند ناگهان اطّلاعاتی ارسال کنند که در طرف دیگر دیوار قرار دارند، یا بگویند پلیری را که در حقیقت به آن نرسیده‌اند زده‌اند، و…. برای کاهش تقلّب، پیرها به هاست فقط ورودی‌هایشان را می‌گویند، ورودی‌هایی مثل این‌که در حال حاضر فلان کلید جهتی را نگه داشته‌اند. هاست این ورودی‌ها را دریافت می‌کند و شروع به حرکت دادن آن پلیر می‌کند، و مکانی که پلیر در آن قرار دارد را به او ارسال می‌کند.

با این کار یک مشکل به وجود می‌آید و آن تأخیر در ورودی‌های پلیرهاست. اگر Latency بازی ما 100ms باشد، و یک پلیر کلید «چپ» را فشار دهد 100ms طول می‌کشد تا این خبر به هاست برسد. بعد 100ms دیگر طول می‌کشد تا هاست پلیر را از مکان جدیدش مطّلع کند، این یعنی همه‌ی کنترل‌های پیر خیلی با تأخیر انجام می‌شوند، کسری از ثانیه طول می‌کشد تا ورودی‌هایی که پیر وارد کرده است عمل کنند. برای حلّ این مشکل بازی‌ای که پیر می‌بیند (بازی محلّی) از پیش‌بینی ورودی محلّی[1] استفاده می‌کند.

پیش‌بینی ورودی محلّی

با فشرده‌شدن کلید چپ توسّط پلیر، پیغامی در این مورد به هاست فرستاده می‌شود، بعد در بازی محلّی، پلیر به سمت چپ حرکت می‌کند، بدون این‌که منتظر تأیید هاست بماند! از آن‌جایی‌که هاست و پیر، هر دو دارند بازی یکسانی را انجام می‌دهند، معمولاً بازی‌شان خیلی زیاد با هم تطابق دارد. حالا کنترل‌های پلیر با تأخیر مواجه نمی‌شوند، والبتّه پیرها هنوز نمی‌توانند تقلّب کنند؛ آن‌ها فقط ورودی‌هایشان را ارسال می‌کنند، و نمی‌توانند وانمود کنند که در جایی دیگر قرار دارند. حتّی اگر بازی محلّی خودشان را هک کنند بی فایده خواهد بود، چون با این کار آن‌ها خودشان را در مکان نادرستی در مقایسه با هاست می‌بینند.

در این صورت بازی‌کن پیر قطعاً خود را در محلّی نمی‌بیند که هاست دارد او را در آن محل می‌بیند. این باعث به وجود آمدن خطاهای کوچک بسیاری از جمله در تنظیم زمان شبکه، هماهنگ‌سازی نرخ فریم، اندازه‌گیری دلتا تایم (t∆) و… می‌شود. البته پیر هنوز پیام‌هایی را از هاست دریافت می‌کند که به او می‌گویند در کجا قرار دارد، امّا این پیام‌ها با تأخیر می‌رسند، در مثال قبلی، دیدیم که این پیام 200 میلی‌ثانیه بعد به پیر می‌رسد. برای تصحیح این مشکلات، موتور چندنفره با استفاده تاریخچه‌ی شیء نگاه می‌کند که شیء مزبور در 200 میلی‌ثانیه پیش در مقایسه با مکان دریافتی از هاست در چه مکانی قرار داشته است. به عبارت دیگر، اصلاحات با توجّه به این‌که شیء در گذشته (با محاسبه‌ی Latency) در چه مکانی قرار داشته است انجام می‌شوند، اگر شیء در مکان نادرستی بود، موتور چندنفره آن را به تدریج حرکت می‌دهد تا در مکان صحیح قرار بگیرد. این کار به آرامی انجام می‌شود تا کمتر به چشم بیاید. ولی در مواردی که اختلاف فاصله خیلی زیاد است، یک اصلاح بزرگ که به چشم بیاید ضروری است.

پیش‌بینی ورودی محلّی

این ویژگی فقط به مکان اشیاء محدود نمی‌شود. موتور چندنفره این توانایی را دارد که تمام این هماهنگ‌سازی‌ها را برای هر متغیّر اینستنسی هم انجام دهد، نه فقط مختصّات X و Y.

LAG

وضعیّت خراب شبکه می‌تواند تأثیرات آشکاری بر روند بازی داشته باشد. گیمرها معمولاً چنین مشکلاتی را به «lag» می‌شناسند. این مشکلات شامل موارد زیر هستند: حرکت ناهموار (وقتی تا 80 میلی‌ثانیه داده‌ها نرسند)، پرش یا ناپیوستگی در روند بازی (وقتی packet loss رخ دهد و باعث شودبه‌روزرسانی مهمّی که وضعیّت بازی را به طور قابل توجّهی تغییر می‌دهد از دست برود)، تغییر مکان ناگهانی بازی‌کن (وقتی پیش‌بینی ورودی محلّی با یک خطای بزرگ مواجه شود)، یا اتّفاقات به ظاهر غیر عادلانه‌ای که پیش می‌آید (این مشکل معمولاً نتیجه‌ی این است که بازی‌کن‌ها بازی را با تأخیرهای مختلفی مشاهده می‌کنند، و هاست به نفع یک پیر خاص تصمیم‌گیری می‌کند).

متأسّفانه راه حلّی برای این‌که همیشه از شرّ این مشکلات خلاص شویم وجود ندارد، مگر این‌که اتّصال اینترنت بهتری پیدا کنیم. این مشکلات معمولاً تحت شرایط سختی از قبیل packet loss کامل به مدّت چند ثانیه، یا تغییرات ناگهانی و شدید در latency یا PDV به وجود می‌آیند. در بعضی مواقع، برای جبران کامل lag استفاده از تکنیک‌های مختلف غیر ممکن است. گاهی اوقات این واقعیّت ارتباط اینترنتی است.

[1] Local input prediction

جبران LAG

مشکل زیر را در نظر بگیرید: بازی‌کن الف ایستاده است و بازی‌کن ب را هدف قرار داده است. بازی‌کن الف موس را دقیقاً روی بازی‌کن ب می‌برد و شلّیک می‌کند. (فرض کنید که تیر مثل عکس زیر درجا برخورد کند، مثلاً لیزر باشد و یا گلوله‌ای با سرعت بی‌نهایت.) در این حین که دارد خبر این شلّیک به هاست می‌رسد (فرض کنید 100 میلی‌ثانیه طول بکشد)، بازی‌کن ب به سمت راست حرکت می‌کند. وقتی خبر شلّیک بعد از 100 میلی‌ثانیه به هاست می‌رسد، هاست بررسی می‌کند که آیا برخوردی صورت گرفته‌است یا نه، امّا برخوردی را تشخیص نمی‌دهد، چون بازی‌کن ب دیگر در آن مکان قرار ندارد! بازی‌کن الف می‌بیند که گلوله‌اش به بازی‌کن ب برخورد کرده است، ولی بازی‌کن ب هیچ صدمه‌ای نمی‌بیند.

در کل به خاطر Latency هر کاری را که بازی‌کن‌ها انجام می‌دهند، هاست یک ذرّه دیرتر می‌بیند، و در نهایت بازی‌کن‌ها اهداف خود را از دست می‌دهند. این نوع مشکلات بازی‌کن‌هایی را که در نهایت یاد می‌گیرند باید فضای خالی جلوی بازی‌کنی که در حال حرکت است را هدف بگیرند، نه خود بازی‌کن را، حسابی عصبانی می‌کند. این تا حدّی واقعی بودن بازی را از بین می‌برد و آن را ناعادلانه می‌کند. جبران Lag تکنیکی است برای جلوگیری از وقوع این نتیجه.

به عقب بردن زمان

هاست می‌داند که چه قدر طول می‌کشد تا هر بازی‌کن بازی را ببیند، زیرا مقدار Latency برای تک تک آن‌ها محاسبه می‌شود. بنابراین وقتی به هاست پیغام می‌رسد که بازی‌کن الف شلّیک کرده است، هاست می‌داند که این شلّیک 100 میلی‌ثانیه قبل اتّفاق افتاده است.

هاست تاریخچه‌ی هر شیء را در چندثانیه‌ی اخیر به یاد دارد. پس می‌تواند نگاه کند که بازی‌کن ب در 100 میلی‌ثانیه‌ی پیش در چه مکانی قرار داشته است. بعد بررسی می‌کند که آیا دقیقاً در همان لحظه‌ی اصلی که شلّیک انجام شد به بازی‌کن ب برخورد کرده است یا نه، و این یعنی مشکل ما برطرف شد.

پیش‌بینی ورودی محلّی

ولی این کار باعث به وجود آمدن یک مشکل دیگر می‌شود. بازی‌کن ب نیز بازی را با تأخیر دریافت می‌کند. یعنی می‌بیند که بازی‌کن الف دقیقاً او را هدف نگرفته‌است و شلّیک می‌کند و به او برخورد می‌کند. در بعضی اوقات وضع بدتر هم می‌شود، مثلاً بازی‌کن ب جایی را پیدا می‌کند و پشت آن پناه می‌گیرد تا بازی‌کن الف نتواند مستقیماً به او شلّیک کند، ولی با شلّیک پلیر الف او آسیب می‌بیند. این موضوع برای بازی‌کن ب آزاردهنده است، ولی هرچه باشد به بدی موقعی نیست که هیچ اصلاحی انجام نشود. لااقل بازی‌کن‌ها برای این‌که بتوانند به هم آسیب برسانند مجبورند مستقیماً یکدیگر را هدف قرار دهند. راه حلّ رایج این مشکل این است که به صورت خیلی دقیق نشان ندهیم که بازی‌کن‌ها کجا را هدف گرفته‌اند، بنابراین بازی‌کن ب به راحتی نمی‌تواند بفهمد که بازی‌کن الف چگونه او را هدف قرار داده است، و برخورد گلوله به او قابل قبول‌تر خواهد بود.

چند بازی‌کن می‌توانند به یک بازی ملحق شوند؟

تعداد بازی‌کن‌هایی که می‌توانند به بازی ملحق شوند به پهنای باند آپلود هاست بستگی دارد. موتور چندنفره محدودیّتی را تحمیل نمی‌کند، ولی در عمل با محدودیّت مواجه خواهیم شد.

مشکل اینجاست که هاست اطّلاعاتی را که از n بازی‌کن دریافت کرده است، می‌خواهد به هرکدام از دیگر بازی‌کن‌ها بفرستد. برای مثال اگر هاست بخواهد 16 بایت داده به هر بازی‌کن ارسال کند، ابتدا باید از هرکدام از بازی‌کن‌ها 16 بایت داده دریافت شود که اگر تعداد بازی‌کن‌ها nتا باشد بایت داده دریافت می‌شود. حالا این داده‌ها قرار است به همه‌ی بازی‌کن‌ها (n بار) ارسال شود، در نتیجه عدد قبلی n برابر شده و هاست باید بایت داده ارسال کند. مثلاً:

10 بازی‌کن = 16×10×10 = 1600 بایت برای هر بروزرسانی
20 بازی‌کن = 16×20×20 = 6400 بایت برای هر بروزرسانی
30 بازی‌کن = 16×30×30 = 14400 بایت برای هر بروزرسانی

100 بازی‌کن = 16×100×100 = 160000 بایت برای هر بروزرسانی

اگرچه تعداد بازی‌کن‌ها معمولی بالا می‌رود، امّا نیاز به پهنای باند به توان2 برابر افزایش می‌یابد. یعنی حتّی با داشتن یک سرور خیلی قدرتمندتر یا داده‌های کم‌حجم‌تری برای هر بازی‌کن، نمی‌توانید تعداد بازی‌کن‌ها را بیش از حد زیاد کنید.

به طور پیش‌فرض به‌روزرسانی‌ها 30 بار در یک ثانیه ارسال می‌شوند، پس در مثال قبل با 100 بازی‌کن، عملاً هاست باید دارای پهنای باندی در حدود 5 مگابایت بر ثانیه (یا 40 مگابیت بر ثانیه) باشد. این مقدار برای یک اینترنت خانگی بسیار زیاد است، امّا برای یک سرور اختصاصی خیر.

گذشته از این، هاست باید بتواند بازی را برای تعداد زیادی بازی‌کن اجرا کند و وظایفی مثل جبران lag و بررسی‌های برخورد را انجام دهد که باعث می‌شود شدیداً از CPU استفاده شود. درضمن اگر هاست یکی از بازی‌کن‌ها باشد، بازی باید برایش رندر هم بشود. معمولاً مقدار کلّ کاری که باید CPU انجام دهد با افزایش تعداد بازی‌کن‌ها به سرعت زیاد می‌شود، اگرچه حدّاکثر تعداد بازی‌کن‌ها بسته به نوع بازی و اتّصال اینترنت متفاوت است، ولی تقریباً پیوستن بیش از 100 بازی‌کن به بازی غیر ممکن است.

تنظیم فرمت به‌روزرسانی‌ها

این امکان وجود دارد که نوع دقیق مقادیری را که می‌خواهید موتور چندنفره آن‌ها را منتقل کند تعیین کنید. استفاده‌ی صحیح از این ویژگی باعث می‌شود نیاز کمتری به پهنای باند داشته باشیم، بدون این‌که تغییر خاصّی در روند بازی رخ دهد، و حتّی حدّاکثر تعداد بازی‌کن‌هایی که به بازی ملحق می‌شوند را افزایش دهیم.

اگر با بیت (bit)، بایت (byte) و باینری (binary) آشنایی ندارید، می‌توانید مقاله‌های بایت و باینری را در ویکی‌پدیا مطالعه کنید و یا در این باره در گوگل جستجو کنید. به طور خلاصه، در کامپیوتر تمام اعداد در مبنای 2 (دستگاه باینری) نگه‌داشته می‌شوند: در این مبنا هر رقم فقط می‌تواند 0 و یا 1 باشد. یک بایت 8 بیت است، پس می‌تواند 28(256) مقدار مختلف داشته باشد، یا مقداری از 0 تا 255. بایت‌های بیشتر می‌توانند محدوده‌ی وسیع‌تری از اعداد را در خود نگه دارند. بعضی از انواع اعداد اعشاری مثل 0.3 حدّاقل 4 بایت را اشغال می‌کنند.

نوع مقادیری که در کانستراکت 2 می‌توانید استفاده کنید به شرح زیر است:

High﴿ double، هشت بایت): یک عدد double-precision floating-point که می‌تواند اعداد اعشاری را با دقّت زیاد در حدود 15 تا 17 رقم اعشار در خود نگه‌دارد. ولی به تنهایی برای یک عدد 8 بایت حجم می‌گیرد، که می‌تواند استفاده از پهنای باند را بی‌خودی افزایش دهد. در عمل انتخاب این نوع مقدار بعید است، مگر در مواقعی که واقعاً ضروری باشد.

Normal﴿ float، چهار بایت): یک عدد single-precision floating-point که می‌تواند اعداد اعشاری را با دقّت حدود 6 تا 9 رقم اعشار را در خود نگه دارد. یعنی بعضی از اعداد به اعدادی با تعداد اعشار کم‌تر گرد می‌شوند. با این‌حال در عمل استفاده از این نوع مقدار به صرفه‌تر از double است، چون حجمی نصف double دارد و ارقام اعشاری بعد از رقم ششم معمولاً اهمّیّتی ندارند (مثلاً 0.333333 به اندازه‌ی کافی دقیق هست و واقعاً نیازی به 0.333333333333333 نداریم.)

Low﴿ int16، دو بایت): یک عدد صحیح 16 بیتی که فقط می‌تواند در محدوده‌ی 32768- تا 32767 قرار داشته باشد.

Very low﴿ uint8، یک بایت): یک عدد حسابی 8 بیتی که فقط می‌تواند در محدوده‌ی 0 تا 255 قرار داشته باشد.

برای کاهش میزان مصرف پهنای باند، باید تا حدّ امکان کم‌ترین دقّتی را که اثر مهمّی در روند بازی ایجاد نکند انتخاب کنیم. مثلاً برای مختصّات X و Y دقّت نوع low﴿ int16) مناسب است. زیرا معمولاً اندازه‌ی لیوت بیشتر از 3267×3267 نیست، و اعشارِ مختصّات پیکسل‌ها اثری در روند بازی ندارد. این دقّت کاملاً کافی است و نسبت به double چهاربرابر کم‌تر از پهنای باند استفاده می‌کند.

دقّت low﴿ int16) و Very low﴿ uint8) برای ورودی‌هایی که پیرها وارد می‌کنند و به هاست فرستاده می‌شود مفید است. با استفاده از اکسپرشن‌های setbit، getbit و togglebit در کانستراکت 2 می‌توانید بیت‌هایی جداگانه را در این اعداد قرار دهید. اگر یک بازی از 4 کلید جهتی برای حرکت و از Space برای شلّیک استفاده کند، فقط 5 ورودی وجود دارد، که همه‌اش می‌تواند در یک 8 بیت ذخیره شود با این حساب که صفر نشان دهنده‌ی این است که کلید مورد نظر در حال فشار داده شدن نیست و یک نشان‌دهنده‌ی این است که کلید مورد نظر دارد فشار داده می‌شود. بعد هاست می‌تواند به هرکدام از بیت‌ها نگاه کند و ورودی مناسب با آن را شبیه‌سازی کند. همه‌ی این‌ها فقط یک بایت حجم می‌گیرند. اگر شما بیشتر از 8 ورودی دارید می‌توانید از یک مقدار int16 استفاده کنید، با این‌کار در استفاده از پهنای باند خیلی صرفه‌جویی می‌کنید. به طریق مشابه، هاست هم می‌تواند چندین حالت روشن/خاموش[1] را در قالب یک مقدار به پیرها بفرستد.

[1] منظور چیزهایی در بازی هست که نمی‌توانند بیش از دو حالت داشته باشند

پلاگین MULTIPLAYER در کانستراکت ۲

طرّاحی کلّی یک بازی چندنفره در کانستراکت 2 چیزی شبیه این است.

روند یک بازی چندنفره

چرخه‌ی یک بازی چندنفره شبیه زیر است.

  1. اتّصال به سیگنالینگ سرور و ورود به آن
  2. پیوستن به یک روم
  3. در طول بازی پیرهای دیگر می‌توانند به بازی بپیوندند یا از آن خارج شوند.
  4. اطّلاعات اشیاء مختلف و پیام‌های دیگری مثل چت بین پیرهای متّصل‌شده رد و بدل می‌شود.
  5. سرانجام بعد از اتمام بازی، همه روم را ترک می‌کنند، و شاید وارد یک روم دیگر شوند (برگشت به گام 2)

توجّه کنید که اگر اتّصال هاست قطع شود، بازی تمام می‌شود. چون هاست به منزله‌ی سرور بازی عمل می‌کند با قطع شدن اتّصال آن بازی نمی‌تواند ادامه پیدا کند. به همین دلیل بازی‌های چندنفره‌ی آنلاین، مخصوصاً بازی‌های بزرگ با تعداد بازی‌کن زیاد، معمولاً در هاست اختصاصی روی یک سرور مرکزی اجرا می‌شوند. امّا این مشکل برای بازی‌های دونفره وجود ندارد، زیرا هرکدام از دو بازی‌کن که اتّصال‌شان قطع شود بازی خاتمه می‌یابد.

پلاگین Multiplayer دارای ویژگی‌هایی است که مرحله‌ی سیگنال‌دهی را انجام می‌دهد (گام‌های 1 و 2)، و نیز ویژگی‌های «room» روند بازی را پوشش می‌دهند، مثلاً وقتی پیرها بازی را ترک ‌کنند، به بازی ملحق شوند، پیامی دریافت شود و… به ما خبر می‌دهند.

طرّاحی کلّی

این طور در نظر ‌گرفته شده است بازی‌ها طوری طرّاحی شده اند که یک آبجکت‌تایپ داریم که نماینده‌ی اشیاء تحت کنترل بازی‌کن‌هاست. حالا این شیء توسّط تمام بازی‌کن‌ها به طور یکسان استفاده می‌شود که شامل شما نیز می‌شود (حتّی وقتی هاست هستید). عاقلانه است اسم این شیء را ‍Peer بگذارید، زیرا این شیء نماینده‌ی پیرها می‌باشد. اگر بازی‌کن‌های شما از ترکیب چند شیء ساخته شده‌اند، مثلاً از ترکیب یک اسلحه و یک بدن جدا، یکی را به عنوان شیء Peer اصلی در نظر بگیرید و آن را با سایر اشیاء مربوطه در یک کانتینر (Container) قرار دهید، این کار باعث می‌شود مطمئن شوید بازی‌کن شما به صورت کامل به وجود می‌آید و یا نابود می‌شود، و اشیاء مربوط به آن به صورت خودکار به شیء اصلی می‌چسبند، بنابراین تا حدّ زیادی می‌توانید شیء اصلی را به عنوان نماینده‌ی کلّ آن بازی‌کن تلقّی کنید.

هاست و پیرها همه پروژه‌ی یکسانی را اجرا می‌کنند. یعنی همان یک پروژه‌ی شما باید بتواند هم با ایونت‌های مربوط به هاستی سروکار داشته‌باشد که نسخه‌ی معتبر و اصلی را بازی می‌کند، و هم با ایونت‌های مربوط به پیرهایی که نسخه‌ی تأخیردار را بازی می‌کنند و فقط ورودی‌هایشان را ارسال می‌کنند. راحت‌ترین روش برای این کار این است که دو ایونت گروپ یکی مختصّ هاست و یکی مختصّ پیرها داشته باشیم، و بعد از ملحق شدن به بازی و تشخیص این‌که آیا هاست شدیم یا پیر، فقط ایونت گروپ مناسب را فعّال کنیم.

اکشن Sync object شیء Multiplayer راه اصلی نشان‌دادنِ این است که می‌خواهید داده‌هایی در مورد شیئی خاص را از طریق شبکه ارسال کنید. این اکشن به هاست می‌گوید که اطّلاعات مربوط به آن اشیاء را به همه‌ی پیرها ارسال کند، و به پیرها می‌گوید تا منتظر اطّلاعات مربوط به آن اشیاء بمانند. وقتی پیرها به بازی ملحق می‌شوند و یا آن را ترک می‌کنند، موتور چندنفره به صورت خودکار اشیائی را که نماینده‌ی آن پیرها هستند به وجود می‌آورد و یا حذف می‌کند. (اکشن Sync object می‌تواند برای اشیائی که نماینده‌ی هیچ پیری نیستند هم به کار رود، ولی بیشتر برای پیرها استفاده می‌شود)

هر پیر شناسه‌ای منحصر به فرد دارد که از سیگنالینگ سرور دریافت کرده است، این شناسه که Peer ID نامیده می‌شود یک رشته است که در انتهای آن تعدادی کاراکتر تصادفی برای منحصر به فرد شدن اضافه شده است. به طور کلّی این شناسه‌ها برای این به کار می‌روند بتوانیم به طور مداوم به بازی‌کنی خاص اشاره داشته باشیم، حتّی اگر نام مستعار خود را در بازی تغییر دهد. Peer ID باید در یک متغیّر اینستنس ذخیره شود تا بدانید کدام شیء نماینده‌ی پیر مورد نظر است. وقتی موتور چندنفره شیئی را برای یک بازی‌کن به وجود آورد مقدار اکسپرشن Multiplayer.PeerID به Peer ID آن شیء تغییر می‌کند، بنابراین این مقدار می‌تواند در یک متغیّر اینستنس مربوط به همان شیء ذخیره شود. برای این‌که شما فقط شیء پیر مربوط به خودتان را کنترل کنید به راحتی می‌توانید با بررسی این‌که آیا مقدار آن متغیّر اینستنس با اکسپرشن Multiplayer.MyID[1] برابر است یا نه این کار را انجام دهید.

حالت‌های معتبر

3 حالت برای انتقال اطّلاعات وجود دارد.

مطمئن‌ترین حالت Reliable ordered است. در این حالت یک پیام به صورت زنجیروار فرستاده می‌شود: اگر این پیام در بین راه به هر دلیلی از بین برود، مجدّداً فرستاده می‌شود تا وقتی‌که اطمینان حاصل شود پیام به مقصد رسیده است. در این حالت ترتیب پیام‌ها نیز رعایت می‌شود، بنابراین پیام‌ها دقیقاً به همان ترتیبی که ارسال شده‌اند به مقصد می‌رسند. این خیلی مفید است، ولی سریع‌ترین حالت نیست: اگر یک پیام در بین راه از بین برود، مانع ارسال همه‌ی پیام‌های بعدی می‌شود تا این‌که به مقصد برسد. یعنی یک پیام تنها ممکن است Latency را چندین برابر آن چیزی که باید باشد بکند زیرا حدّاقل به اندازه‌ی یک زمان رفت و برگشت باید صبر کند تا بداند پیام رسیده‌است یا نه. به طور کلّی این حالت فقط مناسب پیام‌های کم‌بسامد مثل پیام‌های چت است.

حالت بعدی Reliable unordered است. در این حالت یک پیام به صورت زنجیروار آن‌قدر فرستاده می‌شود تا مطمئن شود به مقصد رسیده است. ولی ترتیب پیام‌ها در این حالت مهم نیست، این باعث می‌شود وقتی یک پیام در بین راه از بین می‌رود و مجدّداً فرستاده می‌شود پیام‌های بعدی را پشت سرش نگه ندارد، در این موقع این پیام بعد از پیام‌هایی به مقصد می‌رسد که دیرتر از آن ارسال شده‌اند. با این حال Latency برای رسیدن همان یک پیام هنوز هم چند برابر می‌شود. این حالت برای رویدادهای روند بازی که ربطی به هم نداشته باشند مناسب است، مثل دری که باز می‌شود یا انفجاری که رخ می‌دهد.

سریع‌ترین حالت Unreliable است. در این حالت پیام فرستاده می‌شود و پیگیری هم نمی‌شود. اگر پیام در بین راه از بین برود هیچگاه به مقصد نمی‌رسد. در این حالت نیز مثل حالت قبل ترتیب پیام‌ها مهم نیست. معمولاً این حالت برای پیام‌های عادی مناسب است که می‌خواهید هرچه سریع‌تر به مقصد برسند و یا اگر قرار است دیر برسند بهتر است اصلاً نرسند. اگر یکی از این پیام‌ها در بین راه از بین برود، پیام بعدی با داده‌ای جدیدتر به سرعت به مقصد می‌رسد، بنابراین پیام از دست رفته آنچنان مهم نیست. موتور چند نفره برای اشیائی که Sync object شده اند و ویژگی‌های درون‌یابی و جبران از این حالت استفاده می‌کند. پس سعی نکنید دوباره روی این حالت تنظیمشان کنید.

آماده برای رفتن!

با این‌که پلاگین Multiplayer کانستراکت 2 تعداد زیادی از جزئیّات فنّی مثل پیش‌بینی ورودی و اتّصال را برای شما انجام می‌دهد، باز هم خیلی مهم است که تئوری را هم بلد باشید تا بتوانید با توجّه به این‌که چه داده‌ای با چه دقّتی و از چه حالت معتبری فرستاده می‌شود انتخاب‌های مناسبی انجام دهید. امیدوارم این آموزش به اندازه‌ی کافی یک نمای کلّی به شما داده باشد تا شروع کنید به ساخت اوّلین بازی چندنفره‌تان، با اطّلاع از این‌که پشت صحنه چه اتّفاقاتی دارد می‌افتد و شما باید چه کارهایی را انجام دهید تا بهترین استفاده را از ویژگی‌های چندنفره‌ی کانستراکت 2 بکنید. با این‌که این آموزش روی تئوری تمرکز داشت، آموزش‌های بعدی در عمل چگونگی رسیدگی به مسائلی از قبیل پیش‌بینی ورودی و جبران lag را با استفاده از ویژگی‌های خاص پلاگین Multiplayer پوشش می‌دهند.

[1] این اکسپرشن Peer ID شما را برمی‌گرداند

منبع : si2.ir