يمكنك أن تتذكر
ألكساندر كوروتاييف في إصدار متصفح "أبطال القوة والسحر":
فك تشفير تقريره عنها جمع قدرًا هائلاً من الآراء حول حبري. وقد صنع الآن لعبة تركز على المبرمجين: تحتاج إلى تشغيلها برمز JS.
هذه المرة ، لم يستغرق التطوير أسابيع ، بل أسابيع ، لكن بدون تحديات مثيرة على أي حال ، لم يكن من الممكن القيام به. كيف تجعل اللعبة مريحة حتى بالنسبة للمطورين الذين لم يسبق لهم لمس JavaScript؟ كيف تحمي نفسك من طرق بسيطة للتغلب على اللعبة؟

نتيجة لذلك ، قدم ألكساندر مرة أخرى تقريرًا عن HolyJS ، وقمنا (منظمو المؤتمر) مرة أخرى بإعداد نسخة نصية لـ Habr.
اسمي ألكسندر كوروتاييف ، أعمل في Tinkoff.ru ، أنا منخرط في الواجهة الأمامية. بالإضافة إلى ذلك ، كجزء من مجتمع Spb-frontend ، أساعد في تنظيم عمليات mitaps. أقوم بإنتاج بودكاست Drinkc ، ندعو الأشخاص المثيرين للاهتمام ومناقشة مختلف الموضوعات.
ما هو جوهر اللعبة؟ أولاً ، تحتاج إلى اختيار وحدة من الوحدات المقترحة ، وهذا نظام RPG: لكل وحدة نقاط القوة والضعف الخاصة بها. ترى الوحدات التي اختارها العدو ، واختر الانتقام منه. ثم عليك أن تكتب في JavaScript نصًا لسلوك جيشك - وبعبارة أخرى ، النص "ما يجب أن تفعله كل وحدة في ساحة المعركة".
يتم ذلك في وضع التصحيح: في الواقع ، تقوم بخصم الكود ، ثم يقوم كلا الخصمين بدفع الكود الخاص بهم ، وتبدأ المعركة بين الجانبين.
وبالتالي ، يمكنك أن ترى كيف أن مخطوطين ، منطقين ، خوارزميات تقاتلان بعضهما البعض. أردت دائمًا أن أفعل شيئًا كهذا ، والآن يتم تنفيذه أخيرًا.
في العمل ، يبدو كل شيء كما يلي:
وما شكل العمل عليه؟ ذهب الكثير من العمل في الوثائق. عندما يجلس المشغل على الكمبيوتر المحمول ، يرى الوثائق ، التي يتم وصف كل شيء فيها ببعض التفاصيل.
استغرق مني الكثير من الوقت لتخطيطه ومراجعته واستجوابه بين الناس عما إذا كان الأمر واضحًا. ونتيجة لذلك ، اتضح بشكل واضح لـ sishnikov و javists والمطورين الآخرين الذين لا يعرفون شيئًا عن JS. يمكنك أيضًا ترقية JavaScript باستخدام هذه اللعبة: "إنها ليست مخيفة ، انظر كيف يمكنك الكتابة عليها ، حتى يحدث شيء ممتع."

كانت لدينا بطولة كبيرة في شركتنا ، شارك فيها أي مبرمجين تقريبًا.
من التكنولوجيا ، استخدمت محرك اللعبة الأكثر شعبية من عالم JS - Phaser. أكبر وأكثرها استخداما محرر الآس. هذا محرر على شبكة الإنترنت ، يشبه إلى حد كبير Sublime أو VSCode ، ويمكن تضمينه في صفحة ويب. كما أنني استخدمت RxJS للعمل مع التفاعلات غير المتزامنة من مختلف المستخدمين و Preact لتقديم HTML. من التقنيات المحلية ، كان يعمل بشكل خاص مع العمال و websocket.

ألعاب للمبرمجين
ما هي الألعاب للمبرمجين بشكل عام؟ في رأيي ، هذه ألعاب تحتاج إلى الكود فيها ، ثم تحصل على نتيجة مضحكة يمكن مقارنتها بشخص ما ، فهذه معركة. من بين هذه الألعاب المتوفرة عبر الإنترنت ، أعرف
"Elevator Saga" - تكتب نصوصًا للمصاعد وفقًا لمعايير معينة.
"Screeps" - حول البيولوجيا ، الجزيئات ، تكتب نصوصاً لهم.
هناك أيضًا ألعاب يتم عرضها أحيانًا في المؤتمرات. الأكثر شعبية منهم هو "Code in the Dark" ، وقد قدمناها أيضًا اليوم. بالمناسبة ، "الكود في الظلام" ألهمني بطريقة ما.

لماذا تم ذلك؟ لقد حصلت على المهمة التي تحتاجها للتوصل إلى شيء رائع بموقف في المؤتمر ، شيء غير عادي. لا أن هناك eychars مع الاستبيانات. من الواضح أن الجميع يريدون جذب الانتباه وجمع جهات الاتصال. قررنا الذهاب أبعد من ذلك وتوصلنا إلى شيء رائع وممتع للمبرمجين. أدركت أن المبرمجين يريدون القتال والتنافس ، ونحن بحاجة إلى منحهم مثل هذه الفرصة. من الضروري إنشاء موقف سيأتون إليه وسوف يرمزون إليه.
Gamification لقد فعلنا هذا ليس فقط بين المبرمجين الممارسين ، ولكن أيضًا بين الطلاب. عقدنا مثل هذه المباريات في المعاهد في يوم المهنة. كنا بحاجة إلى أن نرى بطريقة أو بأخرى أي نوع من اللاعبين كانوا مناسبين لنا أم لا. استخدمنا gamification لجذب الناس إلى العملية ، لنرى كيف يتصرفون ، ماذا يفعلون. لقد لعبوا وتم صرف انتباههم ، لكن ذلك أعطانا معلومات. دفع البعض الشفرة دون تشغيلها مرة واحدة ، وكان من الواضح على الفور أنه من المبكر جدًا التطوير.

كيف بدا في الإصدار الأول. كانت شاشة رئيسية وجهازي كمبيوتر محمول للاعبين. كل هذا اتصل بالخادم ، وقام الخادم بتخزين الحالة وتفتيشها بين جميع العملاء المتصلين. كانت كل شاشة عميل متصل. أجهزة الكمبيوتر المحمولة للاعبين عبارة عن شاشات تفاعلية يمكن تغيير هذه الحالة منها. يتم ربط الشاشات بشكل صارم بخادم واحد.
قصة ضيق الوقت
القصة الأولى التي صادفتها في هذا التطور هي القصة التي كان لدي القليل من الوقت فيها. في غضون خمس دقائق حرفيًا ، ظهرت فكرة ، في خمس ثوان تم اختراع اسم عندما كان مطلوبًا لإنشاء
مستودع على GitHub. يمكن أن أقضي كل ذلك أربع ساعات فقط في المساء ، وأخذهم بعيداً عن زوجتي. ونتيجة لذلك ، كان أمامي ثلاثة أسابيع فقط قبل المؤتمر لإدراك ذلك بطريقة أو بأخرى على الأقل. بدأ كل شيء بحيث كان من الضروري للتوصل إلى فكرة في إطار العصف الذهني ، في خمس دقائق ولدت الفكرة: "هيا نكتب نوعًا من الذكاء الاصطناعي لـ RPG في JS". إنه رائع ، ممتع ، يمكنني تنفيذه.

في التطبيق الأول ، كان للشاشة محرر كود وشاشة معركة ، كانت المعركة نفسها عليها. تم استخدام Phaser و Ace Editor و Node.js الخالص كخادم بدون أي أطر عمل. ما أسفه لاحقًا ، لكن لا شيء خاص كان مطلوبًا من الخادم.

تمكنت من إدراك Renderer الذي رسم المعركة بنفسه. كان الجزء الأكثر صعوبة هو صندوق الرمل لرمز JS ، أي صندوق رمل كان من المفترض أن يتم فيه تنفيذ كل شيء بمعزل عن كل لاعب. كان هناك أيضا تقاسم الدولة التي جاءت من الخادم. أرسل اللاعبون حالة تغيير بطريقة ما ، وألقوا على الخادم ، أرسل الباقي إلى مآخذ الويب. كان الخادم مصدرًا للحقيقة ، وقد وثق جميع العملاء المتصلين بما جاء من الخادم.
صندوق الرمل
ما هو الصعب للغاية لتنفيذ رمل؟ والحقيقة هي أن رمل هو العالم كله للرمز الذي يجب أن يكون رمز موجود. وهذا يعني أنك تصنع له نفس العالم كما هو حوله ، ولكن يتكون فقط من بعض الاتفاقيات ، من واجهة برمجة تطبيقات يمكنك التفاعل معها. كيفية تنفيذ هذا على JS؟ يبدو أن JS غير قادر على ذلك ، فهو مليء بالثقوب ومجاني لدرجة أنه لا يعمل على إحاطة رمز المستخدم بالكامل في صندوق دون استخدام جهاز افتراضي منفصل مع نظام تشغيل منفصل.

ماذا يجب أن تفعل رمل؟
أولاً ، كما قلت ، قم بعزل الكود. يجب أن يكون عالما لا يمكن للمرء الخروج منه.
أيضا ، يجب أن يتم طرح API إدارة وحدة هناك. يجب أن يتفاعل اللاعبون مع ساحة المعركة ، ونقل الوحدات ، وتوجيههم ، ومنحهم ناقل هجوم.
وأية إجراءات من وحدات غير متزامن ، وهذا هو ، يجب أن تعمل بطريقة أو بأخرى مع رمز غير متزامن.

ماذا أردت أن أقول عن عدم التزامن؟ والحقيقة هي أنه في JS يتم تنفيذه أساسا باستخدام الوعود. كل شيء واضح للجميع هنا ، والوعود شيء عظيم ، فهي تعمل بشكل مثالي ، وكنا دائمًا معنا. لسنوات عديدة ، يعرف الجميع كيفية العمل معهم ، ولكن هذه اللعبة لم تكن مخصصة فقط لجافا سكريبت. تخيل لو بدأت في شرح للجاويين كيفية كتابة رمز معركة باستخدام الوعود؟ كيف نفعل بعد ذلك ، ثم ، لماذا لا يكون ذلك ضروريًا في بعض الأحيان ... ماذا تفعل بالظروف أو الحلقات؟

يمكنك ، بالطبع ، أن تذهب بأفضل طريقة وأن تأخذ بناء جملة async / await. [Slide 8:57] ولكن هل يمكنك أيضًا أن تتخيل كيف يمكن لمبرمجي برامج الجافا سكريبت توضيح أنك بحاجة إلى الانتظار قبل كل سطر تقريبًا؟ نتيجة لذلك ، فإن أفضل طريقة للتعامل مع عدم التزامن هي عدم استخدامه على الإطلاق.

اصنع الرمز الأكثر تزامنًا وواجهة برمجة التطبيقات البسيطة ، على غرار أي لغة برمجة تقريبًا. نحن نصنع لعبة ، ليس فقط للأشخاص الذين يكتبون في JS ، بل نريد أن نجعلها في متناول الجميع الذين يعرفون كيفية الشفرة.

نحن جميعا بحاجة لبدء بطريقة ما. يكتب المستخدم الكود ، ونحن بحاجة إلى تنفيذه ، انقل الوحدات على الخريطة. أول ما يتبادر إلى الذهن هو أننا نحتاج إلى eval () بالإضافة إلى العبارة غير الموصى بها مع العبارة ، والتي
لا يوصى باستخدامها على MDN . هذا سوف يعمل ، ولكن هناك مشاكل.

على سبيل المثال ، لدينا كود يدمر تمامًا فكرتنا بالكامل ، مما يمنعنا من القيام بأي شيء آخر. هذا هو الرمز الذي يمنع التنفيذ. يجب القيام بشيء ما حتى لا يتمكن المستخدم من حظر التطبيق. على سبيل المثال ، يمكن حلقة لا نهاية لها كسر كل شيء. إذا كان لا يزال من الممكن إعادة تعريف التنبيه () والموجه () ، فلا يمكننا إعادة تعريف حلقة لا نهائية على الإطلاق.
eval () هو الشر
لذلك نصل إلى النقطة التي يكون فيها eval () شريرًا. لا يسمونه شرًا لأنه لا شيء ، لأنه وظيفة خبيثة تدمج فعليًا كل ما هو أكثر حرية وانفتاحًا في JS ، ولا تتركنا أعزل تمامًا. من خلال وظيفة واحدة بسيطة ، نقوم بعمل ثقب كبير في تطبيقنا.

ولكن ماذا لو قلت لك ،
[في صوت ستيف جوبز] أننا اخترعنا eval ()؟
لقد فعلنا eval () في التقنيات الأخرى ، وهو يعمل بنفس الطريقة تقريبًا مثل eval () التي لدينا بالفعل. في الحقيقة ، لديّ وظيفة eval () في الكود الخاص بي ، لكن تم تنفيذها باستخدام Workers ، the with statement ، و Proxy.

لماذا العمال؟ الحقيقة هي أنهم ينشئون سلسلة منفصلة من التنفيذ ، أي أن JS هي ذات سلسلة واحدة ، لكن بفضل العمال يمكننا الحصول على سلسلة أخرى. هذا يعطينا العديد من الفوائد. على سبيل المثال ، ضمن نفس الحلقات التي لا نهاية لها ، يمكننا مقاطعة الخيط الذي تم إنشاؤه من خلال العامل من الخيط الرئيسي ، وربما هذا هو السبب الرئيسي لاستخدام العمال. إذا تمكن العامل من العمل بشكل أسرع من ثانية واحدة ، فإننا نعتبره ناجحًا ، ونحصل على النتيجة. إذا لم يكن الأمر كذلك ، فإننا نقطعها. في الواقع ، لم يعمل رمز المستخدم لسبب ما ، حدثت بعض الأخطاء الغريبة ، أو تم إبطائه بسبب حلقة لا نهائية. لقد حاول الكثيرون اليوم الكتابة بينما (صحيح) ، وحذرت من أن هذا لن ينجح.

لكتابة عاملنا ، نحتاج فقط إلى تغذية البرنامج النصي إلى المنشئ العامل ، والذي سيتم تنزيله عبر http. داخل البرنامج النصي ، نحتاج إلى إنشاء معالج رسائل من سلسلة الرسائل الرئيسية. باستخدام وظيفة postMessage () داخل العامل ، يمكننا توجيه الرسائل إلى سلسلة الرسائل الرئيسية. بهذه الطريقة نجعل التواصل بين الخيطين. واجهة برمجة تطبيقات بسيطة مريحة إلى حد ما ، ولكن هناك شيء ما مفقود فيها ، وهو رمز المستخدم الذي يجب علينا تنفيذه في هذا العامل. لن نقوم في كل مرة بإنشاء ملف نصي على الخادم وإطعامه للعامل.

لقد وجدت طريقة لاستخدام URL.createObjectURL (). نجعل كتلة وإطعامها إلى عامل src. وبالتالي ، فإنه يفرغ رمز لدينا مباشرة من الخط. بالمناسبة ، تعمل هذه الطريقة مع أي كائنات في DOM لها src - تعمل الصورة مثل هذا ، على سبيل المثال ، وحتى في iframe يمكنك تحميل html فقط عن طريق توليده من سلسلة. رائع جدا ومرنة ، على ما أعتقد. يمكننا أيضًا إدارة العامل عن طريق تمريره ببساطة كائننا الذي تم إنشاؤه خصيصًا من عنوان URL. يمكننا أيضًا إنهائه ويعمل بالفعل حسب حاجتنا ، وأنشأنا أول صندوق رمل.

تتواصل التفاعلات غير المتزامنة إلى أبعد من ذلك ، لأن أي عمل مع العمال غير متزامن. لقد أرسلنا بعض الرسائل ، ولا يمكننا الانتظار بشكل متزامن للرسالة التالية ، حيث يقوم العامل بإرجاع المثال إلينا ، ويمكننا الاشتراك في الرسائل. نحصل على الرسالة باستخدام RxJS ، نقوم بإنشاء خيطين: واحد للرسالة الناجحة من العامل ، والثاني للإنجاز بحلول المهلة. اثنين من المواضيع التي نتحكم بعد ذلك مع دمجها.

لدى RxJS عوامل تشغيل تسمح لنا بالعمل مع سلاسل الرسائل. في الواقع ، هو مثل lodash لعمليات متزامنة. يمكننا الإشارة إلى بعض الوظائف وعدم التفكير في كيفية تنفيذها في الداخل ، فهو يخفف من الصداع. نحتاج إلى البدء في التفكير في مؤشرات الترابط ، ويدمج عامل الدمج مؤشرات الترابط الخاصة بنا ، ويستجيب لأي رسالة. سوف تستجيب لكل من المهلة والرسالة. نحتاج إلى الرسالة الأولى فقط ، على التوالي ، بعد الرسالة الأولى التي ننهي العامل. في حالة وجود خطأ ، اطبع هذا الخطأ ؛ في حالة النجاح ، نحل المشكلة.

كل شيء بسيط جدا هنا. يصبح لدينا كود التعريفي ، وتعقيد عدم التزامن يذهب إلى مكان ما. الشيء الرئيسي هو تعلم هؤلاء المشغلين.

هذه هي الطريقة التي نعمل بها مع وحدة واجهة برمجة التطبيقات. أردت أن تكون وحدة واجهة برمجة التطبيقات بسيطة قدر الإمكان. عند الحديث عن JS ، يعتقد الكثير من الناس أنه من الصعب ، عليك الصعود إلى مكان ما ، وتعلم شيء ما. وأردت أن أبسط الأمر قدر الإمكان: كل شيء في المنطقة العالمية ، لا يوجد سوى نطاق واجهة برمجة تطبيقات الوحدة ، لا شيء أكثر من ذلك. كل شيء لإدارة وحدة ، حتى الإكمال التلقائي.

[الشريحة 15:20] يقترح الحل نفسه أن كل هذا يمكن أن يتم دفعه إلى الممنوع للغاية من خلال العبارة. دعونا نفهم لماذا ممنوع.
الحقيقة هي أنه مع مشاكله. على سبيل المثال ، مع ، للأسف ، يتم تسريبه خارج النطاق الذي ألقينا فيه ، لأنه يحاول أن يبدو أعمق من وحدة واجهة برمجة التطبيقات وينظر إلى النطاق العام.

هنا المثال الأخير رائع بشكل خاص ، لأنه حتى أربعة يمكن أن تكون خطرة على التعليمات البرمجية لدينا ، حيث يمكن تنفيذ جميع هذه الوظائف عن طريق رمز المستخدم. يمكن للمستخدم القيام بأي شيء. هذه لعبة للمبرمجين ، وهم يحبون استكشاف المشكلات وطرق اختراق شيء ما.

كما قلت ، فإن النطاقات شديدة التسرب ، لذلك يتوفر نطاق عالمي دائمًا. بغض النظر عن عدد النطاقات التي نضعها على الشفرة المخصصة لدينا ، وبغض النظر عن عدد النطاقات التي نلفها بها ، سيظل النطاق العالمي مرئيًا. وكل ذلك بسبب مع.
في الواقع ، إنه لا يعزل أي شيء ، إنه يضيف إلينا طبقة جديدة من التجريد ، نطاق عالمي جديد. ولكن يمكننا تغيير هذا السلوك مع الوكيل.

الحقيقة هي أن الخادم الوكيل يعتني بكافة المكالمات التي نوجهها إلى الكائن الذي يتم إرساله عبر واجهة برمجة التطبيقات الجديدة ، ويمكننا التحكم في كيفية سلوك طلبات البيانات الجديدة في هذا الكائن.

في الواقع ، مع الأعمال بكل بساطة. عندما نطعمه نوعًا ما من المتغيرات ، يتحقق تحت الغطاء ما إذا كان هذا المتغير موجودًا في الكائن (أي أنه ينفذ المشغل) ، وإذا كان الأمر كذلك ، فسيتم تنفيذه في الكائن ، وإذا لم يكن كذلك ، فسيتم تنفيذه في النطاق العلوي ، في قضيتنا عالمية. انها بسيطة جدا هنا. الشيء الرئيسي الذي يساعدنا الوكيل هو أنه يمكننا تجاوز هذا السلوك.

هناك شيء مثل السنانير في الوكيل. شيء رائع يسمح لنا بالوكالة عن أي طلبات للكائن. يمكننا تغيير سلوك طلب السمة ، وتغيير سلوك مهمة السمة ، والأهم من ذلك ، يمكننا تغيير سلوك هذا في عامل التشغيل. هناك هوك ، والتي يمكننا العودة صحيحا فقط. وبالتالي ، فإننا نأخذ وخدعنا تمامًا بياننا ، مما يجعل API أكثر أمانًا من ذي قبل.

إذا حاولنا تشغيل eval () ، فسيسأل أولاً إذا كان هذا eval () موجودًا في unitApi ، فسوف يجيبون بـ "نعم" ويحصلون على "غير معرّفة ليست وظيفة". يبدو أن هذه هي المرة الأولى التي أكون سعيدًا بهذا الخطأ! هذا الخطأ هو بالضبط ما كان ينبغي أن نتلقاه. أخذناها وأخبرنا المستخدم: "آسف ، انسوا كل شيء تعرفه عن كائن النافذة ، هذا لم يعد". لقد تركنا بالفعل بعض المشاكل ، لكن هذا ليس كل شيء.

الحقيقة هي أن العبارة with هي نفسها من JS ، JS ديناميكية وغريبة بعض الشيء. الشيء الغريب هو أنه لا يعمل كل شيء كما نود ، دون النظر في المواصفات. والحقيقة هي أنه مع يعمل أيضا مع خصائص النموذج الأولي. وهذا هو ، يمكننا أن يطعمه مبتذل مجموعة ، وتنفيذ هذا الرمز الغامض. جميع وظائف المصفوفة متاحة كعمومية في هذا النطاق ، والتي تبدو غريبة بعض الشيء.

هذا غير مهم بالنسبة لنا ، من المهم بالنسبة لنا أنه يمكن للمستخدم تنفيذ valueOf () والحصول على كل صندوق الحماية الخاص بنا. خذ مباشرة والتقاط ، ونرى ما هو فيه. لا أريد هذا أيضًا ، لذا تم تقديم شيء مثير للاهتمام في المواصفات: Symbol.unscopables. هذا هو ، في المواصفات الجديدة للرموز ، تم تقديم Symbol.unscopables خصيصًا للبيان with ، وهو محظور. لأنهم يعتقدون أن شخصًا آخر يستخدمه. على سبيل المثال ، أنا!

وبالتالي ، سنقوم بعمل اعتراض آخر ، حيث نتحقق بالتحديد لمعرفة ما إذا كان هذا الرمز في قائمة جميع سمات unscopables. إذا لم يكن كذلك ، فأعده ، ولكن إذا كان الأمر كذلك ، فأسف ، لن نعود. نحن لا نستخدمه أيضا. وبالتالي ، مع أننا لا نستطيع حتى الحصول على نموذج أولي من رمل لدينا.

لا يزال لدينا بيئة العمال. هذا شيء معلق في منطقة عالمية ولا يزال الوصول إليه ممكنًا. الحقيقة هي أنه إذا قمت ببساطة بتجاوز هذا ، فسيكون متاحًا في النموذج الأولي. من خلال النموذج الأولي في JS ، يمكنك سحب أي شيء تقريبًا. والمثير للدهشة أن كل هذه الأساليب لا تزال متاحة من خلال النموذج الأولي.

كان علي أن آخذ كل هذا وتنظيفه. نذهب من خلال جميع المفاتيح وتنظيف كل شيء.

ثم نترك بيضة عيد الفصح قليلاً للمستخدم ، الذي لا يزال يحاول استدعاء هذا. نأخذ الوظيفة المعتادة ، الشيء الرئيسي ليس وظيفة السهم ، التي لها نطاق ، ونغير نطاقها إلى كائننا ، الذي نترك فيه بيضة عيد الفصح صغيرة لمستخدم فضولي بشكل خاص يريد عرض بعض هذا أو الذات في وحدة التحكم. أعتقد أن بيض عيد الفصح رائع ويجب تركه في الكود.

اتضح كذلك أنهم تركوا فقط مع وحدة واجهة برمجة التطبيقات الخاصة بنا. لقد حظرنا كل شيء تمامًا - في الواقع ، تركنا قائمة بيضاء. نحتاج إلى إضافة واجهات برمجة التطبيقات (APIs) المفيدة والمطلوبة. على سبيل المثال ، واجهة برمجة تطبيقات Math ، التي تحتوي على وظيفة عشوائية مفيدة يستخدمها العديد من الأشخاص عند كتابة التعليمات البرمجية للوحدات.
نحتاج أيضًا إلى وحدة التحكم والعديد من الوظائف النفعية الأخرى التي لا تحمل أي وظيفة مدمرة. نقوم بإنشاء قائمة من الوقت لواجهات برمجة التطبيقات الخاصة بنا.
هذا أمر جيد ، لأنه إذا أنشأنا قائمة سوداء ، فسنعتمد على أي تحديث للمتصفح يحدث دون علمنا.
من خلال إنشاء قائمة بيضاء ، يمكننا البدء في استخدام try-catch في التعليمات البرمجية الخاصة بنا. لدينا رمز ملفوف بالفعل يمسك الأخطاء ويمكن إرسالها إلى المستخدم ، وهو أمر مهم للغاية لتصحيح الأخطاء.
ولكن الحقيقة هي أن أساليب وحدة التحكم من Worker لا تظهر نفسها في رمز المستخدم. أي إذا فتحت وحدة التحكم وانتقلت إلى بيئة العامل ، فستكون متاحة ، لكن سيكون من الخطأ إخبار المستخدم "افتح وحدة التحكم وشاهد ما حدث لك". قررت إنشاء وحدة تحكم ودية للاعب ، حيث يمكن للاعب ، حتى بدون خبرة في JavaScript ، أن يرى بطريقة ودية ما حدث., , - . , . , webpack .

patchMethod(), , postMessage(). postMessage() console log, error, warn, info. , . , <div>, , , , , .

, . : - - — , , - . , , promises. , actions, .

actions. , real-time ? , real-time workers , worker, . - , . , , . , , . .

workers, . workers , . , . , , ( , ), . : — .
Math.random()
, , , . Math.random().
, , , . , Math.random() - .

, , ( ), JS , . .

, , , . , - .
, . , random(), .

, random() — « » , . , - , random() , . - , . , , random() .

. , , random() . - seed ( , , ).

, . , random(). , random() -.
هناك حاجة إلى جميع التعليمات البرمجية التي يتم إرسالها إلى العامل لجعل JS آمنة تماما. البرتقالي "إدراج" هو نفس رمز المستخدم. الذي يتم حقنه هناك. هذا هو مقدار الكود الذي تحتاجه لجعل JS آمنة. يتم حقن Random () وواجهة برمجة التطبيقات للوحدة أيضًا هناك. من خلال الحقن ، أحصل على مزيد من الشفرة التي يتم إرسالها إلى العامل.
مشاركة الدولة: RxJS والخادم والعملاء
لذلك اكتشفنا ما لدينا مع العميل. الآن دعنا نتحدث عن مشاركة الدولة ، لماذا هناك حاجة لذلك وكيف تم تنظيمها. لدينا حالة مخزنة على الخادم ، يجب على الخادم أن يتعثر مع العملاء المتصلين. [الشريحة 28:48]
لدينا أربعة أدوار لعملاء مختلفين يمكنهم الاتصال بالخادم: "المستخدم الأيسر" ، "المستخدم الصحيح" ، المشاهد الذي ينظر إلى الشاشة الرئيسية ، ومسؤول يمكنه فعل أي شيء.
لا يمكن للشاشة اليسرى تغيير حالة المشغل الصحيح ، ولا يمكن للمشاهد تغيير أي شيء ، ويمكن للمشرف فعل كل شيء.

لماذا كانت هذه مشكلة؟ كل شيء مرتب بكل بساطة. يمكن لأي عميل متصل إلقاء جلسة ، ويقبله الخادم ويدخل في الحالة ، وهو موجود داخل الخادم ثم يوزعه على جميع العملاء. إنه يتحسس لأي تغييرات تأتي إليه. كان من الضروري تصفية ذلك بطريقة أو بأخرى.

أولاً ، سأقول لماذا يحتوي الخادم أيضًا على RxJS. تصبح جميع التفاعلات مع اثنين أو أكثر من المستخدمين المتصلين غير متزامنة. يجب أن ننتظر النتائج من كلا المستخدمين. على سبيل المثال ، نقر المستخدمون على الزر "إنهاء" ، وعليك الانتظار حتى ينقر كلاهما ، ثم فقط تنفيذ الإجراء. كان كل شيء واضحًا جدًا على RxJS بهذه الطريقة:

نحن نعمل مرة أخرى مع المواضيع ، هناك تيار من المقبس ، والذي يسمى المقبس. لإنشاء مؤشر ترابط واحد يراقب اللاعب الأيسر فقط ، نحن ببساطة نأخذ ونرشح الرسائل من هذا المقبس بواسطة اللاعب الأيسر (وبالمثل مع اليمين). بعد ذلك ، يمكننا دمجها باستخدام عامل التشغيل forkJoin () ، والذي يعمل مثل Promise.all () وهو التناظرية. ننتظر كلا الإجراءين ونستدعي طريقة setState () ، والتي تحدد حالتنا على "جاهزة". اتضح أننا ننتظر اللاعبين ونغير حالة الخادم. في RxJS ، يظهر هذا التصريح قدر الإمكان ، وهذا هو سبب استخدامه.
لا تزال هناك مشكلة في حقيقة أن اللاعبين يمكنهم تغيير حالة بعضهم البعض. يجب أن يحظر عليهم القيام بذلك. لا يزال ، هم المبرمجين ، كانت هناك سوابق حاول شخص ما. لنقم بإنشاء فصول منفصلة لهم موروثة من العميل.

سيكون لديهم المنطق الأساسي لاتصال اللاعب بالخادم ، وفي كل فصل سيكون هناك منطقه المخصص لتصفية البيانات.
العميل هو في الواقع مجموعة من الاتصالات ، اتصالات مع العملاء.

إنه يخزنهم فقط ولديه دفق onUnsafeMessage ، وهو أمر غير آمن تمامًا: لا يمكن الوثوق به ، فهذه مجرد رسائل أولية من المستخدم الذي يتلقاه. نكتب هذه الرسائل الأولية إلى الدفق.
علاوة على ذلك ، عند تطبيق لاعب معين ، فإننا نأخذ هذا onUnsafeMessage ونصفه.

نحتاج فقط إلى تصفية البيانات التي يمكننا الحصول عليها من هذا اللاعب ، الذي يمكننا الوثوق به. يمكن للاعب الأيسر تغيير حالة اللاعب الأيسر فقط ، على التوالي ، نأخذ من جميع البيانات التي يمكن أن يرسلها ، فقط حالة اللاعب الأيسر. إذا لم ترسلها ، حسنًا. إذا أرسلت - نحن نأخذ. وبالتالي ، من الرسائل غير الآمنة تمامًا ، نحصل على رسائل آمنة يمكننا الوثوق بها عند العمل في الغرفة.

لدينا غرف ألعاب تجمع اللاعبين. داخل الغرفة ، يمكننا كتابة الوظائف ذاتها التي يمكن أن تتغير حالتها مباشرةً ، ببساطة عن طريق الاشتراك في هذه التدفقات ، والتي يمكننا الوثوق بها بالفعل. نحن المستخرجة من مجموعة من الشيكات. لقد قمنا بالتحققات بناءً على الأدوار ، ودعونا بفصول منفصلة. قمنا بتقسيم الكود بطريقة أنه داخل وحدة التحكم ، حيث يتم تنفيذ الوظائف المهمة لتغيير الحالة ، أصبح الكود بسيطًا وتوضيحيًا قدر الإمكان.
يستخدم RxJS أيضًا على العميل ، وهو متصل بالمقبس على الجانب الخلفي ، ويصدر الأحداث ويعيد توجيهها بكل طريقة.
في هذه الحالة ، أود أن أقدم مثالاً عندما أحتاج إلى تغيير جيش الخصم الصحيح.

للاشتراك فيه ، نقوم بإنشاء دفق من نفس المقبس وتصفيته. نتأكد من أن هذا هو اللاعب المناسب حقًا ، ونأخذ رسالة منه حول ماهية جيشه. إذا لم تكن هناك رسالة من هذا القبيل ، فلن يُرجع الدفق أي شيء ، ولن تكون هناك رسالة واحدة فيه ، وستظل صامتة حتى يغير اللاعب الجيش. نحن على الفور حل مشكلة تصفية الأحداث ، ليس لدينا هو مبتذل.
وعندما يأتي شيء بالفعل من الدفق ، فإننا ندعو وظيفة setState (). هذا بسيط للغاية ، وهو النهج الذي يسمح لنا بالقيام بكل شيء بشفافية وإعلانية. الشيء ذاته الذي أخذت منه مشروع RxJS وما ساعدني كثيرًا.

أقوم بإنشاء تدفقات قمت بتسميةها بوضوح تام ، والتي أفهمها كيف أعمل ، كل شيء تعريفي ، يتم استدعاء الوظائف الضرورية ، لا يوجد أي ضجة مع الكثير من أحداث if وفلترة ، كل ذلك يتم بواسطة RxJS.
التاريخ: من لاعب واحد إلى لاعبين متعددين
لذلك ، تم كتابة الإصدار الأول من لعبتي. يمكننا القول أنه كان لاعبًا واحدًا ، لأنه لا يمكن تشغيله إلا لاعبين اثنين ، تم إصلاح عدد العملاء المتصلين. كان لدينا لاعب يسار ولاعب الأيمن وشاشة خلفه ، كل هذا متصل مباشرة بالخادم. كان كل شيء مشدودًا ، لكن خلال ثلاثة أسابيع تم القيام به.
تلقيت عرضًا جديدًا: لتوسيع اللعبة لجميع المبرمجين في الشركة حتى يتمكنوا من فتحها وتشغيلها على أجهزة الكمبيوتر الخاصة بهم. حتى نحصل على قائمة من القادة ، متعددة اللاعبين حتى يتمكنوا من اللعب معًا. ثم أدركت أن لدي الكثير من إعادة البناء.

اتضح أنها ليست صعبة للغاية. لقد قمت ببساطة بدمج جميع الكيانات التي كنت أمتلكها في غرف منفصلة. حصلت على جوهر "الغرفة" ، والتي يمكن أن تجمع بين جميع الأدوار. الآن ليس اللاعبون أنفسهم هم الذين يتصلون مباشرة بالخادم ، ولكن الغرف. تحتوي الغرف بالفعل على طلبات مباشرة إلى الخادم ، لتحل محل الحالة ، وأصبحت الولاية منفصلة لكل غرفة.

لقد أخذت وأعدت كتابة كل شيء ، أضفنا قائمة من القادة ، لقد منحنا الأفضل بجوائز. كان من الضروري وجود عدد كبير من المستخدمين ، كان من المستحيل بالفعل متابعة الجميع ، كان من الضروري أن تكتب شيئًا لتجمع فيه جميع البيانات.
شبيبة Gamedev ومشاكله
وهكذا ، أصبحت أكثر معرفة جدية مع JS-gamedev. قمت بحركة حول المشروع الأخير لمدة ثلاث سنوات ، واستريح بشكل دوري. وهنا كان لدي كل مرة لمدة ثلاثة أسابيع. جلست كل يوم وفعلت شيئًا في المساء.
ما هي المشاكل الموجودة في تطوير الألعاب على JS؟ يختلف كل شيء عن تطبيقات أعمالنا ، حيث لا تشكل مشكلة في كتابة شيء ما من نقطة الصفر. علاوة على ذلك ، فإن الكثير منها مرحب به: سنقوم بعملنا الخاص ، ونتذكر القصص مع NPM والجزء الأيسر بنفسك.

من المستحيل القيام بذلك في JS Gamedev ، لأن جميع تقنيات عرض الرسومات منخفضة للغاية لدرجة أنه من غير المربح اقتصاديًا كتابة شيء عليها. إذا استخدمت هذه اللعبة وبدأت في كتابتها من نقطة الصفر على WebGL ، فسأجلس خلفها لمدة ستة أشهر فقط ، وأحاول فقط اكتشاف بعض الأخطاء الغريبة. محرك اللعبة الأكثر شعبية فيزر إزالة هذه المشاكل مني ...

... وأضفت جديدة إلي: 5 ميغابايت في حزمة. ولا يمكن القيام بشيء حيال ذلك ؛ فهو لا يعرف ماهية تهجم الأشجار على الإطلاق. علاوة على ذلك ، يمكن فقط لأحدث إصدار من Phaser العمل مع حزم الويب والحزم. قبل ذلك ، كان متصلاً Phaser فقط في علامة html للنص ، كان غريباً بالنسبة لي.
لقد جئت من جميع أنواع البرامج النصية webpacks ، وفي لعبة JS dev ، لا يمكن لأي شيء تقريبًا فعل ذلك. تحتوي جميع الوحدات النمطية على طباعة رديئة للغاية أو لا تملكها على الإطلاق ، أو أساسًا لا تعرف كيفية استخدام حزمة الويب ، كان من الضروري إيجاد طرق لفها. كما اتضح ، حتى Ace Editor بشكله النقي لا يعمل مع webpack على الإطلاق. لبدء العمل ، تحتاج إلى تنزيل حزمة منفصلة حيث يتم لفها بالفعل (دعامة).
كان الأمر على نفس المنوال مع Phaser ، لكن في الإصدار الجديد ، فعلوا ذلك بشكل طبيعي أكثر أو أقل. واصلت الكتابة على Phaser ووجدت كيف أجعل كل شيء يعمل مع حزمة الويب بالطريقة التي اعتدنا عليها: يمكن ربط كل من الاختبارات والاختبارات بكل هذا. لقد وجدت أنه يمكنك أن تأخذ
PixiJS بشكل منفصل ، وهو عبارة عن عرض webpack ، والعثور على الكثير من الوحدات الجاهزة للعمل معها.

PixiJS هي مكتبة رائعة يمكن عرضها إما على WebGL أو على Canvas. علاوة على ذلك ، يمكنك كتابة الكود كما لو كان Canvas ، وسوف يتم عرضه في WebGL. يمكن أن تقدم هذه المكتبة ثنائية الأبعاد بسرعة كبيرة. الشيء الرئيسي هو معرفة كيفية عملها مع الذاكرة ، حتى لا تقع في موقف عندما انتهت الذاكرة.
أوصي بشكل منفصل
بمخزن رائع - pixijs على GitHub ، حيث يمكنك العثور على وحدات مختلفة. الأهم من ذلك كله أنني أحب
React-pixi . يمكننا ببساطة تجاهل حل المشكلات في طريقة العرض عندما نكتب وظائف حتمية مباشرة في وحدة التحكم لرسم الأشكال الهندسية والعفاريت والرسوم المتحركة والمزيد. يمكننا جميع العلامات في JSX. لقد جئنا من عالم JSX من خلال تطبيق أعمالنا ويمكننا استخدامه أكثر. هذا هو ما أحب التجريد ل. React-pixi يعطينا هذا التجريد المألوف.
كما أنصحك أن تأخذ tween.js - نفس محرك الرسوم المتحركة الشهير من Phaser ، والذي يسمح لك بعمل رسوم متحركة إرشادية تشبه إلى حد ما الرسوم المتحركة لـ CSS: نحن ننتقل بين الولايات ، ونقرر tween.js لنا بالضبط كيفية تحريك الكائن.
أنواع اللاعبين: من هم وكيفية تكوين صداقات معهم
صادفت لاعبين مختلفين ، وأود أيضًا أن أخبركم عن اختبار اللعبة. جمعت زملائي في غرفة واحدة مغلقة ولم أسمح لهم بالخروج حتى ينتهيوا من اللعبة. لسوء الحظ ، لم يتمكن الجميع من إنهاء اللعبة ، لأنه في البداية كان لدي الكثير من الأخطاء. لحسن الحظ ، بدأت في الاختبار بمجرد ظهور بعض النماذج الأولية للعمل. بصراحة ، فشل الاختبار الأول لأن اثنين من اللاعبين لم يبدأوا بأي شيء. كان ذلك عارًا ، لكنه أعطاني ركلة سمحت لي بالمضي قدمًا.
عندما تكون لعبتك جاهزة ، يمكنك استلامها جيدًا ، أو باستخدام رصيف مشعل ومشاعل. جميع الناس ينتظرون نوعًا من المعجبين بالألعاب ، في انتظار السعادة التي ستعطيها لهم. وأنت تعطيهم شيئًا لا يعمل على الإطلاق ، رغم أنه يبدو أنه يعمل من أجلك. عندما يكون لديك لعبة على الإنترنت ، فهناك المزيد من الأخطاء.
نتيجةً لذلك ، فإن أكثر الأشخاص اللطيفين الذين قابلتهم هم "باحثون" يجدون دائمًا في لعبتك أكثر مما هو في الحقيقة. يمكنهم استكمالها بكل سرور بكل أنواع الأشياء الصغيرة ، مما يدفعك إلى إضافة شيء ما. ولكن لسوء الحظ ، فإن التواصل مع هؤلاء الأشخاص لم يعطِ شيئًا مهمًا - استقرار اللعبة.
هناك لاعبون عاديون يأتون فقط من أجل المعجبين. قد لا يلاحظون في بعض الأحيان أخطاء ، يتسللون بطريقة ما من خلالهم في طريقهم إلى المتعة.
فئة أخرى هي جامعي الأخطاء ، حيث لا يعمل كل شيء تقريبًا. يجب أن تكون صديقًا لهؤلاء الأشخاص ، رغم أنهم سيتحدثون كثيرًا عن السلبية. نحتاج إلى إقامة علاقات غريبة معهم: إنها تؤذيك ، وتحاول أن تأخذ شيئًا مفيدًا لنفسك منها ، "دعنا نجلس على الكمبيوتر ونرى". تحتاج إلى العمل معهم ، لأنه في النهاية هؤلاء الأشخاص هم الذين سيجعلون جودة لعبتك.
تحتاج إلى اختبار فقط على الناس الأحياء. عينيك غير واضحة ، وسيظهر الاختبار بالتأكيد ما هو مخفي. أنت تقوم بتطوير لعبة والغطس بشكل أعمق ، مع رؤية بعض الميزات ، لكن قد لا تكون هناك حاجة إليها. تذهب مباشرة إلى مستهلكيك ، اعرضهم وشاهد كيف يلعبون ، أي المفاتيح يضغطون عليها. يمنحك هذا حافزًا للقيام بما تحتاجه بالضبط. سترى أن بعض الأشخاص يضغطون باستمرار على Ctrl + S ، لأنهم معتادون على حفظ الكود - حسنًا ، على الأقل لجعل الكود يعمل على Ctrl + S ، سيشعر اللاعب بمزيد من الراحة. تحتاج إلى تهيئة بيئة مريحة للاعب ، لذلك عليك أن تحبه وتتبعه.
تعمل القاعدة 80/20: أنت تقدم عرضًا تجريبيًا بنسبة 20٪ من الوقت من التطوير الكامل للعبة ، ويبدو أنها لعبة مكتملة بنسبة 80٪ بالنسبة للاعب. يعمل الإدراك بحيث تكون الميكانيكا الأساسية جاهزة ، وكل شيء يتحرك ويعمل ، مما يعني أن اللعبة جاهزة تقريبًا ، وسيعمل المطور على الانتهاء منها قريبًا. ولكن في الواقع ، لا يزال لدى المطور طريقة للخروج من 80 ٪. كما قلت ، لفترة طويلة كان عليّ أن أعمل على التوثيق بحيث يكون مفهومًا للجميع. لقد أوضحت ذلك للعديد من الأشخاص الذين تحدثوا عن تعليقاتهم ، قمت بتصفيتها ، محاولين فهم جوهر البيانات. وكثير من الوقت استغرق مني البحث عن الأخطاء.
لذا في تطوير اللعبة ، يمكنني أن أنصحك فقط بالقيام بالعروض التوضيحية: فهي تسعد الجميع ، ولا تتطلب الكثير من الوقت ، ولا يتوقع أحد حقًا أي شيء من العروض. تعتبر عملية إنهاء الألعاب عملية مملة ، ولكن البدء أمر رائع.
أخيرًا ، أتركك روابط:
سوف يعقد HolyJS 2019 Piter ، وهو مؤتمر لمطوري جافا سكريبت ، يومي 24 و 25 مايو في سان بطرسبرغ. وقد ظهرت بالفعل أول المتحدثين على الموقع.
يمكنك أيضًا تقديم طلب للحصول على تقرير ، Call for Papers مفتوح حتى 11 مارس.
سترتفع أسعار التذاكر في 1 فبراير.