در این آموزش، یک بازی ساده به سبک آرکید ۲ بُعدی خواهیم ساخت که رکورد امتیازهای آن در قرارداد هوشمند بر بستر بلاک چین اتریوم ثبت میشود.
راهنمای قدم به قدم ایجاد و پیاده سازی این پروژه، برنامه نویسی بازی با استفاده از Phaser.js، نوشتن قرارداد هوشمند با زبان برنامه نویسی سالیدیتی (Solidity) با استفاده از Remix IDE، اجرای قرارداد هوشمند در شبکه آزمایشی اتریوم و در آخر متصل کردن بازی خود به اتریوم با استفاده از متامسک (Metamask) و Web3.js را به شما ارائه خواهیم داد.
چه نوع بازیای خواهیم ساخت؟ یک بازی ساده. در صفحه چندین سکه به طور تصادفی قرار میگیرند و بازیکن باید قبل از آن که زمان به پایان برسد هرچه بیشتر این سکهها را جمع آوری کند. سپس امتیاز به دست آمده در قرارداد هوشمند ثبت خواهد شد.
این آموزش، شروع بسیار خوبی برای توسعه بازی اتریوم خواهد بود. برای استفاده از این آموزش باید مقدمات جاوا اسکریپت را بدانید.
شروع
قبل از شروع اطمینان حاصل کنید که افزونه متامسک را بر روی مرورگر خود نصب کرده باشید.
اکنون در ترمینال خود، دایرکتوری جدیدی بر روی هارد خود ایجاد کنید.
سپس این فایل را در دایرکتوری بازی ذخیره کنید.
ما برای آزمایش بازی خود به وب سرور نیاز داریم. میتوانید از وب سرور مورد نظر خود استفاده کنید، اما برای راحتی کار، ما از ماژول http.server پایتون ۳ استفاده خواهیم کرد.
در آخر، داراییهای بازی خود را به دست میآوریم. برای این کار میتوانید از آدرسهای زیر به دانلود یپردازید:
Coin.png از آدرس: https://fatalgames.itch.io/2d-pixel-coin
pixel guy.png از آدرس: https://theleggies.itch.io/simple-pixel-guy?download
برنامه نویسی بازی با Pahser.js
برنامه نویسی بازی خود را شروع میکنیم. ابتدا فایل جدیدی در دایرکتوری به اسم index.html با ویرایشگر متن خود ایجاد کنید.
از چارچوب زیر استفاده کنید:
این خط کتابخانه Web3.js را به پروژه ما ایمپورت میکند تا بعداً از آن استفاده کنیم:
این خط نیز کتابخانه Phaser.js را به پروژه ما ایمپورت میکند تا بعداً از آن استفاده کنیم:
ساختار بازی Phaser
بازی نوشته شده با Phaser.js به سه تابع و عملکرد نیاز دارد: پیش بارگذاری (preload)، ایجاد (create) و به روزرسانی (update). ما میتوانیم این سه تابع را دقیقا داخل تگ های <script>…</script> در بدنه فایل index.html خود تعریف کنیم:
از بابت جزئیات خطوط این کد پس از تعریف تابع ()update نگران نباشید. این خطوط، تنظیمات مقدماتی و سپس شروع بازی را امکان پذیر میسازند.
پیش بارگذاری داراییهای بازی
بهتر است داراییهای بازی را دقیقا هنگامی که به آنها نیاز است بارگذاری نکنیم؛ زیرا این امر میتواند روند بازی ما را با تداخل ایجاد کند. این همان کاری است که تابع ()preload انجام میدهد. ما میتوانیم داراییهای بازی را قبل از آن که بازی شروع شود بارگذاری کنیم. کدهای زیر را در تابع ()preload وارد کنید:
اضافه کردن آدمک بازیکن
اکنون که داراییها را بارگذاری کردهایم، آنها را وارد بازی میکنیم. کدهای زیر را در تابع ()create وارد کنید:
اکنون میتوانیم وب سرور محلی را ایجاد کنیم تا بتوانیم بازی خود را آزمایش کنیم. در ترمینال خود، فرمان ریز را اجرا کنید:
اکنون من سرور محلی را اجرا کردهاید، آدرس URL زیر را در مرورگر خود باز کنید. http://0.0.0.0:8000/ اکنون باید آدمک بازیکن خود را در مرکز صفحه مشاهده کنید.
این شروع بسیار خوبی بود. اما بهتر است برای آدمک، انیمیشن حرکت نیز ایجاد کنیم.
به حرکت در آوردن آدمک بازیکن
کد زیر را در انتهای تابع ()create وارد کنید:
اکنون صفحه مرورگر خود را ریفرش کنید. آدمک ما اکنون به حرکت در آمده است. سپس به برنامه نویسی کنترل آدمک میپردازیم.
کنترل آدمک
کد زیر را در انتهای تابع ()create وارد کنید:
سپس کدهای زیر را در تابع ()update وارد کنید:
صفحه را ریفرش کنید و کلیدهای جهت بر روی صفحه کلید را فشار دهید.
قرار دادن تصادفی سکهها
اکنون سکهها را به طور تصادفی بر روی صفحه قرار میدهیم. پس از آن که سکهای جمع آوری شد، امتیاز بازیکن افزایش خواهد یافت و سکه دیگری به طور تصادفی بر روی صفحه قرار خواهد گرفت.
این کار را با استفاده از مجموعهای از سکهها پیاده سازی خواهیم کرد. کد زیر را در انتهای تابع ()create وارد کنید:
مرورگر خود را ریفرش کنید و سپس سکهها را در صفحه مشاهده خواهید کرد.
شناسایی برخورد در بازی
هنگامی که سکهای دریافت شد، امتیاز بازیکن افزایش خواهد یافت و سپس، سکه در جای دیگری از صفحه به طور تصادفی قرار خواهد گرفت. ابتدا، متغیر امتیاز را در تابع ()create وارد میکنیم:
سپس تابع کمکی را برای جمع آوری سکهها خواهیم نوشت. این تابع را قبل از تابع ()update قرار دهید:
اطمینان حاصل کنید که این تابع را در انتهای تابع ()update خود فراخوانی کنید:
اکنون این عملکرد را در مرورگر خود آزمایش کنید. در مرحله بعد، شمارشگر را پیاده سازی خواهیم کرد تا بازی را به پایان برسانیم.
پایان یافتن بازی
تایمر را اجرا میکنیم. بازدیدهای Phaser با نرخ ۶۰ فریم بر ثانیه اجرا میشوند. همچنین متغیر فریم را خواهیم داشت که تمام لوپهای به روزرسانی که بازی ما اجرا میکند را خواهد شمرد. کد زیر را پس از تابع امتیاز اضافه کنید:
بنابراین تایمر را پس از هر ۶۰ فریم، کاهش میدهیم. هنگامی که تایمر صفر شود، بازی به پایان خواهد رسید. کد زیر را به ابتدای تابع ()update اضافه کنید:
این کد را آزمایش کنید. خب بازی ما آماده است.
در مرحله بعد، Phaser را کنار خواهیم گذاشت و با کد سالیدیتی بازی را مینویسیم.
برنامه نویسی سالیدیتی با استفاده از Remix IDE
اکنون آماده شروع برنامه نویسی قرارداد هوشمند اتریوم برای بازی خود هستیم. قرارداد ما برای ثبت رکورد امتیازات استفاده خواهد شد. ما از Remix IDE استفاده خواهیم کرد. میتوانید با مراجعه به سایت زیر، از Remix IDE در مرورگر خود استفاده کنید:
دریافت اتر برای شبکه آزمایشی
اکنون زمان خوبی برای این است تا اطمینان حاصل کنیم که اتریوم کافی برای شبکه آزمایشی خود داریم تا تراکنشهایی با قرارداد هوشمند خود ایجاد و آن را اجرا کنیم. چندین فاست (Faucet) شبکه آزمایشی وجود دارد. میتوانید از فاست زیر استفاده کنید:
قرارداد ما چه کاری انجام میدهد؟
قبل از آن که برنامه نویسی سالیدیتی را شروع کنیم، به این موضوع میپردازیم که از قرارداد هوشمند میخواهیم چه کاری برای ما در این بازی انجام دهد. به منظور آنکه بازیکن بازی ما را اجرا کند و رکورد امتیاز جدیدی ثبت کند، باید افزونه متامسک را بر روی مرورگر خود نصب کرده باشد.
آدرس انتخاب شده در متامسک به عنوان حساب بازیکن عمل خواهد کرد. به منظور ثبت رکورد امتیاز، بازیکن به سرمایه کافی در کیف پول خود نیاز دارد تا کارمزد تراکنش را بپردازد.
هدف اصلی قرارداد هوشمند ما، ذخیره سازی الگوی آدرسدهی به امتیازات است. این قرارداد هم چنین شامل تابع عمومی برای ثبت امتیاز بازیکن و تابع عمومی دیگر برای دریافت امتیاز بازیکن خواهد بود.
به علاوه، قرارداد ما تعداد کل بازیکنهایی که امتیاز آنها در قرارداد ما ثبت شده است را رصد خواهد کرد.
برنامه نویسی قرارداد هوشمند
در Remix IDE بر روی + کلیک کنید تا فایل جدیدی ایجاد کنید. فایل جدید را Highscores.sol نامگذاری کنید.
در بخش ویرایشگر متن، کد زیر را وارد کنید:
خط اول مشخص میکند که از کدام کامپایلر سالیدیتی استفاده خواهیم کرد. قبل از پیشروی بیشتر، در Remix به زبانه (tab) کامپایلر سالیدیتی بروید. در منوی باز شده، ۰.۵.۵ را انتخاب کنید.
اکنون کدهای زیر را به ویرایشگر متن اضافه کنید:
به خاطر داشته باشید که اسامی توابع و متغیرهای شخصی در سالیدیتی با _ شروع میشود.
توابع شخصی قراردادهای هوشمند ما
در مرحله بعد، بعضی از توابع کمکی را تعریف خواهیم کرد که شخصی هستند، یعنی فقط در قرارداد ما فراخوانی خواهند شد. هیچ دلیلی ندارد که بازی ما این توابع را مستقیما استفاده کند و به همین دلیل است که این توابع، شخصی هستند:
توابع عمومی قراردادهای هوشمند ما
اکنون توابع عمومی فراخوانی شده توسط بازی را تعریف خواهیم کرد:
در سالیدیتی، msg.sender به آدرس انتخاب شده کنونی کاربر در متامسک اشاره میکند. همانطور که متوجه شدهاید، اگر آدرسی متفاوت در متامسک انتخاب کنید، قرارداد شما را به عنوان کاربری دیگر خواهد شناخت. این دقیقا نحوه آزمایش قرارداد هوشمند و ورود چندین رکورد امتیاز توسط ما خواهد بود.
اجرای قرارداد هوشمند ما
اکنون که برنامه نویسی قرارداد هوشمند برای بازی ما پایان یافته است، میتوانیم قرارداد را در شبکه آزمایشی رینکبای (Rinkeby) آزمایش کنیم. ابتدا اطمینان حاصل کنید که در افزونه متامسک به رینکبای متصل هستید.
در Remix IDE، به زبانه اجرا (Deploy) بروید و در منوی باز شده به اسم محیط (Environment) گزینه Injected Web3 را انتخاب کنید. اطمینان حاصل کنید که فیلد حساب (Account) مطابق با آدرسی باشد که در آن سرمایه دارید تا تراکنش انجام شود. سایر فیلدها را میتوان بدون تغییر گذاشت.
اکنون، دکمه اجرا را کلیک کنید. پنجره متامسک باز خواهد شد و کارمزد گس که باید پرداخت کنید را نشان خواهد داد. با در نظر گرفتن این نکته که سرمایه کافی برای انجام تراکنش دارید، دکمه تایید (Confirm) را کلیک کنید.
پس از چند لحظه اعلانی دریافت خواهید کرد که قرارداد هوشمند اجرا شده است. در بخش پایینی زبانه اجرای تراکنش، قراردادهای اجرا شده (Deployed Contracts) را مشاهده خواهید کرد. بر روی < کلیک کنید تا توابع و متغیرهای عمومی قراردادها را مشاهده کنید. ما میتوانیم قرارداد هوشمند خود را قبل از آنکه در بازی قرار دهیم در این قسمت آزمایش کنیم.
آزمایش قرارداد هوشمند
ابتدا بر روی totalPlayers کلیک کنید. همانطور که انتظار میرود نتایج ۰ است. بنابراین چند رکورد امتیاز به قرارداد اضافه کنید. سپس در فیلد کنار دکمه setHighscore عدد ۴۲ را وارد کرده و سپس دکمه را کلیک کنید. متامسک از شما میخواهد تا کارمزد تراکنش را تایید کنید. اگر مجددا بر روی totalPlayers کلیک کنید، نتیجه ۱ را دریافت خواهید کرد.
توجه به این نکته بسیار مهم است که نوشتن قرارداد هوشمند منجر به تغییر وضعیت آن میشود، بنابراین با کارمزد تراکنش نیاز خواهد داشت. سایر توابع و متغیرهای عمومی در قرارداد هوشمند ما فقط خواندنی (read-only) هستند، بنابراین به کارمزد تراکنش نیازی نخواهند داشت.
سپس در فیلد کنار دکمه آدرسها، عدد ۰ را وارد کنید و سپس دکمه را کلیک کنید. همانطور که انتظار میرود، نتیجه همان آدرسی است که در حال حاضر در متامسک شما انتخاب شده است. اکنون آدرس را کپی کرده و در فیلد کنار دکمه getHighscore پیست کنید. سپس بر روی دکمه کلیک کنید و مشاهده کنید که ناحیه ۴۲ را دریافت کردهاید.
اکنون رکورد جدید دیگری وارد میکنیم. ابتدا در متامسک مقداری سرمایه به یکی دیگر از آدرسهای خود ارسال کنید. سپس به این آدرس وارد شوید. پس از آن، در فیلد کنار دکمه setHighscore، عدد ۲۱ را وارد کنید و سپس دکمه را کلیک کنید. پس از آن، در فیلد کنار دکمه آدرس ها (addresses) عدد ۱ را وارد کرده و دکمه را کلیک کنید. نتیجه باید آدرس انتخاب شده کنونی باشد. مجددا این آدرس را کپی کرده و در فیلد کنار دکمه getHighscore پیست کنید و دکمه را کلیک کنید. همانطور که انتظار میرود، نتیجه ۲۱ است و مشخصا نتیجه totalPlayers نیز ۲ خواهد بود.
تا اینجای کار، همه چیز به خوبی پیش رفته است. اگر تمایل دارید میتوانید با آدرس سوم نیز این موضوع را آزمایش کنید اما به نظر میرسد کافی است. بنابراین به برنامه نویسی بازی خود برمیگردیم تا قرارداد هوشمند اتریوم را فراخوانی کنیم.
اتصال بازی به اتریوم
در ویرایشگر کد به index.html برگردید. داخل تگ های <script>…</script> بلاک کد زیر را وارد کنید:
بارگذاری قرارداد هوشمند ما
اکنون به بارگذاری قرارداد هوشمند در بازی خود میپردازیم. همچنان داخل تگهای <script>…</script> و دقیقا بالاتر از تابع ()preload، کد زیر را داریم:
سپس باید رابط دودویی نرم افزار (application binary interface) قرارداد هوشمند خود را دریافت کنیم. میتوانید این موضوع را همانند API قرارداد خود در نظر بگیرید تا بازی ما بتواند با آن تعامل برقرار کند.
به Remix IDE برگردید و به زبانه کامپایلر سالیدیتی بروید. در پایین این زبانه، آیکنی با اسم ABI مشاهده خواهید کرد. بر روی این دکمه کلیک کنید تا قراردادهای ABI کپی شوند. اکنون میتوانید آن را به عنوان ورودی در تابع تازه اضافه شده به بازی پیست کنید. کدی همانند کد زیر به وجود میآید:
سپس به آدرس قرارداد هوشمند خود بر بستر شبکه آزمایشی راپستن (Ropsten) نیاز خواهید داشت. به Remix IDE برگردید و به زبانه اجرای تراکنشها بروید. در قسمت پایینی بر روی آیکن کلیپ بورد کلیک کنید تا آدرس قراردادهای ما کپی شود.
اکنون به کدنویسی بازی خود بر میگردیم. کد زیر را دقیقا پس از ABI مورد نظر HighscoreContract اضافه کنید:
آدرس را در ورودی فراخوانی تابع پیست کنید. کد ما باید به شکل زیر باشد:
اکنون بازی ما میتواند با قرارداد هوشمند تعامل برقرار کند.
تعامل با قرارداد هوشمند
در کدهای بازی، بخشی از تابع ()update را پیدا کنید که نوشتهایم TODO: // اکنون یک تابع کمکی مینویسیم تا با منطق بازی سروکار داشته باشد.
تابعی به اسم gameOver را تعریف میکنیم که ابتدا رکورد امتیاز کنونی بازیکن را دریافت خواهد کرد و سپس بررسی میکند که آیا رکورد جدید بیشتر از رکورد قبلی است یا خیر. اگر امتیاز جدید بیشتر از امتیاز قبلی باشد، این امتیاز را در قرارداد هوشمند خواهیم نوشت. این تابع را بالاتر از تابع ()update اضافه کنید:
با دقت این کد را بررسی کنید. این کد به دلیل کال بکهای زیاد ممکن است در ابتدا سردرگم کننده باشد. هدف این است که پس از پایان فراخوانی تابع ()getHighscore، تابع ()setHighscore را فراخوانی کنیم و امتیاز بالاتر بازیکن در قرارداد هوشمند ثبت شود.
اکنون اطمینان حاصل کنید که فراخوانی ()gameOver را به تابع ()update اضافه کنید:
اکنون به آزمایش بازی میپردازیم. بازی را ریفرش کنید و با حساب اول خود، بازی را امتحان کنید. توجه داشته باشید هنگامی که قرارداد را در Remix آزمایش میکردیم، تمام رکورد امتیازها در بازی باقی میماندند.
اگر میبینید که نمیتوانید رکورد امتیاز ۴۲ را بشکنید، با حساب دوم خود بازی کنید. به عنوان مثال اگر به رکورد امتیاز ۱۲ برسید از شما درخواست میشود تا تراکنش انجام دهید. سپس با حساب دیگری امتحان کنید. فارغ از امتیازی که دارید از شما خواسته میشود که تراکنش انجام دهید.
تبریک میگوییم! شما توانستید یک بازی ساده بلاک چین بسازید.
تمرین
- اعداد جادویی بسیار زیادی در کدهای ما استفاده شده است. برای مثال، میتوان سرعت بازیکن را با استفاده از ثابتی به اسم PLAYER_SPEED تعریف کرد، به این صورت که به جای استفاده از عدد ۲، اعداد صحیح به کار برد. اگر بخواهیم این مقدار را تغییر دهیم، میتوانیم ثابت مورد نظر را به عدد دیگری تغییر دهیم.
- ما تمام کد خود را در index.html قرار میدهیم. این موضوع به شدت سازماندهی نشده است. تمام توابع Phaser.js را میتوان در فایل جداگانهای به اسم Game.js تعریف کرد. تمام ثابتها را نیز میتوان در فایل Constants.js تعریف کرد. توابع کمکی را میتوان در فایلهای خود تعریف کرد.
- روش نشان دادن رکورد امتیاز بازیکن از طریق ()window.alert است. همچنین به خاطر داشته باشید که رکورد امتیاز سایر بازیکنها از داخل بازی قابل دسترسی است.
فرصتهایی برای بهبود بیشتر
این بازی چندان مورد پسند گیمرهای مبتدی که کوین در اختیار ندارند قرار نمیگیرد. این بازی به یک افزونه مرورگر با سیستم لاگین غیرمرسوم نیاز دارد.
به علاوه، از آنجایی که ثبت رکورد امتیاز در بلاک چین به تراکنش اتر نیاز دارد، بازیکن باید سرمایه خود را مدیریت کند.
اگرچه توسعه دهنده هنگام برنامه نویسی بازی بر بستر اتریوم باید دانش کامل از اتفاقات در حال انجام داشته باشد، بازیکن مبتدی نباید نگران این موضوعات باشد.
در این راهنما به این راهکارها نپرداختهایم؛ اما میتوانید به بررسی Portis به عنوان یکی از گزینههای لاگین مرسوم و Gas Station Network برای پرداخت تراکنشهای کوچک از جانب بازیکن بپردازید.
دلیل ساخت بازی بر بستر اتریوم چیست؟
یکی از شعارهای عرصه ارزهای دیجیتال این است که “آیا موضوع مورد نظر حتما باید بر بستر بلاک چین باشد یا میتواند بر روی دیتابیس نیز قرار گیرد؟”
قطعا این بازی ساده میتواند رکورد امتیازات را در دیتابیس ثبت کند. اما این شرایط را در نظر بگیرید که پول نیز در این بازی نقش دارد.
فرض کنید اجرای این بازی به پرداخت نیاز داشته باشد و پرداخت تمام بازیکنها منجر به ایجاد جایزه بزرگی شود. در اینجاست که ثبت امتیازات در دیتابیس متمرکز با مسائل امنیتی مواجه میشود و برنامه نویسی بازی بر بستر اتریوم، ویژگیهای بیشتری را ارائه میدهد.
ما در این راهنما درباره توکنهای غیرقابل تعویض (NFT) اصلا صحبت نکردیم. در عرصه ارزهای دیجیتال در خصوص استفاده از NFTها در گیمینگ به عنوان روشی برای ایجاد بازاری برای آیتمهای موجود در بازی، هیجان زیادی وجود دارد.
نتیجه گیری
اگرچه بازی ساخته شده به نظر بسیار ساده به نظر میرسد، اما امیدواریم که این راهنما برای شما مفید واقع شود و مقدمات برنامه نویسی بازی بر بستر اتریوم را یاد گرفته باشید. در مسیر تبدیل شدن به توسعه دهنده بازیها بر بستر اتریوم موفق باشید!