Khi quyết định mọi game puzzle mới ở studio sẽ chạy trên một codebase, câu hỏi đầu tiên không phải "pattern nào" mà là "tường ở đâu". Một framework cho phép code game với tới mọi thứ chỉ là một game lớn. Giá trị đến từ những ranh giới đứng vững khi cơ chế thứ mười xuất hiện và không ai còn nhớ cơ chế đầu tiên.
Đây là bài viết kỹ thuật về cách CMZ Puzzle Framework được cấu trúc trong Unity. Nó giả định bạn quen với assembly definition, ScriptableObject và các SDK mobile thông thường.
Ranh giới package
Dự án được chia thành các assembly với phụ thuộc một chiều nghiêm ngặt:
- Core — tiện ích dùng chung, event bus, hệ thống lưu, localization, timer. Không phụ thuộc gì.
- Puzzle.Contract — các interface một cơ chế phải hiện thực. Phụ thuộc Core.
- Puzzle.Mechanics.* — một assembly cho mỗi cơ chế (BoardSort, ConveyorSort, ArrowLogic, CrowdJam, BlockBlast …). Chỉ phụ thuộc Contract và Core. Chúng không biết lớp meta tồn tại.
- Meta — progression, phần thưởng, streak, sự kiện, giải đấu, bộ sưu tập. Phụ thuộc Core và Contract; không bao giờ phụ thuộc một cơ chế cụ thể.
- Monetization — wrapper mediation quảng cáo, wrapper IAP, cấu hình vị trí. Phụ thuộc Core.
- Tracking — client analytics, taxonomy sự kiện, batching. Phụ thuộc Core.
- Game — assembly mỏng theo từng game: chủ đề, art, dữ liệu level, cấu hình. Phụ thuộc tất cả.
Quy tắc quan trọng nhất: cơ chế không bao giờ tham chiếu trực tiếp Meta, Monetization hay Tracking. Chúng phát sự kiện qua Contract; framework đăng ký nhận. Đây là điều cho phép một cơ chế mới ra mắt mà không chạm vào (hoặc làm hỏng) các hệ thống xung quanh.
Hợp đồng cơ chế
Hợp đồng được cố ý giữ nhỏ. Một cơ chế cung cấp:
LoadLevel(LevelData)vàUnload()- Một bề mặt input mà framework định tuyến thao tác chạm vào
- Sự kiện:
LevelStarted,MoveMade(MoveInfo),LevelWon(WinInfo),LevelFailed(FailInfo),HintRequested - Một
BoosterPortnhận hiệu ứng booster mà cơ chế hỗ trợ (hoàn tác, xáo, thêm ô…) và khai báo cái nào không hỗ trợ
Mọi thứ lớp meta và tracking cần — số lần thử, thời gian, nước đi, dùng booster, lý do thua — chảy qua các sự kiện đó. Nếu một cơ chế muốn booster chưa tồn tại, nó khai báo loại booster mới trong Contract, và hệ thống meta cùng shop xử lý một cách tổng quát.
Giữ hợp đồng hẹp khó hơn tưởng. Mỗi cơ chế đều cám dỗ bạn thêm "chỉ một" phương thức. Chúng tôi cưỡng lại bằng cách hỏi lớp meta có bao giờ cần gọi nó không; nếu câu trả lời là "chỉ cơ chế này quan tâm", nó ở lại trong assembly cơ chế.
Meta theo cấu hình
Hệ thống meta được xây như dịch vụ runtime cấu hình bằng ScriptableObject và remote config, không phải scene hay prefab mà game sao chép rồi sửa. Một game bật hệ thống win streak bằng cách thêm asset cấu hình mô tả ngưỡng, phần thưởng và quy tắc reset. Dịch vụ đăng ký LevelWon / LevelFailed từ hợp đồng và làm phần còn lại.
Điều tương tự áp dụng cho sự kiện giới hạn thời gian, giải đấu, reward track và bộ sưu tập. Vì cấu hình là dữ liệu, phần lớn cũng được lộ ra qua remote config, nên đội live-ops điều chỉnh tham số sự kiện — hoặc tắt nó — mà không cần phát hành app.
UI cho các hệ thống này nằm trong Meta dưới dạng prefab theo chủ đề với các slot mà assembly Game của từng title điền art vào. Điều đó cho mỗi game diện mạo riêng trong khi logic dùng chung.
Tracking miễn phí
Assembly Tracking đăng ký các sự kiện hợp đồng và phát một taxonomy cố định: level bắt đầu/thắng/thua với chỉ số lần thử, thời lượng, nước đi và dùng booster; giao dịch kinh tế với source và sink; sự kiện quảng cáo và IAP với định danh vị trí và sản phẩm; ranh giới phiên. Game chỉ thêm sự kiện cho tính năng thực sự riêng của title.
Đây là quyết định duy nhất làm hệ thống analytics của chúng tôi khả thi. Vì mọi game phát cùng sự kiện với cùng ý nghĩa, dashboard được xây một lần, và game mới được bao phủ đầy đủ từ bản build đầu tiên.
Sự kiện được gom trên thiết bị với bộ đệm offline và đẩy theo timer và lúc kết thúc phiên. Tầng batching được viết để sống sót khi bị kill giữa lúc đẩy, vốn là trường hợp bình thường trên mobile.
Cô lập SDK
SDK quảng cáo, IAP, attribution và analytics thay đổi thường xuyên và hỏng vào những lúc bất tiện. Mỗi cái được bọc sau một interface trong assembly riêng với hiện thực null dùng trong editor và test. Mạng mediation cấu hình bằng dữ liệu, và vị trí quảng cáo là hằng số có tên dùng chung với taxonomy Tracking, nên doanh thu của một vị trí và ảnh hưởng của nó lên phiên luôn nối được với nhau.
Lợi ích thực tế: nâng cấp SDK chạm vào một assembly, biên dịch hoặc lỗi độc lập, và có thể kiểm chứng trên thiết bị mà không cần build lại cơ chế.
Ngân sách hiệu năng mobile
Framework áp đặt vài ngân sách mà mọi game thừa hưởng:
- Khởi động đến tương tác đầu tiên dưới mục tiêu cố định trên thiết bị Android tầm trung tham chiếu, đạt được bằng hoãn khởi tạo SDK và load scene level đầu theo kiểu additive.
- Thời gian khung hình có dư địa, kiểm tra trong CI trên thiết bị tham chiếu với profiler, theo từng cơ chế.
- Ngân sách dung lượng build với Addressables cho nội dung chương sau chương đầu, và preset nén texture theo nền tảng.
- Kỷ luật cấp phát trong vòng lặp gameplay: object pooling, không cấp phát mỗi khung hình, collection định kích thước trước.
Ngân sách nhàm chán cho đến ngày một cơ chế mới nhân đôi thời gian khung hình trên thiết bị không ai trong đội sở hữu. Có chúng trong CI biến điều đó thành build lỗi thay vì đánh giá một sao.
Điều chúng tôi sẽ làm khác
Hai điều. Thứ nhất, chúng tôi lẽ ra nên đưa hiện thực SDK null vào từ ngày đầu; bổ sung sau tốn hơn viết ngay từ đầu. Thứ hai, chúng tôi đầu tư thiếu vào công cụ editor cho dữ liệu level từ sớm, và designer trả giá bằng lặp chậm hơn. Công cụ level là code framework, không phải code từng game.
Tóm lại
Tường trước, pattern sau. Hợp đồng cơ chế tối giản, phụ thuộc assembly một chiều, meta theo dữ liệu, tracking trên sự kiện hợp đồng và SDK sau interface là những gì cho phép mười bốn game puzzle ra mắt trên một codebase trong chưa đầy một năm — và cho phép game thứ mười lăm bắt đầu ở mức 60–70% hoàn thành.
Nếu bạn đang xây hoặc đánh giá một framework Unity cho danh mục game, kỹ sư của chúng tôi sẵn lòng trao đổi. Liên hệ.





