دليلك الشامل: بناء محاكي ألعاب طاولة جماعية تفاعلية بـ Vue و Phaser و Node.js
يُعد تجميع مكونات تطبيق JavaScript كامل المكدس (Full Stack) مهمة معقدة تتطلب فهماً عميقاً للعديد من التقنيات. في هذا الدليل الشامل، سنتعلم كيفية بناء محاكي ألعاب طاولة متعدد اللاعبين (Multiplayer Tabletop Game Simulator) باستخدام أطر العمل والتقنيات الحديثة مثل Vue.js و Phaser و Node.js مع Express، بالإضافة إلى مكتبة Socket.IO. سيكشف هذا المشروع عن مفاهيم أساسية وقيمة يمكن تطبيقها في أي تطبيق Full Stack.
يمكنك أيضاً متابعة هذا الشرح المرئي المصاحب (مدة المشاهدة: ساعة و16 دقيقة).
تتوفر جميع ملفات المشروع لهذا الدليل على مستودع GitHub الخاص بالمشروع.
نظرة عامة على المشروع
سيتمحور مشروعنا حول بيئة لعب (Game Instance) مبنية باستخدام مكتبة Phaser، والتي ستمكننا من إنشاء رموز (Tokens) وبطاقات (Cards) على الشاشة، وتحريكها بسلاسة على لوح لعب رقمي. سيتم تغليف بيئة Phaser هذه داخل مكون (Component) من Vue.js، والذي سيتولى إدارة وظائف مثل الدردشة متعددة اللاعبين (Multiplayer Chat) وتنفيذ الأوامر.
معاً، ستشكل Phaser و Vue.js الواجهة الأمامية لتطبيقنا (والتي سنشير إليها لاحقاً بـ "العميل" أو "Client"). سنستخدم مكتبة Socket.IO لتسهيل التواصل الفوري بين اللاعبين وربط الواجهة الأمامية بالواجهة الخلفية لتطبيقنا.
أما الواجهة الخلفية (والتي سنشير إليها بـ "الخادم" أو "Server")، فستكون عبارة عن خادم Express بسيط يستقبل أحداث Socket.IO من العملاء ويتصرف بناءً عليها. سيعمل التطبيق بأكمله على بيئة تشغيل Node.js.
لا يلزم أن تكون خبيراً في أي من أطر العمل المذكورة أعلاه لإكمال هذا المشروع، ولكن يُفضل أن يكون لديك أساس متين في لغات JavaScript و HTML/CSS قبل الخوض في التفاصيل الدقيقة. يمكنك أيضاً متابعة سلسلتي حول تعلم JavaScript من خلال بناء ألعاب الطاولة الرقمية وتطبيقات الويب. تأكد أيضاً من تثبيت Node.js و Git على نظامك، بالإضافة إلى محرر الأكواد المفضل لديك وواجهة سطر الأوامر (CLI). (يمكنك مراجعة دليلنا حول إعداد بيئة التطوير المتكاملة IDE إذا احتجت للمساعدة).
لنبدأ!
الجزء الأول: أساسيات الواجهة الأمامية (Client)
سنبدأ ببناء واجهتنا الأمامية بتثبيت أداة سطر الأوامر الخاصة بـ Vue.js، والمعروفة بـ Vue CLI. ستساعدنا هذه الأداة في توفير مجموعة من الأدوات (Tooling) وتسهيل عملية التطوير، مما يتيح لنا إجراء التغييرات على ملفات المشروع دون الحاجة إلى إعادة تحميل المتصفح يدوياً.
في واجهة سطر الأوامر، اكتب الأمر التالي لتثبيت Vue CLI بشكل عام (Globally):
npm install -g @vue/cli
انتقل إلى الدليل الذي تفضله وقم بإنشاء مجلد جديد لمشروعنا:
mkdir tabletop-project cd tabletop-project
الآن يمكننا استخدام Vue CLI لإنشاء قالب لمشروع الواجهة الأمامية:
vue create client
يمكنك ببساطة الضغط على مفتاح "Enter" في المطالبات اللاحقة ما لم تكن لديك تفضيلات محددة.
لقد قامت Vue CLI بإنشاء قالب مشروع الواجهة الأمامية لنا بنجاح، والذي يمكننا الآن معاينته في محرر الأكواد الخاص بنا:
دعنا ننتقل إلى مجلد client الجديد في واجهة سطر الأوامر ونشغل التطبيق النموذجي:
cd client npm run serve
بعد قليل من العمل، ستبدأ Vue CLI في عرض تطبيقنا في متصفح الويب على العنوان الافتراضي http://localhost:8080:
رائع! لقد أصبح لدينا الهيكل الأساسي لواجهتنا الأمامية. دعنا نعدل هذا الهيكل بإنشاء مكونين جديدين في مجلد /components، وهما Game.vue و Chat.vue. (يمكنك حذف الملف HelloWorld.vue وأي شيء في مجلد assets إذا كنت مهووساً بالنظافة مثل الكاتب).
استبدل الكود في ملف App.vue بما يلي:
< template > < div id = "app" > < div id = "game" > < Game /> </ div > < div id = "border" /> < div id = "input" > < Chat /> </ div > </ div > </ template > < script > import Chat from './components/Chat.vue' ; import Game from './components/Game.vue' ; export default { name : 'App' , components : { Chat, Game } } </ script > < style > #app { font-family : 'Trebuchet MS' ; text-align : left; background-color : black; color : cyan; display : flex; } #game { width : 50vw ; height : 100vh ; } #input { width : 50vw ; height : 100vh ; } #border { border-right : 2px solid cyan; } @media ( max-width: 1000px ) { #app { flex-direction : column; } #game { width : 100vw ; height : 50vh ; } #input { width : 100vw ; height : 50vh ; } } </ style >
كما ترى، يتكون مكون Vue عادةً من ثلاثة أقسام رئيسية: Template (القالب)، و Script (السكربت)، و Style (النمط)، والتي تحتوي على أكواد HTML و JavaScript و CSS لهذا المكون على التوالي. لقد قمنا هنا باستيراد مكوني Game و Chat وأضفنا بعض التنسيقات (Styling) لمنح التطبيق مظهراً مستوحى من "السايبربانك" (Cyberpunk) عندما يعمل بشكل كامل. هذا هو كل ما نحتاجه لإعداد مكون App.vue، والذي سيحتوي على جميع المكونات الأخرى في واجهتنا الأمامية. ولكن قبل أن نتمكن من فعل أي شيء به، سنحتاج إلى تشغيل خادمنا!
الجزء الثاني: أساسيات الواجهة الخلفية (Server)
في الدليل الجذري لمشروعنا (tabletop-project، وهو المجلد الذي يضم /client)، قم بتهيئة مشروع جديد في واجهة سطر أوامر جديدة عن طريق كتابة:
npm init
كما هو الحال مع مشروع الواجهة الأمامية، يمكنك المضي قدماً والضغط على مفتاح "Enter" في المطالبات ما لم تكن هناك تفاصيل محددة ترغب في تعيينها في هذا الوقت. سنحتاج إلى تثبيت Express و Socket.IO، بالإضافة إلى Nodemon لمراقبة ملفات الخادم وإعادة تشغيله تلقائياً عند الضرورة:
npm install --save express socket.io nodemon
دعنا نفتح ملف package.json الجديد في هذا الدليل الجذري ونضيف أمراً "start" في قسم "scripts":
"scripts" : { "start" : "nodemon server.js" },
أنشئ ملفاً جديداً باسم server.js في هذا الدليل، وأدخل الكود التالي:
const server = require ( 'express' )(); const http = require ( 'http' ).createServer(server); const io = require ( 'socket.io' )(http); io.on( 'connection' , function ( socket ) { console .log( 'A user connected: ' + socket.id); socket.on( 'send' , function ( text ) { let newText = "<" + socket.id + "> " + text; io.emit( 'receive' , newText); }); socket.on( 'disconnect' , function ( ) { console .log( 'A user disconnected: ' + socket.id); }); }); http.listen( 3000 , function ( ) { console .log( 'Server started!' ); });
ممتاز! سيستمع خادمنا البسيط الآن على العنوان http://localhost:3000، وسيستخدم Socket.IO لتسجيل رسائل في وحدة التحكم (Console) عند اتصال المستخدمين وفصلهم، مع عرض معرف المقبس (Socket ID) الخاص بهم. عندما يتلقى الخادم حدث "send" من العميل، فإنه سينشئ سلسلة نصية جديدة تتضمن معرف المقبس للعميل الذي أطلق الحدث، ثم يطلق حدثه الخاص "receive" إلى جميع العملاء بالنص الذي تلقاه، مع تضمين معرف المقبس.
يمكننا اختبار الخادم بالعودة إلى واجهة سطر الأوامر وتشغيله:
npm run start
يجب أن تعرض وحدة التحكم الآن ما يلي:
رائع! دعنا نعود إلى مكون Chat في واجهتنا الأمامية لبدء بناء وظائف الواجهة الأمامية.
الجزء الثالث: مكون الدردشة (Chat Component)
دعنا نفتح واجهة سطر أوامر منفصلة وننتقل إلى دليل /client. داخل هذا الدليل، قم بتثبيت نسخة العميل من Socket.IO:
npm install --save socket.io-client
في الملف /client/src/components/Chat.vue، أضف الكود التالي:
< template > < div id = "container" > < div id = "output" > < h1 > STRUCT </ h1 > < p v-for = "(text, index) in textOutput" :key = "index" > {{text}} </ p > </ div > < div id = "input" > < form > < input type = "text" v-model = "textInput" :placeholder = "textInput" /> < input type = "submit" value = "Send" v-on:click = "submitText" /> </ form > </ div > </ div > </ template > < script > import io from 'socket.io-client' ; let socket = io( 'http://localhost:3000' ); export default { name : 'Chat' , data : function ( ) { return { textInput : null , textOutput : [] } }, methods : { submitText : function ( event ) { event.preventDefault(); socket.emit( 'send' , this .textInput); } }, created : function ( ) { socket.on( 'connect' , () => { console .log( 'Connected!' ); }); socket.on( 'receive' , ( text ) => { this .textOutput.push(text); this .textInput = null ; }); } } </ script > < style scoped > #container { text-align : left; display : flex; flex-direction : column; margin-left : 1vw ; min-height : 100vh ; } h1 { text-align : center; } .hotpink { color : hotpink; } #input { position : fixed; margin-top : 95vh ; } input [type=text] { height : 20px ; width : 40vw ; border : 2px solid cyan; background-color : black; color : hotpink; padding-left : 1em ; } input [type=submit] { height : 25px ; width : 5vw ; background-color : black; color : cyan; border : 2px solid cyan; margin-right : 2vw ; } input [type=submit] :focus { outline : none; } input [type=submit] :hover { color : hotpink; } @media ( max-width: 1000px ) { #container { border-left : none; border-top : 2px solid cyan; min-height : 50vh ; } #input { margin-top : 43vh ; } #output { margin-right : 10vw ; } input [type=text] { width : 60vw ; } input [type=submit] { min-width : 10vw ; } } </ style >
في هذا المكون، نلاحظ أن قسم <template> يحتوي على هيكل الدردشة، بما في ذلك منطقة عرض الرسائل (output) وحقل إدخال النص مع زر الإرسال (input). يتم استخدام توجيه v-for من Vue لعرض الرسائل المستقبلة ديناميكياً. أما قسم <script>، فهو يستورد مكتبة socket.io-client لإنشاء اتصال مع الخادم على http://localhost:3000. يدير كائن data حالة الإدخال والإخراج، بينما تحتوي methods على دالة submitText لإرسال الرسائل إلى الخادم عبر حدث "send". الأهم من ذلك، يتم استخدام دورة حياة created للاستماع إلى أحداث "connect" و "receive" من الخادم، حيث يتم تحديث textOutput عند استلام رسالة جديدة. أخيراً، يضيف قسم <style scoped> التنسيقات الخاصة بالمكون، مع مراعاة الاستجابة لأحجام الشاشات المختلفة.
الخلاصة التقنية
لقد قدم هذا الدليل رحلة عملية وشاملة في بناء تطبيق Full Stack JavaScript متعدد اللاعبين، يجمع بين قوة Vue.js للواجهة الأمامية التفاعلية، و Phaser لتجربة اللعب الغنية، و Node.js مع Express لإنشاء خادم فعال، و Socket.IO لتوفير الاتصال في الوقت الفعلي. أظهرنا كيف يمكن دمج هذه التقنيات لإنشاء تجربة مستخدم سلسة وممتعة، بدءاً من إعداد بيئة التطوير وصولاً إلى بناء مكونات العميل والخادم. إن فهم كيفية ربط هذه الأجزاء المتنوعة معاً هو مفتاح تطوير تطبيقات ويب حديثة وقابلة للتوسع، ويفتح الباب أمام إمكانيات لا حصر لها في عالم الألعاب التفاعلية والتطبيقات التعاونية.