مسئلهای که باید حل میکردم
وقتی صدا، رابط و گزارشگیری همگی به بازی واکنش نشان میدهند، وصلکردن مستقیم آنها به هر قانون وابستگی زیادی ایجاد میکنه. من یک مرز رویدادی ساده لازم داشتم.
پیادهسازی در نسخهٔ فعلی
GameEventBus برای CardPlayed، RoundStarted، RoundEnded، GameStarted و GameEnded رویدادهای نوعدار داره. متدهای Publish همان داده را به مشترکهای موجود منتقل میکنند.
تصمیم و هزینهٔ طراحی
نوعدار بودن کمک میکنه مصرفکننده قرارداد مشخصی داشته باشد. در عوض، این گذرگاه یک سامانهٔ پیام توزیعشده نیست؛ فراخوانی مشترکها در همان مسیر اجرا اتفاق میافتد.
مرزهای فعلی
کد گذرگاه استثنای هر مشترک را جدا نمیگیرد. عمر اشتراکها هم مسئولیت مصرفکننده هست؛ وجود event بهتنهایی به معنای جلوگیری از نشت یا قطع وابستگی کامل نیست.
رویداد کارت، نتیجهٔ معتبر یا درخواست؟
فرض کن بازیکن کارت نامعتبر را لمس میکنه و رابط میخواهد صدا و حرکت آن را آغاز کنه. اگر CardPlayed پیش از تأیید قانون منتشر بشه، شنوندهها رخدادی را واقعی فرض میکنند که بازی هنوز نپذیرفته هست. GameEventBus هیچ بررسی مالکیت، خال یا نوبتی داخل PublishCardPlayed نداره؛ فقط eventData را منتقل میکنه. بنابراین قرارداد زمانی مهمتر از نام متد هست: مسیر بازی باید ابتدا اعتبار حرکت و تغییر وضعیت لازم را روشن کنه و سپس رخداد مناسب را اعلام کنه. خود این کلاس ترتیب درست فراخوانیهای بیرونی را تحمیل نمیکنه.
CardPlayedEvent بازیکن، نمونهٔ کارت، تعداد کارتهای میز و ترتیب بازی شدن را حمل میکنه. چنین دادهای اجازه میدهد شنونده بدون تفسیر متن روی دکمه بفهمد کدوم کارت مطرح هست. با این حال، داشتن property خواندنی به معنای گرفتن کپی مستقل از RuntimePlayer نیست. اگر شنونده بعداً همان مرجع را بررسی کنه، ممکنه وضعیت بازیکن تغییر کرده باشد. برای ثبت تاریخی باید مشخص کرد کدوم مقادیر در لحظهٔ رخداد ذخیره میشوند و کدامها ارجاع زندهاند؛ این تصمیم را نمیتوان صرفاً از نام Event نتیجه گرفت.
Publishها از فراخوانی مستقیم delegate استفاده میکنند و صف، زمانبندی جدا یا پردازش پسزمینه نمیسازند. اگر یک شنونده کار سنگینی انجام دهد، همان مسیر انتشار را طولانی میکنه؛ اگر استثنا بدهد، کلاس حلقهٔ محافظتشدهای برای ادامهٔ شنوندههای دیگر نداره. این محدودیت دلیل حذف رویداد نیست، بلکه دلیل کوچک نگه داشتن واکنشها و مدیریت عمر اتصال هست. در یک صحنهٔ Unity، فعال و غیرفعال شدن اجزا میتواند تکرار اشتراک بسازد؛ مصرفکننده باید ثبت و لغو ثبت را متقارن نگه داره و تصور نکند باس این مسئولیت را از او گرفته هست.
چیزی که از این مرحله یاد گرفتم
برای من، رویداد زبان گزارش یک اتفاق هست. قانون باید ابتدا اتفاق معتبر را بسازد، سپس نمایش و صدا به آن واکنش نشان دهند؛ رویداد نباید جای اعتبارسنجی خود بازی را بگیرد.
مثال عملی مرز رویداد و نمایش
برای فهم عملی مرز رویداد و نمایش، یک مثال آموزشی را قدمبهقدم دنبال کنیم. پایان یک حرکت هم باید امتیاز را تغییر دهد و هم انیمیشن کارت را آغاز کند. پیش از اجرا، وضعیت آغاز را روی کاغذ بنویس؛ مشخص کن چه چیزی میتواند تغییر کند و چه چیزی باید ثابت بماند. بعد فقط همین مسیر را اجرا کن. این مثال گزارشی از آمار کاربران یا قابلیت تازهٔ منتشرشدهٔ دلو نیست؛ تمرینی برای روشن کردن تصمیم طراحی همین مطلب است.
خطای رایج و علت آن
اگر نمایش قانون را دوباره اجرا کند، یک رویداد میتواند دو بار امتیاز بسازد. این خطا معمولاً وقتی پنهان میماند که فقط مسیر موفق و ظاهر نهایی را ببینیم. برای پیدا کردن علت، آخرین وضعیت درست را از نخستین وضعیت نادرست جدا کن و ببین تغییر دقیقاً در کدام مرز رخ داده است. رویداد خبر تغییر است؛ مجوز ایجاد همان تغییر نباید در همهٔ شنوندهها پخش شود. اگر این تفاوت در قرارداد مشخص نباشد، اصلاح یک نشانه ممکن است همان مسئله را در بخش دیگری دوباره ایجاد کند.
چطور نتیجه را بررسی کنیم؟
با دو نمایش متفاوت، نتیجهٔ منطقی باید یکسان بماند و تعداد اعلانها مشخص باشد. اجرای یکباره برای نتیجهگیری کافی نیست؛ یک بار مسیر معمول و بار دیگر همان موقعیت را با ورودی مرزی یا تکرار اقدام بررسی کن. اگر نتیجه فرق دارد، ورودی و شرایط اجرا را همراه خروجی نگه دار تا مقایسه قابل بازسازی باشد. جدول زیر خلاصهٔ مشخصات همین سناریو است و برای ثبت نتیجهٔ بررسی به کار میآید.
| بخش بررسی | آنچه باید ثبت شود |
|---|---|
| موقعیت آزمایشی | پایان یک حرکت هم باید امتیاز را تغییر دهد و هم انیمیشن کارت را آغاز کند. |
| ریسک اصلی | اگر نمایش قانون را دوباره اجرا کند، یک رویداد میتواند دو بار امتیاز بسازد. |
| روش بررسی | با دو نمایش متفاوت، نتیجهٔ منطقی باید یکسان بماند و تعداد اعلانها مشخص باشد. |
| مرز نتیجهگیری | رویداد خبر تغییر است؛ مجوز ایجاد همان تغییر نباید در همهٔ شنوندهها پخش شود. |
پرسشهای کاربردی دربارهٔ مرز رویداد و نمایش
از کجا شروع کنم؟
از همان موقعیت محدود این مطلب شروع کن: پایان یک حرکت هم باید امتیاز را تغییر دهد و هم انیمیشن کارت را آغاز کند. ابتدا نتیجهٔ مورد انتظار را مشخص کن و بعد سراغ پیادهسازی یا ابزار برو. وقتی مسیر پایه قابل توضیح و بررسی شد، میتوان حالتهای بیشتری اضافه کرد. ساخت همهٔ حالتها از ابتدا، فهم علت خطا را سختتر میکند.
چه زمانی میتوانم بگویم این بخش درست کار میکند؟
زمانی که رفتار در موقعیت تعریفشده با قرارداد سازگار باشد و محدودیتهای آن روشن بمانند. با دو نمایش متفاوت، نتیجهٔ منطقی باید یکسان بماند و تعداد اعلانها مشخص باشد. موفقیت در این آزمون دربارهٔ همان سناریو شاهد میدهد؛ از آن نمیتوان بدون بررسی دربارهٔ همهٔ دستگاهها، همهٔ قوانین محلی یا همهٔ حجمهای داده نتیجه گرفت. رویداد خبر تغییر است؛ مجوز ایجاد همان تغییر نباید در همهٔ شنوندهها پخش شود.
برای ادامهٔ همین موضوع، هستهٔ مشترک دلو؛ یک میز برای چند بازی و بازی دلو را ببین. زمینهٔ ساخت این پروژهها و معرفی سازنده در صفحهٔ کیان پاک نعمت آمده است.




