Turn the game into a third-person Mashhad city game

Replace the linear forest walk with an open area of real western Mashhad
built from OpenStreetMap data, starting at Park Mellat. A father and child,
guided by the Robot Market robot, find vending machines at a park, school,
universities, a metro station and a mall, on foot or by car.

- Iran province briefing map; only Mashhad is unlocked
- Third-person camera, building collision, arcade car and ambient traffic
- Minimap and full city map with addresses, opening hours and A* routing
- Purchase scoring, missions with cash rewards, ranks and an end screen
- Map data build script (OSM + Natural Earth) and new logic tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 11:27:48 +03:30
co-authored by Claude Opus 5.5
parent 8a49dc07fa
commit 95a2ae851d
31 changed files with 3131 additions and 2770 deletions
+60 -43
View File
@@ -1,14 +1,46 @@
# تپهٔ آرزوها — روبات مارکت
# عملیات مشهد — روبات مارکت
بازی سه‌بعدی JavaScript با Three.js: پدر و بچه در جنگل راه می‌روند، از دستگاه خرید می‌کنند و به پیک‌نیک می‌رسند. مدل‌ها با کد ساخته شده‌اند. شخصیت کودک با روبات فیروزه‌ای و سفید Robot Market، الهام‌گرفته از تصویر مرجع، جایگزین شده است؛ پدر همراه او باقی می‌ماند. روبات دارای صورت نورانی، آنتن و انیمیشن راه‌رفتن، دریافت محصول و نشستن است.
بازی سه‌بعدی مرورگری (Three.js) با حال‌وهوای بازی‌های اکشن سوم‌شخص، بدون سلاح و خشونت. یک پدر و فرزندش، همراه روبات راهنمای روبات مارکت، در خیابان‌های واقعی مشهد می‌گردند، دستگاه‌های وندینگ روبات مارکت را پیدا می‌کنند و با هر خرید امتیاز می‌گیرند.
🎮 [اجرای آنلاین بازی](https://hamedabdollahzade.github.io/vending-machine-game/)
## انتشار در GitHub Pages
## داستان و هدف
در تنظیمات مخزن، بخش **Settings → Pages → Build and deployment**، گزینهٔ **Source** را روی **GitHub Actions** قرار دهید. انتشار مستقیم از `main / (root)` مناسب این پروژه نیست: فایل‌های سورس باید ابتدا با Vite ساخته شوند تا JavaScript، استایل‌ها و وابستگی‌ها برای مرورگر آماده شوند.
- **شروع:** ورودی جنوبی بوستان ملت، بزرگراه وکیل‌آباد
- **نقشهٔ ایران:** صفحهٔ توجیه مأموریت نقشهٔ استان‌های ایران را نشان می‌دهد. فعلاً فقط مشهد (خراسان رضوی) باز است و شهرهای دیگر قفل‌اند.
- **محدودهٔ قابل بازی:** حدود ۴٫۸ در ۳٫۳ کیلومتر از غرب مشهد، شامل بوستان ملت، دانشگاه فردوسی، دانشگاه علوم پزشکی، ایستگاه‌های مترو و مشهد مال. خیابان‌ها، ساختمان‌ها و پارک‌ها از داده‌های واقعی OpenStreetMap ساخته شده‌اند.
- **دستگاه‌ها:** بوستان ملت، مجموعه آموزشی راحیل (فقط ۷:۳۰ تا ۱۳:۳۰)، دانشگاه فردوسی و دانشکدهٔ ادبیات (۲۰٪ تخفیف دانشجویی)، دانشگاه علوم پزشکی، ایستگاه مترو آزادی، مشهد مال (از ساعت ۱۰). همهٔ دستگاه‌ها و محصولاتشان فرضی‌اند.
گردش‌کار `.github/workflows/pages.yml` با هر push به `main` تست‌ها و build را اجرا می‌کند و فقط خروجی `dist` را منتشر می‌کند. پس از تغییر Source، تغییرات را به `main` بفرستید یا از بخش **Actions** گردش‌کار **Deploy game to GitHub Pages** را دستی اجرا کنید. تنظیم `base: './'` در Vite مسیر فایل‌های خروجی را با زیرمسیر مخزن سازگار نگه می‌دارد.
## کنترل
| کار | صفحه‌کلید | موبایل |
|---|---|---|
| حرکت / رانندگی | W A S D یا جهت‌ها | جوی‌استیک |
| دویدن | Shift | دکمهٔ «دویدن» |
| چرخاندن دوربین | ماوس (با کلیک قفل می‌شود) یا کشیدن | کشیدن روی صفحه |
| زوم دوربین | چرخ ماوس | — |
| سوار و پیاده شدن از ماشین | F | دکمهٔ F |
| خرید از دستگاه | E | دکمهٔ E |
| کشیدن کارت | C | دکمهٔ E |
| ترمز دستی | Space | — |
| نقشهٔ شهر | M یا کلیک روی نقشهٔ گوشه | لمس نقشه |
کنترل‌ها با صفحه‌کلید فارسی هم کار می‌کنند. دوربین فقط سوم‌شخص است.
## نقشه و مسیریابی
با کلیک روی نقشهٔ گرد گوشهٔ صفحه، نقشهٔ کامل شهر باز می‌شود. فهرست دستگاه‌ها با آدرس، ساعت کاری، باز یا بسته بودن، محصولات و فاصله نمایش داده می‌شود. «مسیریابی تا اینجا» مسیر را روی شبکهٔ واقعی خیابان‌ها پیدا می‌کند (پیاده روی همهٔ مسیرها، با ماشین فقط روی خیابان‌های سواره‌رو). مسیر به شکل خط طلایی روی زمین، روی نقشهٔ گوشه و روی قطب‌نمای بالای صفحه نمایش داده می‌شود. بدون انتخاب دستی، هدف مأموریت فعلی مقصد است.
## امتیاز
| رویداد | امتیاز |
|---|---|
| هر خرید | ۱۰۰ |
| اولین خرید در هر مکان (کشف) | ۲۵۰ |
| خرید نوشیدنی و خوراکی از یک دستگاه | ۱۵۰ |
| خرید از هر پنج نوع مکان | ۵۰۰ |
شش مأموریت امتیاز و پاداش نقدی (هتومان) دارند. درجه‌ها از «تازه‌وارد» تا «افسانهٔ مشهد» بالا می‌روند. بودجهٔ اولیه ۵۰۰ هتومان است (۱۰ هتومان = ۱۰۰٬۰۰۰ ریال). وقتی پول کافی برای هیچ خریدی نماند، یا همهٔ مأموریت‌ها انجام شود، عملیات تمام می‌شود. هر ثانیهٔ واقعی ده ثانیه از ساعت بازی است.
## اجرا
@@ -19,51 +51,36 @@ npm run build
node --test tests/*.test.js
```
## کنترل
- `?quality=low` یا دکمهٔ «گرافیک» سایه‌ها را خاموش می‌کند (پیش‌فرض گوشی‌ها).
- `?debug` وضعیت بازی را در `window.game` در دسترس می‌گذارد.
- چپ / راست یا A / D: حرکت
- بالا / پایین: زوم دوربین، بدون حرکت شخصیت
- دکمه‌های چهارجهته: نگه داشتن برای حرکت یا زوم در موبایل
- E یا دکمهٔ محصولات: باز کردن دستگاه در نزدیکی آن
- شروع دوباره: بازنشانی داستان، موجودی و زوم
## ساخت دوبارهٔ دادهٔ نقشه
گفت‌وگوها کوتاه‌اند و در کادر سفید پایین صفحه خودکار عوض می‌شوند. هنگام گفت‌وگوها، خرید، تحویل محصول یا باز بودن دفترچه حرکت موقتاً متوقف می‌شود.
`src/data/mellat.json` و `src/data/iran.json` از خروجی خام OpenStreetMap (Overpass API) و Natural Earth ساخته می‌شوند. کوئری‌ها در ابتدای اسکریپت آمده‌اند:
## دستگاه ۶۰ کانال و خرید با هتومان
```sh
node scripts/build-map-data.mjs city-osm.json poi-osm.json ne_10m_admin_1_states_provinces.geojson
```
واحد بازی «هتومان» است: **۱۰ هتومان = ۱۰۰٬۰۰۰ ریال**، یعنی هر هتومان ۱۰٬۰۰۰ ریال. موجودی اولیه ۵۰۰ هتومان است. همهٔ اعداد و قیمت‌ها نمایشی‌اند و پرداخت واقعی ندارند.
دستگاه شش ردیف ده‌تایی با شماره‌های ۱ تا ۶۰ دارد. فقط کانال‌های **۲۱ تا ۶۰** قابل خریدند. با نزدیک شدن به دستگاه، نشان E / تعامل روی کارت‌خوان نمایش داده می‌شود. با E یا لمس نشان، پنجرهٔ خرید باز می‌شود: فقط شماره‌های ۲۱ تا ۶۰ سمت راست و کد، محصول فرضی و قیمت کانال‌های قابل خرید سمت چپ قرار دارند. کلیک روی شماره یا محصول، کد را پر می‌کند؛ «پرداخت» یا Enter مرحلهٔ کارت‌خوان را باز می‌کند. دوربین به کارت‌خوان نزدیک می‌شود؛ سپس با دکمهٔ «کشیدن کارت» یا کلید C مبلغ کسر می‌شود، پیام خرید موفق نمایش داده می‌شود و محصول تحویل داده می‌شود. پیش از کارت کشیدن امکان انصراف بدون کسر موجودی وجود دارد. کدهای فارسی، عربی و انگلیسی پشتیبانی می‌شوند. کانال نامعتبر پول کم نمی‌کند. توضیح تبدیل واحد هم کنار دستگاه و هم داخل پنجره نمایش داده می‌شود.
محصولات فرضی بین کانال‌ها تکرار می‌شوند: آب‌میوه ۳۵، آب ۱۵، بیسکویت ۲۵، شیرکاکائو ۴۰، چای سرد ۴۵، لیموناد ۴۰، شکلات ۳۰، آجیل ۶۵ و کیک ۳۵ هتومان. مسیر تحویل از کانال انتخاب‌شده شروع می‌شود. برای تکمیل مأموریت، هزینهٔ حداقل یک نوشیدنی و یک خوراکی کنار گذاشته می‌شود.
برای اضافه کردن محدودهٔ جدید، bbox اسکریپت و `ORIGIN` در `src/geo.js` را تغییر دهید.
## ساختار
- `src/main.js`: صحنه، دوربین، دستگاه، رابط و حلقهٔ بازی
- `src/controls.js`: جهت حرکت و شرایط مجاز بودن حرکت؛ دیالوگ حرکت را موقتاً متوقف می‌کند
- `src/characters.js`: شخصیت‌های مفصلی، تناسب بدن، لباس، چشم‌ها، قدم زدن و تماس دست‌ها
- `src/payment.js`: مراحل پرداخت، انصراف و جلوگیری از برداشت تکراری
- `src/game-state.js`: قیمت‌های هتومان، موجودی، اعتبارسنجی کد و خرید
- `src/story.js`: متن‌های کوتاه، فصل‌ها، انتخاب مسیر و کشف‌ها
- `src/style.css`: چیدمان واکنش‌گرا و کادر سفید متن
- `tests/`: آزمون مسیر داستان، حرکت، پول و تبدیل‌های شخصیت‌ها
- `src/main.js`: صحنه، دوربین سوم‌شخص، کنترل‌ها، رابط کاربری (HUD)، نقشه، خرید و حلقهٔ بازی
- `src/city.js`: ساخت شهر سه‌بعدی از داده‌ها (خیابان، پیاده‌رو، ساختمان، پارک، درخت، ورودی مترو، کوه‌ها)
- `src/map-render.js`: نقشهٔ گوشه، نقشهٔ کامل شهر و نقشهٔ ایران
- `src/routing.js`: گراف خیابان‌ها، مسیریابی A* و پیدا کردن نام خیابان
- `src/collision.js`: برخورد با ساختمان‌ها برای شخصیت‌ها، ماشین و دوربین
- `src/locations.js`: دستگاه‌ها، آدرس‌ها، ساعت کاری و محصولات
- `src/game-state.js`، `src/payment.js`، `src/scoring.js`: پول، خرید، پرداخت، امتیاز، درجه و مأموریت‌ها
- `src/characters.js`: پدر، فرزند و روبات راهنما
- `src/vending.js`، `src/vehicle.js`، `src/traffic.js`: مدل دستگاه، فیزیک ماشین و ترافیک شهری
- `src/geo.js`: تبدیل طول و عرض جغرافیایی به مختصات بازی
قیمت‌ها و موجودی فقط در ماژول game-state تعریف شده‌اند. محاسبات با هتومان صحیح انجام می‌شود؛ رابط با ارقام فارسی نمایش می‌دهد.
## محدودیت‌ها و گام‌های بعدی
## محدودیت‌ها
- مدل‌ها هندسی و سبک‌اند و کیفیت گرافیکی بازی‌های AAA را ندارند.
- خیابان‌ها یک‌طرفه و چراغ راهنمایی ندارند، و ترافیک فقط روی بلوارهای اصلی است.
- پیشنهادهای بعدی: امتیاز ایمنی (خط عابر و چراغ قرمز)، تاکسی و قطار شهری، چرخهٔ روز و شب، ذخیرهٔ پیشرفت، جدول امتیاز آنلاین، و محله‌ها و شهرهای دیگر.
مدل‌ها هنوز هندسی و سبک هستند؛ تناسب بدن و حرکت طبیعی‌تر شده اما مدل انسانی واقع‌گرایانه یا موشن‌کپچر اضافه نشده است. پرداخت واقعی، ذخیرهٔ پیشرفت و برخورد آزاد با درخت‌ها وجود ندارد. بازیکن در مسیر تعیین‌شده حرکت می‌کند. زمان کامل تجربه هنوز با بازیکن اندازه‌گیری نشده است.
پنجره‌های خرید، دفترچه، پایان و پرداخت پس‌زمینهٔ شیشه‌ای نیمه‌شفاف دارند. نشان تعامل به موقعیت سه‌بعدی دستگاه متصل است و با حرکت دوربین جابه‌جا می‌شود.
## تعامل تک‌دکمه‌ای
گزینه‌های چندانتخابی داستان حذف شده‌اند. هر رویداد یک کار مشخص دارد: تماشای خرگوش، برداشتن نقاشی، ادامه در مسیر آفتابی و کامل کردن نقاشی با آسمان طلایی. برای انجام آن، کلید **F** یا همان دکمهٔ روی صفحه را بزنید. متن‌های معمولی خودکار عوض می‌شوند و پس از پایان گفت‌وگو حرکت دوباره آزاد می‌شود. **E** تعامل با دستگاه و **C** کشیدن کارت است. انتخاب شمارهٔ محصول و دکمهٔ پرداخت در پنجرهٔ دستگاه باقی است.
## سفر از خانه به کوه
بازی با خروج خانواده از خانه شروع می‌شود. با F یا دکمهٔ روی صفحه سوار ماشین شوید؛ با W یا ↑ گاز بدهید، با S یا ↓ ترمز کنید و با A/D فرمان بدهید؛ پس از رسیدن به ورودی جنگل، در ورودی جنگل دوباره F را بزنید تا پیاده شوید. در مسیر جنگل، جمعی از دخترها و پسرها کنار آتش می‌رقصند و خانواده آدرس دستگاه وندینگ را از آن‌ها می‌پرسد. پس از خرید نوشیدنی و خوراکی، مسیر را تا پیک‌نیک بالای کوه ادامه دهید.
دوربین پیش‌فرض سوم‌شخص است؛ با V یا دکمهٔ تغییر دوربین بین نمای اول‌شخص و سوم‌شخص جابه‌جا شوید. برای نگاه به اطراف در نمای اول‌شخص یا چرخاندن دوربین در نمای سوم‌شخص روی صحنه بکشید؛ هنگام تمرکز خودکار روی رویدادها و دستگاه، نمای دوربین ثابت است. W/S یا چپ/راست حرکت در مسیر و Shift دویدن است. این نسخه از مدل‌های هندسی استفاده می‌کند و کیفیت گرافیکی یک بازی AAA ندارد.
گفت‌وگوی هر رویداد هنگام رسیدن به همان نقطه نمایش داده می‌شود و تا پایان آن حرکت متوقف می‌ماند. دوربین نزدیک دستگاه خودکار روی آن تمرکز می‌کند. خانواده پس از رسیدن به قله روی فرش می‌نشینند.
نقشه: © مشارکت‌کنندگان OpenStreetMap (ODbL). مرز استان‌ها: Natural Earth.