بازی Snake
بازی آرکید مدرن مبتنی بر مرورگر
این پروژه یک بازی Snake مدرن و مبتنی بر مرورگر است که با React و TypeScript ساخته شده و تجربهای شبیه بازیهای کلاسیک آرکید را با رابط کاربری polished روی دسکتاپ و موبایل ارائه میدهد. تمرکز سیستم روی جداسازی منطق بازی از UI، چیدمان واکنشگرا و بهروزرسانی پایدار state در یک game loop با بازه زمانی ثابت است.
محور اصلی پروژه، مدیریت قابلپیشبینی state بازی، پشتیبانی از ورودی در دستگاههای مختلف و حفظ عملکرد روان بدون re-renderهای غیرضروری است.
تکنولوژیها
React 19TypeScript 6Vite 8Plain CSSCSS GridlocalStorage
ویژگیها
- گیمپلی کلاسیک Snake با تشخیص برخورد با خود
- Wrap-around دیوارها (خروج از یک لبه و ورود از لبه مقابل)
- ۱۰ سطح قابل تنظیم برای سرعت بازی
- ذخیره و نمایش بهترین امتیاز بین sessionها
- غذاهای تصادفی با emoji
- کنترل دسکتاپ (Arrow keys / WASD) با قابلیت Pause (Space / Esc)
- UI سازگار با موبایل و مقیاسپذیری خودکار صفحه بازی
- D-pad روی صفحه و پشتیبانی از swipe روی بورد
- پشتیبانی از safe-area برای دستگاههای notchدار
- تم تیره با پنلهای glassmorphism و انیمیشنهای روان
نقش من در پروژه
توسعهدهنده Front-End (React / TypeScript)
مسئول پیادهسازی منطق بازی، UI/UX، چیدمان واکنشگرا، مدیریت ورودی (کیبورد، لمس، swipe)، state management و persistence محلی.
چالشها و تمرکز پروژه
اجرای پایدار game loop با state در React بدون race condition یا directionهای stale، پشتیبانی همزمان از چند روش ورودی (کیبورد، D-pad، swipe) با رفتار یکسان، واکنشگرا کردن کامل بورد بازی در صفحهنمایشهای کوچک بدون بههمریختن grid، جلوگیری از تغییر جهت نامعتبر (مثل چرخش ۱۸۰ درجه فوری)، ذخیرهسازی پایدار تنظیمات کاربر (سرعت و high score) در مرورگر
تصمیمهای فنی
Custom Hook برای منطق بازی (useSnakeGame)
تمام state و قوانین اصلی بازی در یک hook اختصاصی قرار گرفته تا کامپوننت UI فقط روی رندر و تعامل تمرکز کند.
استفاده از useRef برای Direction
جهت فعلی در ref نگهداری میشود تا در tickهای interval-based مقدار stale نشود و از حرکت معکوس نامعتبر جلوگیری شود.
جداسازی Logic، UI و Utilities
قوانین بازی، رندرینگ و توابع کمکی (تولید غذا، wrap کردن مختصات، محاسبه سرعت) در ماژولهای جداگانه قرار گرفتهاند.
CSS Grid برای بورد بازی
بهجای Canvas از CSS Grid استفاده شده تا استایلدهی، نمایش emoji و scale واکنشگرا سادهتر باشد.
CSS خالص بهجای UI Framework
برای کنترل کامل روی انیمیشنها، افکت glassmorphism و layout موبایل بدون وابستگی اضافه انتخاب شد.
localStorage برای Persistence سبک
high score و سطح سرعت بدون backend ذخیره میشوند و اپ کاملاً static و قابل deploy روی هر host باقی میماند.
بهینهسازیها و راهحلها
- استفاده از functional state update در tick بازی برای سازگاری با batching در React
- Memoization با useCallback برای تغییر جهت، reset و pause
- محاسبه dynamic اندازه cell بر اساس عرض viewport برای fit شدن در موبایل
- مسدود کردن حرکت در جهت مخالف برای جلوگیری از self-collision تصادفی
- منطق spawn غذا بدون overlap با بدنه snake
Trade-offها و ملاحظات مهندسی
- CSS Grid بهجای Canvas برای سادگی و انعطاف استایل انتخاب شد، اما برای gridهای خیلی بزرگ یا افکتهای پیشرفتهتر محدودتر است.
- game loop با setInterval پیاده شده نه requestAnimationFrame؛ سادهتر است اما کمتر با refresh rate صفحه sync میشود.
- backend و multiplayer عمداً حذف شده تا پروژه سبک و fully static بماند.
- ورودی touch و keyboard یک handler مشترک دارند و برخی trade-offهای UX موبایل پذیرفته شده (مثل نبود حرکت diagonal).
نتیجه
این پروژه نشان میدهد که فراتر از UI ساده، میتوان state بلادرنگ را در React مدیریت کرد، تعامل cross-device طراحی کرد و یک codebase کوچک را readable و قابل توسعه نگه داشت. تمرکز روی UX (بورد واکنشگرا، swipe، persistence) است، در حالی که معماری ساده و قابل نگهداری باقی مانده.