همه آن پوشه را دارند. همان پوشهای که پر از آموزشهای نیمهتمام، پروژههای جانبی رها شده و فایلهای README است که بیش از آنچه انجام میدهند، وعده میدهند. این گورستان نیتهای خوب است و تنها راه خروج، عرضه کردن چیزی است — هر چیزی — که واقعاً کار کند.
همان میل شدید به تمام کردن، انگیزهی خلق LIAR بود؛ یک بازی مرورگر که آنقدر کوچک و آنقدر بیرحم است که در قالب یک فایل HTML واحد با حجم تنها ۲۸ کیلوبایت جای میگیرد. بدون فریمورک. بدون فایلهای تصویری. بدون داراییهای صوتی. فقط HTML5 Canvas خالص، Web Audio API و یک رگهی بدجنسی.
ضد-آموزش
اکثر پروژههای یادگیری به این دلیل میمیرند که بیش از حد بزرگ میشوند. با یک آموزش Canvas شروع میکنید، یک اسکریپت حرکت اضافه میکنید، سپس تصمیم میگیرید که به یک ویرایشگر تایل (tile editor) نیاز دارید، بعد یک سیستم کامپوننت موجودیت (entity component system) و سپس یک پیکربندی Webpack که یازده ثانیه طول میکشد تا کامپایل شود. شش هفته بعد، شما یک خط لوله ساخت (build pipeline) دارید اما هیچ بازیای ندارید.
LIAR از این تله فرار میکند. این یک بازی واکنشی است. دکمهای به شما میگوید که TAP، HOLD یا DON'T کنید. شما باید قبل از تمام شدن تایمر عمل کنید. راندهای اولیه اعتماد ایجاد میکنند. متن میگوید TAP، شما ضربه میزنید. متن میگوید HOLD، شما انگشت خود را نگه میدارید. ساده، ریتمیک و تقریباً مراقبهگونه است.
سپس راند ششم از راه میرسد.
مکانیسمهای خیانت
حدود راند ششم، بازی شروع به دروغ گفتن میکند. دستوری روی صفحه چشمک میزند — شاید یک TAP قرمز، لرزان و خشن — و تمام واکنشهای بازتابی که در طول مرحله گرم کردن ساختهاید، فریاد میزنند که دکمه را فشار دهید. اگر این کار را انجام دهید، میبازید. لرزش قرمز یک باگ نیست؛ بلکه یک نشانه (tell) است. یک دروغگوی صادق به شما سرنخی میدهد و این بازی دقیقاً همین کار را میکند: یک دستور زبان بصری از فریبکاری.
این ترفند به این دلیل کار میکند که زیربنای بازی صادقانه است. راندهای اولیه به شما میآموزند که رنگ و حرکت معنا دارند. وقتی پالت رنگی ناگهان تغییر میکند و متن میلرزد، بازی تقلب نمیکند؛ بلکه در حال سیگنال دادن است. شما اطلاعات را داشتید؛ یا آن را خواندید یا نخواندید.
وقتی شکست میخورید، بازی به شما توهین میکند. این سوزشِ دلنازک، عمدی است. در یک بازی کوچک (micro-game) بدون جدول امتیازات و بدون پیشرفت دائمی، تحقیر، واحد پولِ تکرارپذیری (replayability) است. این کار حلقه بازخورد را میبندد. شما به دلیل لگ یا به دلیل نامناسب بودن ناحیه برخورد (hitbox) نمیبازید. شما میبازید چون به یک کلمه قرمز لرزان اعتماد کردید، و بازی اطمینان حاصل میکند که شما با آن اشتباه کنار بیایید.
۲۸ کیلوبایت واقعاً به چه معناست
انتخاب ساخت بازی در قالب یک فایل HTML واحد با حجم ۲۸ کیلوبایت، صرفاً یک نوآوری نیست؛ بلکه یک محدودیت طراحی است که تصمیمات سختی را تحمیل میکند. خبری از مگابایتها sprite sheet برای پنهان شدن پشت آنها نیست. هیچ فایل صوتی برای پخش کردن وجود ندارد. هر آنچه دیده میشود، فریمبهفریم روی یک HTML5 Canvas ترسیم میشود. هر آنچه شنیده میشود، از نوسانسازهای (oscillators) Web Audio میآید.
اگر مستقیماً با Web Audio API کار نکردهاید، این کار شامل چه چیزهایی است: به جای بارگذاری یک فایل WAV یا MP3 از پیش ضبط شده، کد یک AudioContext ایجاد میکند، یک oscillator node به آن متصل میکند، یک شکل موج — sine ،square ،sawtooth — را انتخاب میکند و یک فرکانس را تنظیم میکند. یک بوق کوتاه برای ورودی صحیح، و یک وزوز خشن برای شکست. این تنها به صورت آنی (real time) توسط مرورگر محاسبه میشوند. آنها هیچ هزینهای از نظر حجم فایل ندارند و هیچ درخواست شبکه خارجی ایجاد نمیکنند.
همین منطق برای بخش بصری نیز صدق میکند. Canvas به شما یک سطح ترسیم در حالت فوری (immediate-mode) میدهد. شما مستطیل را پاک میکنید. متن را پر میکنید. یک transform یا یک shadow blur برای اثر لرزش تنظیم میکنید. خبری از virtual DOM diffing، یا React reconciliation، یا dependency array برای عیبیابی نیست. مرورگر کد را اجرا میکند و پیکسلها ظاهر میشوند. برای بازیای با این میزان تمرکز، این مستقیم بودن یک ویژگی است، نه یک محدودیت.
نگه داشتن حجم محتوا (payload) در ۲۸ کیلوبایت همچنین به این معناست که بازی تقریباً بلافاصله در مرورگر موبایل، حتی با یک اتصال ضعیف، بارگذاری میشود. میزبانی کردن آن تقریباً هیچ هزینهای ندارد. کل اپلیکیشن کوچکتر از اکثر faviconهای وبسایتها است. اگر قرار باشد بازی را از طریق یک لینک مشترک توزیع کنید یا در یک انجمن قرار دهید، این موضوع اهمیت دارد. هیچ اصطکاکی برای نصب وجود ندارد. URL را باز میکنید و دروغ آماده است.
فریب منصفانه
صرف زمان واقعی روی مکانیسم دروغگویی، حقیقتی ظریف را درباره طراحی بازی آشکار میکند. ناعادلانه بودن تنها زمانی سرگرمکننده است که قابل درک باشد. یک تله تصادفی که بدون هشدار بازیکن را میکشد، طراحی بدی است. تلهای که میلرزد، رنگش تغییر میکند و ریتم بصریِ مستقر شده را میشکند، در واقع یک پازل است که در لباس یک کمین ظاهر شده است.
متن قرمز لرزان چندین هدف را دنبال میکند. این متن، پاسخهای عادتگونهای را که بازیکنان در راندهای اول تا پنجم ایجاد کرده بودند، خنثی میکند. این متن یک ضربآهنگ احساسی — شک، تردید، وحشت — را به چیزی که قبلاً یک تست واکنش بود، اضافه میکند. و مهمتر از همه، باعث میشود شکست، حسِ «مسئولیتپذیری» داشته باشد. وقتی روی آن دستور قرمز ضربه میزنید و توهین ظاهر میشود، میدانید که تقصیر با خودتان بوده است. بازی به شما یک نشانه داده بود؛ اما شما در خواندن آن شکست خوردید.
این تفاوت بین یک ضربه ناجوانمردانه و یک مبارزه منصفانه است. LIAR میخواهد به صورت شما مشت بزند، اما ابتدا تمام وزن خود را پشت این حرکت قرار میدهد.
اولویت با عرضه کردن است تا صیقل دادن
بازی خام است. خود نویسنده این را به شما خواهد گفت. این اولین بازی تمامشدهی اوست و سادگی، بهای به پایان رساندن آن بود. این صداقت در اکوسیستمی که توسعهدهندگان اغلب درباره سیستمهایی که هرگز به مرحله تولید نمیرسند وبلاگ مینویسند، بسیار تازگیبخش است. LIAR در یک URL زنده در دسترس است. میتوانید همین حالا آن را بازی کنید. میتوانید کد منبع را در یک فایل واحد، بدون نیاز به باز کردن پیچیدگیهای یک monorepo، مشاهده کنید.
توسعهدهنده از هر کسی که آنقدر شجاع هست که بازی را امتحان کند، میخواهد دو چیز را بداند. اول اینکه چقدر دوام میآورید؟ دوم اینکه وقتی اولین دروغ در راند ششم رخ میدهد، آیا منصفانه به نظر میرسد یا ناجوانمردانه؟ اینها سوالات درستی هستند. آنها با دروغ نه به عنوان یک باگ، بلکه به عنوان مکانیزمی که نیاز به تنظیم دارد، برخورد میکنند.
اگر علاقهمندی وجود داشته باشد، آنها پیشنهاد دادهاند راهنمای عمیقتری بنویسند که حلقه ترسیم Canvas، منطق پشت نوسانسازهای Web Audio و دقیقاً نحوه ساختار مکانیزم دروغ در کد را پوشش دهد. با توجه به اینکه دیدن یک بازی کامل در قالب یک فایل HTML بسیار نادر است، آن راهنما برای هر کسی که در «برزخ آموزشها» گیر کرده است، واقعاً مفید خواهد بود.
نکته اصلی
برای ساخت یک بازی، نیازی به موتور بازیسازی ندارید. نیازی به شبکه توزیع محتوا (CDN) برای داراییها، یا یک سند طراحی بیست صفحهای، یا اجازه از نگهدارنده یک فریمورک ندارید. شما به یک مرز نیاز دارید — در اینجا، ۲۸ کیلوبایت و یک فایل واحد — و دلیلی برای تمام کردن. محدودیتها باعث شفافیت میشوند. وقتی مکانیزم زیربنایی مستحکم باشد، یک کلمه قرمز لرزان، ماندگارتر از هزاران اسپرایت وارد شده است.
خودتان LIAR را در https://playliar.netlify.app/ بازی کنید.
میتوانید تحلیل اصلی توسعهدهنده و بافتار کد منبع را در https://dev.to/shabbir_sesaifee_8fdc587/i-built-a-game-that-lies-to-you-in-a-single-28kb-html-file-no-framework-no-assets-4hnh بخوانید.
