Unity

Kiến trúc Unity cho một framework puzzle đa game

Cách chúng tôi cấu trúc một codebase Unity duy nhất để chạy hơn một tá cơ chế puzzle: ranh giới package, hợp đồng cơ chế, lớp meta theo dữ liệu và tracking đi kèm miễn phí.

Tác giả CMZ Soft6 phút đọc
Bàn puzzle 3D của Block Flow

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)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 BoosterPort nhậ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ệ.

Xem chúng tôi áp dụng điều này ra sao

Game của chúng tôi được xây trên chính những ý tưởng chúng tôi viết.

Khám phá game

Đang làm một game puzzle?

Chúng tôi hợp tác với publisher ở prototype và sản xuất trọn gói.

Trao đổi với chúng tôi

Game liên quan

Ảnh chụp gameplay Zen Garden: Flower Sort

Zen Garden: Flower Sort

Sort Puzzle

Gom những bông hoa giống nhau vào đúng bình và dọn bàn — một biến tấu êm đềm, đẹp mắt của sort puzzle.

Đang phát hànhAndroid
Xem game
Ảnh chụp gameplay Hole Crowd: Bus Jam

Hole Crowd: Bus Jam

Crowd Jam

Mở đường thoát để mỗi người que rơi vào hố đúng màu và lên đúng xe buýt trước khi hết ô chờ.

Đang phát hànhAndroid
Xem game

Bài viết liên quan

Tất cả bài viết
Icon các game của CMZ Soft trên Google Play
Tin studio·

Giới thiệu CMZ Soft: studio puzzle định hướng sản phẩm từ Hà Nội

Chúng tôi là ai, đã phát hành gì — mười sáu game trên Google Play trong chưa đầy một năm — và dự định làm việc thế nào với publisher, nhà đầu tư và những người sẽ gia nhập.

3 phút đọc

Ghép icon các game puzzle mobile
Phân tích thị trường·

Bức tranh game puzzle mobile 2026: một studio nhỏ còn có thể thắng ở đâu

Puzzle vẫn là một trong những thể loại mobile lớn và bền nhất, và cũng cạnh tranh nhất. Cơ hội cho một studio tập trung nằm ở đâu: khoảng trống sub-genre, tốc độ sản xuất, kinh tế hybrid và UA kỷ luật.

4 phút đọc

Danh mục icon game prototype và game live
Analytics·

Khung go / kill cho prototype game mobile

Quyết định prototype nào xứng đáng được đầu tư thêm là quyết định đắt nhất của một studio. Khung quyết định chúng tôi dùng: ngưỡng thống nhất trước, một tập nhỏ chỉ số, và ba kết quả — go, iterate, kill.

4 phút đọc