A Unity-based hexagonal color-sorting puzzle game built with clean architecture, service-oriented design, and the MVVM (Model–View–ViewModel) pattern. The project uses VContainer (DI container) as its Composition Root for dependency injection, state management, and lifecycle control.
- Overview
- Project Structure
- Architecture
- Core Systems
- Game Mechanics
- Configuration
- Third-Party Libraries
Hexa Sort is a puzzle game where players sort colored hexagonal cells by dragging stacks onto a hexagonal grid. The game features:
- Hexagonal Grid System: Cells are arranged in a hexagonal grid pattern
- Color-Based Sorting: Cells have different colors and must be sorted according to specific rules
- Stack Management: Cells are organized in stacks that can be dragged and placed on the grid
- Level Progression: Multiple levels with increasing difficulty
- Boosters: Special power-ups to help players (Hammer, Shuffle)
- Save System: Persistent game progress
Assets/_Project/Scripts/
│ ├── Runtime/
│ │ ├── Bootstrap/ # Application initialization and DI setup
│ │ │ ├── DI/ # Dependency injection configuration
│ │ │ └── Units/ # Loading units for bootstrap process
│ │ │
│ │ ├── Gameplay/ # Core game logic
│ │ │ ├── Core/ # Core models, interfaces, and shared types
│ │ │ │ ├── Interfaces/ # ICell, IStack, ISlot, IDraggable
│ │ │ │ └── Models/ # ColorType, HexCoordinates, HexMetrics, LevelData
│ │ │ │
│ │ │ ├── Domain/ # Business logic layer
│ │ │ │ ├── Boosters/ # Booster system (Hammer, Shuffle)
│ │ │ │ ├── Grid/ # Grid domain logic and services
│ │ │ │ ├── Level/ # Level management
│ │ │ │ └── Stack/ # Stack domain logic and services
│ │ │ │
│ │ │ ├── Infrastructure/ # Infrastructure layer
│ │ │ │ ├── DI/ # Dependency injection installers
│ │ │ │ ├── Factories/ # Object factories (HexGridFactory, HexStackFactory)
│ │ │ │ ├── Input/ # Input handling services
│ │ │ │ ├── State/ # Gameplay state management
│ │ │ │ └── UI/ # UI interfaces (IView, IViewModel)
│ │ │ │
│ │ │ ├── Presentation/ # Presentation layer (Unity-specific)
│ │ │ │ ├── Cell/ # HexCell, HexCellAnimator, HexCellMaterial
│ │ │ │ ├── Grid/ # Grid controllers and slots
│ │ │ │ └── Stack/ # Stack presentation components
│ │ │ │
│ │ │ ├── UI/ # UI layer (MVVM pattern)
│ │ │ │ ├── Boosters/ # Booster UI views and view models
│ │ │ │ ├── Game/ # Main game UI
│ │ │ │ ├── LevelComplete/ # Level completion screen
│ │ │ │ ├── LevelFailed/ # Level failure screen
│ │ │ │ ├── LevelProgression/ # Level progression UI
│ │ │ │ └── Settings/ # Settings UI
│ │ │ │
│ │ │ └── Config/ # ScriptableObject configurations
│ │ │
│ │ └── Utilities/ # Shared utilities
│ │ ├── Loading/ # Loading service
│ │ ├── Logger/ # Custom logging system
│ │ └── Persistence/ # Save/Load services
│ │
│ └── Editor/ # Editor-only scripts and tools
│
├── Art/ # Visual assets (sprites, materials, etc.)
├── Bundles/ # Asset bundles
└── Scenes/ # Unity scenes
├── 0.Bootstrap.unity # Bootstrap scene
└── 1.Gameplay.unity # Main gameplay scene
The project follows Clean Architecture principles with clear separation of concerns:
- Core Layer: Pure C# models, interfaces, and enums (no Unity dependencies)
- Domain Layer: Business logic and game rules (no Unity dependencies)
- Infrastructure Layer: External concerns (DI, input, state management)
- Presentation Layer: Unity-specific components (MonoBehaviours, visual representation)
- Gameplay Presentation: Game world objects (Cell, Grid, Stack) - 3D/2D game entities
- UI Presentation: Screen-space user interface (menus, HUD, popups) - MVVM pattern
The project uses VContainer for dependency injection:
- BootstrapScope: Registers core services (LoadingService, SaveService, LoadService)
- GameplayScope: Registers gameplay-specific services, factories, and managers
- Installers: Modular installers for different systems (InputInstaller, ConfigInstaller, UIInstaller, BoosterInstaller)
The project follows a service-based architecture where functionality is organized into discrete, reusable services:
- Services: Self-contained components that handle specific responsibilities (e.g.,
SaveService,LoadService,InputService,StackMergeService,StackSortingService) - Managers: Coordinate multiple services and manage domain-specific logic (e.g.,
LevelManager,BoosterManager,GameplayStateManager) - Separation of Concerns: Each service has a single, well-defined responsibility
- Dependency Injection: Services are injected where needed, promoting loose coupling and testability
- Examples:
PersistenceService,LoadingService,RaycastService,PositionCalculationService,GridCleanupService
The project implements the Composition Root pattern, where all object creation and dependency wiring happens in centralized locations:
- BootstrapScope: The root composition point for application-level services
- GameplayScope: The composition point for gameplay-specific dependencies
- All dependencies are configured at startup through VContainer's
LifetimeScope - This ensures a single point of control for dependency management and makes the system easier to test and maintain
The UI follows the Model-View-ViewModel pattern:
- View: Unity UI components (MonoBehaviours) -
*View.cs - ViewModel: Business logic and state for views -
*ViewModel.cs - Model: Data models and domain logic
Example:
GameView+GameViewModelLevelCompletedView+LevelCompletedViewModelBoosterView+BoosterViewModel
Location: Runtime/Bootstrap/
- BootstrapScope: Initial DI container setup
- BootstrapFlow: Entry point that loads configuration and transitions to gameplay scene
- ApplicationConfigurationLoadUnit: Handles initial app configuration loading
Flow:
BootstrapScene → BootstrapScope → BootstrapFlow → Load Config → GameplayScene
Location: Runtime/Gameplay/Domain/Level/
- LevelManager: Manages level progression, completion, and failure
- LevelData: Contains level configuration (grid size, colors, stack heights, cells to clear)
- LevelProgressionConfig: ScriptableObject defining level progression rules
Features:
- Reactive properties for level state (
CurrentLevel,CellsCleared,Progress) - Event streams for level events (
OnLevelStarted,OnLevelCompleted,OnLevelFailed) - Automatic progress calculation
Location: Runtime/Gameplay/Domain/Grid/ and Runtime/Gameplay/Presentation/Grid/
- HexGridMapper: Maps between grid coordinates, offset coordinates, and world positions
- GridController: Manages grid state, slot placement, and neighbor checking
- HexSlot: Individual slot in the hexagonal grid
- HexCoordinates: Hexagonal coordinate system (axial coordinates)
- HexMetrics: Constants for hexagonal grid calculations
Features:
- Hexagonal grid layout with offset coordinates
- Automatic centering of grid
- Neighbor detection (6 neighbors per hex)
- Stack placement and validation
Location: Runtime/Gameplay/Domain/Stack/ and Runtime/Gameplay/Presentation/Stack/
- HexStack: Container for hexagonal cells
- StackMergeService: Handles merging stacks together
- StackSortingService: Implements color-based sorting logic
- StackStateAnalyzer: Analyzes stack state (Empty, Pure, Mixed)
- HexStackBoard: Manages the board of draggable stacks
Stack States:
- Empty: No cells
- Pure: All cells have the same color
- Mixed: Cells have different colors
Sorting Rules:
- Pure → Pure: Merge stacks of the same color
- Mixed → Pure: Transfer matching cells from mixed to pure stack
- Cascading transfers: Multiple cells can transfer in sequence
Location: Runtime/Gameplay/Infrastructure/Input/
- InputService: Main input handling service
- DragService: Handles drag operations
- DropService: Handles drop operations
- RaycastService: Raycast-based input detection
- PositionCalculationService: Calculates positions for dragged objects
- BoosterInputService: Handles booster-specific input
Features:
- Unity Input System integration
- Drag and drop for stacks
- Touch and mouse support
- Position calculation for hexagonal grid
Location: Runtime/Gameplay/Domain/Boosters/
- BoosterManager: Manages all boosters and their usage
- IBooster: Interface for booster implementations
- HammerBooster: Removes a single cell
- ShuffleBooster: Shuffles stacks on the board
- BoosterUnlockConfig: Defines when boosters unlock
Features:
- Booster registration and management
- Usage tracking per level
- Unlock system based on level progression
- Active booster state management
Location: Runtime/Gameplay/Infrastructure/State/
- GameplayStateManager: Manages gameplay state machine
- GameplayState: Enum defining game states (Playing, LevelCompleted, LevelFailed, etc.)
States:
Playing: Normal gameplayLevelCompleted: Level completion screenLevelFailed: Level failure screen- Additional states as needed
Location: Runtime/Utilities/Persistence/
- SaveService: Handles saving game data to disk
- LoadService: Handles loading game data from disk
- GameSaveData: Serializable data model for save files
Features:
- JSON-based save files
- Async save/load operations using UniTask
- File I/O on background threads
- Automatic directory creation
- Error handling and validation
Location: Runtime/Gameplay/Presentation/Cell/
- HexCellAnimator: Handles cell animations
- HexAnimationConfig: ScriptableObject for animation settings
- Uses DOTween for tweening
Animation Types:
- Merge animations (cells moving between stacks)
- Flip animations during movement
- Staggered animations for multiple cells
- Stack Dragging: Players drag stacks from the stack board onto the hexagonal grid
- Color Sorting: When stacks are placed, automatic sorting occurs based on color rules:
- Pure stacks of the same color merge together
- Mixed stacks transfer matching cells to pure stacks
- Cascading transfers continue until no more matches
- Level Objectives: Clear a certain number of cells by creating matches
- Level Failure: Level fails when all grid slots are filled without completing the objective
- Uses axial coordinates (X, Z) with Y = -X - Z
- Offset coordinates for grid layout (row/column style)
- 6 neighbors per hex cell (East, Northeast, Northwest, West, Southwest, Southeast)
- Automatic centering based on grid dimensions
- 8 Colors: Red, Blue, Green, Yellow, Purple, Orange, Pink, Cyan
- Each cell has a
ColorTypeproperty - Colors are mapped to materials via
ColorMaterialConfig
- Levels are defined in
LevelProgressionConfigScriptableObject - Each level specifies:
- Grid dimensions (width × height)
- Color range (min/max colors)
- Stack height range
- Available colors
- Cells to clear (objective)
- Progress is saved automatically after level completion
The project uses ScriptableObjects for configuration:
LevelProgressionConfig- Level definitionsColorMaterialConfig- Color to material mappingHexAnimationConfig- Animation settingsBoosterUnlockConfig- Booster unlock levelsBoosterIconConfig- Booster UI icons
These can be found in Assets/_Project/Bundles/Configs/ and should be created as assets in the Unity project.
- VContainer (
jp.hadashikick.vcontainerv1.17.0)- Lightweight DI framework for Unity
- Used for service registration and dependency injection
- Supports lifetime scopes (Singleton, Scoped, Transient)
- UniTask (
com.cysharp.unitask)- Zero-allocation async/await for Unity
- Used for async operations (save/load, animations)
- Provides
UniTaskandUniTask<T>types
- UniRx (
com.neuecc.unirx)- Reactive Extensions for Unity
- Used for event streams and reactive properties
- Provides
ReactiveProperty<T>,Subject<T>,IObservable<T>
- DOTween (included in
Assets/Plugins/DOTween/)- Tweening library for smooth animations
- Used for cell animations, UI transitions
- Configured via
HexAnimationConfigScriptableObject