ساخت یه بازی با نقشهٔ تصادفی با PHP
خلاصهٔ کاملتر
برنت روس تو این مقاله یه بازی دوبعدی ساده با محوریت جمعآوری منابع رو با PHP میسازه که نقشهش procedurally generated هست، یعنی نقشه رو کد از روی یه عدد به اسم seed میسازه و هر seed یه نقشهٔ کاملاً متفاوت میده. نقطهٔ شروع یه گرید ۱۵۰ در ۱۰۰ پیکسله که هر پیکسلش یه div روی CSS grid هست. نویسنده میگه بعداً میشه سراغ canvas رفت، ولی grid آماده کلی وقت صرفهجویی میکنه.
قدم بعدی نویز هست، یعنی به هر پیکسل یه عدد بین ۰ و ۱ دادن. اول با rand() شروع میکنه، ولی عدد تصادفی هر بار یه نقشهٔ جدید میده. پس میره سراغ یه تابع hash که برای یه نقطه و seed مشخص همیشه همون عدد رو برگردونه. ضرب سادهٔ seed در مختصات به اندازهٔ کافی تصادفی نیست، برای همین از الگوریتم xxh32 استفاده میکنه که PHP خودش پشتیبانی میکنه و خیلی سریعه. بعد مقدار رو برای هر مربع ۱۰ پیکسلی یکی میکنه و ازش جذر میگیره تا عددها کمی بالاتر برن.
حالا اگه پیکسلهای بالای 0.6 رو خشکی (سبز) و بقیه رو آب (آبی) حساب کنی، یه چیزی شبیه نقشه درمیاد، ولی لبهها خیلی تیز و مربعیان. راهحل lerp هست (Linear Interpolation، یعنی پیدا کردن عددی بین دو عدد بر اساس یه کسر):
function lerp(float $a, float $b, float $fraction): float
{
return $a + $fraction * ($b - $a);
}
lerp(0.34, 0.78, 0.5); // 0.56نویسنده فقط پیکسلهایی رو که روی یه شبکهٔ ۱۰ در ۱۰ هستن مستقیم hash میکنه و بقیه رو از روی همین نقاط ثابت درونیابی میکنه. برای پیکسلهایی که روی خطوط شبکهان، یه lerp ساده بین دو نقطهٔ بالا/پایین یا چپ/راست کافیه. برای بقیه از Bilinear Interpolation استفاده میکنه، یعنی دو بار lerp روی محور x بین چهار گوشه، و بعد یه lerp نهایی روی محور y. نتیجه یه انتقال نرم بین مقدارهاست.
با این حال مرزها هنوز زبر به نظر میان، و نویسنده دو ترفند دیگه اضافه میکنه. اول یه shaping function به اسم smoothstep که قبل از lerp کسر رو طوری تغییر میده که نزدیک لبهها نرمتر بشه؛ خودش میگه تفاوتش ظریفه ولی کمی بهتره. دوم یه لایهٔ نویز دایرهای که مثل یه نقشهٔ ارتفاع روی نویز قبلی میشینه: هر چی پیکسل از مرکز دورتر باشه، مقدارش کمتر میشه. یعنی لبههای نقشه بیشتر آب میشن و وسطش خشکی، و نقشه شکل جزیره پیدا میکنه.
نکات کلیدی:
- هر seed همیشه دقیقاً همون نقشه رو تولید میکنه، چون بهجای rand() از hash استفاده میشه.
- برای hash از الگوریتم xxh32 استفاده شده که تو PHP داخلیه و سریعه.
- آستانهٔ 0.6 مرز بین آب و خشکی رو تعیین میکنه.
- نقاط ثابت روی شبکهٔ ۱۰ در ۱۰ hash میشن و بقیهٔ پیکسلها با lerp و Bilinear Interpolation پر میشن.
- smoothstep لبهها رو نرمتر میکنه و نویز دایرهای نقشه رو شبیه جزیره میکنه.




