A Sliding Picture-Assembly Puzzle — Unity Template
Version 1.2 | Unity 6+ | URP
This asset is designed as a template and starting point for your own game development. It provides the core systems, architecture, and tools needed to build a sliding picture-assembly puzzle game. You are expected to customize, extend, and modify this template to create your unique game. This is not a complete, ready-to-publish game — it's a foundation for developers to build upon.
Picture Block Puzzle 2D is a sliding picture-assembly puzzle where players drag colour-coded image pieces across a grid to reconstruct the original pictures before the timer runs out. Each block has a “zero” anchor piece that defines where the assembled image should sit; the remaining pieces must be placed at their solved offsets relative to that anchor. The game ships with a time-limit countdown, four boosters, axis-constrained pieces with a visible arrow overlay, a visual level editor, an automatic level generator, and a 500+ starter pack of generated JSON levels.
Drag image pieces on a 2D grid; drop them on empty cells to reassemble the finished picture. Multi-cell shapes snap to their true footprint and cannot overlap other pieces. The dragged piece darkens while actively held for clear feedback.
Per-piece movement locks (any / horizontal-only / vertical-only) add a layer of puzzle strategy on harder levels. Constrained pieces display a double-headed arrow overlay so the player knows the allowed axis at a glance.
A full Unity Editor window that mirrors the runtime visuals: pieces are rendered with the same sliced-sprite mapping the game uses, multi-cell shapes are drawn across every cell they occupy, and movement-axis arrows show on constrained pieces. Tool modes for shape placement, drag-to-move, walls, and erase — with a green / red hover preview that validates collisions before you click. A merge helper folds adjacent single-piece blocks into one multi-piece block.
Batch-generate fresh levels with configurable grid size, block count, scramble moves, time limit, and booster allowances. Uses a curated tiling-pattern library so blocks always span a clean 2×2 / 2×3 / 3×2 footprint. Difficulty front-loads so hard levels arrive sooner; wall density, axis-constraint chance, and scramble count all scale with progression. Append-only — never overwrites hand-tuned levels.
Time Freeze (pause the countdown for 10 seconds), Hint (ghost-preview a displaced piece's solved position), Shuffle (randomly reposition every block without overlap), and Grid Expander (extend the playable grid by 1 cell on every side for the rest of the level).
Each booster unlocks at a specific level (1 / 2 / 3 / 4 by default) so new players learn one mechanic at a time. Locked buttons show "lvl N" instead of the charge count. Press U in the editor / a development build to unlock & refill everything for testing.
Every level carries its own time budget. A visible FrozenImage indicator appears while the Time Freeze booster is active so the player sees at a glance that the clock has paused.
500+ levels ship as plain JSON under Resources/Levels/PictureBlockPuzzle2D/. Regenerate or extend at any time with the Auto Level Generator; delete every file in one click from the generator's danger-zone button.
Edit > Project Settings > Graphics)Assets/Picture Block Puzzle 2D/Scenes/GameNew.unityTools > Picture Block Puzzle 2D > Level Editor or … > Auto Level GeneratorOnce in Play mode, drag any movable block on the grid to an empty cell. When every non-zero piece of a block sits at its solved offset from that block's zero anchor, the picture completes automatically and the star particles burst. Clear all pictures before the countdown reaches 0 to win the level. On win the next level loads automatically; on time-out the lose panel appears.
Each level displays a grid of cells, a set of multi-cell blocks (each painted with a color and carrying a piece of a larger picture), and a visible countdown. The player drags blocks to empty cells; physics colliders prevent overlap. A block is considered assembled when every non-zero piece of its color sits at zeroHead + (pieceHead − zeroPieceHead) — i.e. the picture is reassembled in its authored orientation. Swapping two same-colored pieces does not count; the exact offsets must match.
CanApplyShapeToGrid ensures every target cell is empty before the move is acceptedmoveAxis of Horizontal or Vertical, restricting drag to that single axis. A double-headed arrow overlay is rendered on top of the piece showing which axis is allowedisZeroPos: true; the solved image is computed from where the zero piece currently sitstimeLimit in seconds; reaching 0 triggers the lose panel. The Time Freeze booster pauses the countdown for 10 seconds and shows an on-screen FrozenImage indicator while activeobstacles in the JSON) cannot be entered by any block. Wall density scales with difficulty on generated levelsLevelManager.AdvanceLevel() runs before the scene reloads; on lose, the same level reloadsSeven predefined block colours, defined in Ecolor.cs and mapped to RGB in MyUtils.GetColor / JsonLevelData.cs → BlockColors:
| Colour Key | Colour | Approx. RGB |
|---|---|---|
yellow |
Yellow | (1.00, 0.84, 0.00) |
red |
Red | (1.00, 0.20, 0.20) |
magenta |
Magenta | (1.00, 0.20, 0.67) |
purple |
Purple | (0.54, 0.17, 0.89) |
blue |
Blue | (0.20, 0.40, 1.00) |
mint |
Mint | (0.40, 0.92, 0.81) |
lime |
Lime | (0.71, 0.91, 0.29) |
SoundManager.Instance.PlayLevelClear() fires, the level index advances, and the next level loads automatically.Blocks use 2D rigidbodies with snap-to-grid placement for drag feedback. Completed pictures fade their ghost sprites into the final image and emit a star particle burst. The Hint booster spawns a translucent ghost of a displaced piece at its solved position and pulses it for ~2.2 seconds while also briefly scaling the real piece so the player can see which piece should move where. The Shuffle booster reseats blocks with an explicit no-overlap validation pass.
Runtime scripts use the PictureBlockPuzzle2D.Scripts namespace. Editor scripts use the PictureBlockPuzzle2D.Editor and PictureBlockPuzzle2D.EditorTools namespaces. Shared helpers (SoundManager, DeveloperSettingsController, LoseWinPanelManager) live under HypercasualGameEngine.
| Script | Description |
|---|---|
GridManager |
Main gameplay controller. Builds the grid from LevelData.gridSize, spawns blocks from blockDatas, runs the level countdown coroutine, toggles the FrozenImage indicator during a Time Freeze, validates shape placements with CanApplyShapeToGrid, stamps occupancy via SetBlockOccupancy, rebuilds occupancy from live positions before each merge check, and exposes ShuffleBlocks() used by the booster. |
InputManager |
Touch / mouse drag handling. Raycasts to pick a block, tracks the drag, and snaps the block to the nearest valid grid cell on release. |
Block |
Block entity. Stores color, piece data, head grid position, and the 2D rigidbody / colliders. Exposes GetAllShape(head) to convert a head cell + piece offsets into an occupancy list. |
BlockIconLoader |
Resolves per-piece picture sprites from Resources/BlockIcons/ by name (e.g. ice-cream-2_0). |
GoalManger |
Tracks remaining color goals for the level and drives the goal UI. |
LevelData |
Runtime level descriptor. Contains gridSize, time, a list of BlockData, obstacles, and per-level booster counts. Created at runtime with HideFlags.HideAndDontSave to survive scene reloads. |
JsonLevelData |
JSON-serialisable mirror of LevelData plus the BlockColors palette helper and the ToRuntimeLevelData / FromRuntimeLevelData conversions used by the editor tools and runtime loader. |
LevelManager |
Static loader. Reads Resources/Levels/PictureBlockPuzzle2D/*.json into a sorted list at startup, tracks the current level index under PlayerPrefs key PictureBlockPuzzle2D_CurrentLevel, and exposes GetCurrentLevel, AdvanceLevel, GoToLevel, ForceReload, plus editor-only disk-write helpers used by the Level Editor. |
BoosterManager |
Manages all four boosters: Time Freeze (calls GridManager.FreezeCountdown(10f) and toggles the FrozenImage), Hint (ghost-previews a displaced piece's solved position), Shuffle (delegates to GridManager.ShuffleBlocks()), and Grid Expander (delegates to GridManager.ExpandGrid()). Binds to the scene buttons Booster-Button-1/2/3/4 by string match, gates each booster by level index (undoUnlockLevel=0, hintUnlockLevel=1, shuffleUnlockLevel=2, gridExpandUnlockLevel=3), and shows first-use tutorial popups keyed in PlayerPrefs. Exposes DebugUnlockAndRefillAll() used by the U dev hotkey (self-healing: re-hooks button refs if Init hasn't run yet). |
PictureBlockPuzzle2DGameManager |
Scene orchestrator. Holds dev hotkeys (arrow keys for level nav, U to unlock & refill boosters), refreshes the HUD level label from LevelManager.CurrentLevelIndex, and wires BoosterManager.Init to the current level on startup. |
GameUI |
Writes the formatted countdown string into the HUD's countdown TextMeshPro via UpdateCountDownText(float). |
LoseWinPanelManager |
Owns the Win / Lose panels. LoadNextLevel() calls LevelManager.AdvanceLevel() before SceneManager.LoadScene so progression actually sticks. Namespaced under HypercasualGameEngine for cross-game reuse. |
AudioButtonController |
HUD mute toggle. Persists the muted state and swaps the button sprite accordingly. |
| Script | Description |
|---|---|
Ecolor |
Colour enum (None, Yellow, Red, Magenta, Purple, Blue, Mint, Lime) used by blocks and the occupancy map. Also defines MoveAxis (Any / Horizontal / Vertical) used by axis-constrained pieces. |
ShapeData |
Maps a shape-type integer in the JSON to a concrete Block prefab, used at spawn time by MyUtils.GetBlock. |
CameraSwitcher |
Swaps camera presets when orientation / aspect changes. |
SnapToClosestObjectOfList |
Edit-time helper that snaps a Transform to the nearest object in a given list — used when hand-placing HUD elements. |
SpriteDummy |
Placeholder sprite component for editor-time visualisation. |
MyUtils |
Small helpers: time formatting, grid origin calculation, and GetBlock(shapeType, shapeData) prefab lookup. |
| Script | Description |
|---|---|
SoundManager |
Singleton audio system with a single AudioSource, master-volume slider, and one PlayX() method per gameplay event (e.g. PlayBlockPlace, PlayUndo, PlayHint, PlayShuffle, PlayLevelClear, PlayFreezeTime). |
DeveloperSettingsController |
Dev-panel controls: next / previous level, trigger win / lose, unlock all boosters, refill all boosters, reset first-use booster popups, ad-panel toggles. |
DeveloperModeButton |
Shows / hides the DeveloperSettingsPanel. Auto-finds the panel child if no Inspector reference is assigned. |
| Script | Description |
|---|---|
LevelEditorWindow |
Unity Editor window (Tools > Picture Block Puzzle 2D > Level Editor) for visually designing levels. Mirrors the runtime block visuals: every cell of every multi-cell piece is drawn, the icon sprite is contain-fit-scaled to the block's bounds and clipped to each piece's cell (matching Block.cs), and movement-axis arrows render on constrained pieces. Tools: Select / Move (click to select a block, drag a piece to move its startPos with collision validation), Place Pattern (drop a 1×2 / 2×1 / L / 1×1 single-piece block with a green / red hover preview), Wall, and Erase. Block list shows a live mini preview (color + sprite slice in solved layout), inline per-piece editor (shapeType / startPos / headPosition / moveAxis / zero toggle), per-block color + sprite picker, and a “↪ merge” button that folds a block's pieces into the currently selected block, recomputing blockSize and each piece's headPosition from the combined bounding box. Top-of-panel fields edit cols, rows, timeLimit, and all four booster counts. |
LevelGeneratorWindow |
Unity Editor window (Tools > Picture Block Puzzle 2D > Auto Level Generator) for batch-generating levels. Settings control grid size, block count, scramble moves, time limit, and booster counts. Uses a curated tiling-pattern library (2×2, 2×3, 3×2) so every block fits cleanly; scales wall density, axis-constraint chance, and scramble depth with difficulty; front-loads difficulty with a pow(t, 0.55) curve so hard levels arrive sooner in the batch. Append-only — never overwrites existing levels. A “Delete ALL” button in the danger zone wipes every level for a clean regenerate. |
PictureBlockPuzzle2DWelcomePopup |
Welcome popup shown once per Unity session on project open. Hosts two CTAs: “Leave a Review on the Asset Store” and “Get HyperCasual Game Engine”. Permanently dismissable via the “Do not show this popup again” checkbox (stored in EditorPrefs). The popup has no menu item — the auto-show on session start is its only entry point. |
DragSnapWithoutPlaymodeEditor |
Edit-mode helper that lets authors drag-snap Block prefabs to grid cells in the scene view without entering Play mode. |
ImportAudioIcon, InputSystemCheck, URPStartupCheck |
Editor-time diagnostics that warn the developer if required settings are missing (icons, Both input handling, URP active). |
In the Unity menu bar, go to Tools > Picture Block Puzzle 2D > Level Editor. This opens a dedicated Editor window — no need to enter Play mode.
Resources/Levels/PictureBlockPuzzle2D/); Reload from Disk; and Refresh Sprites (re-scans Resources/BlockIcons/ for new artwork).The grid renders pieces exactly the way the running game does:
Block.cs's SpriteMask + iconSpriteRenderer composition, so what you see in the editor is what you'll see in Play mode.Any moveAxis show the same horizontal / vertical arrow sprite the runtime renders.isZeroPos: true piece's head cell is labelled 0.| Tool | Behaviour |
|---|---|
| Select / Move | Click a piece to select its block (used by every other tool's color picker and by the merge helper). Drag a piece to move its startPos — the move is collision-validated against walls / other pieces / the grid edge, and the piece's headPosition is preserved so the picture-slice mapping stays correct. |
| Place Pattern | Pick a shape and a color, then click an empty cell to drop a single-piece block. A hover preview shows the cells that would be occupied, tinted green when the placement is valid and red when blocked. The five available shapes match the runtime's ShapeType enum: 1x2 (horizontal pair), 2x1 (vertical pair), L (top-right) — cells (0,0) (0,1) (1,0), L (bottom-left) — cells (0,1) (1,0) (1,1), and 1x1. Each placement creates a new block (auto-selected) so you can immediately set its sprite. |
| Wall | Click (or drag) to add a wall obstacle. Hover preview turns red over a cell that already has a wall or piece. Walls are the runtime's permanent obstacle cells — no block can ever overlap them. |
| Erase | Click (or drag) to remove whatever piece or wall sits at that cell. Empty blocks (no remaining pieces) are pruned automatically. |
Every Place Pattern click creates a single-piece block. To assemble several pieces into one logical multi-piece block (so they share one picture / sprite):
1x2 at (3,4) and again at (3,5).blockSize to that bounding box.headPosition to its slot inside the bounding box.startPos only — headPosition stays put, so the picture mapping survives the scramble.The merge button is greyed out when nothing is selected or when you'd be merging a block into itself.
Every block row in the Blocks list exposes:
(cols, rows) of the assembled picture; bigger sizes display the icon at a larger scale.MoveAxis (kept for old JSONs; per-piece axis is the source of truth at runtime).Resources/BlockIcons/, with a thumbnail preview and a drag-drop slot.startPos, headPosition, moveAxis, zero-piece toggle, and a per-piece delete. Promoting a piece to zero auto-clears the others so exactly one zero remains.All levels are stored as individual JSON files in Assets/Picture Block Puzzle 2D/Resources/Levels/PictureBlockPuzzle2D/ with the naming convention Level_1.json, Level_2.json, … The runtime loader uses Resources.LoadAll<TextAsset>("Levels/PictureBlockPuzzle2D") and sorts by the trailing number in each filename. Save All Levels wipes the existing files in that folder and writes a fresh set, numbered by their order in the level list — reorder the list before saving if you want a specific numbering.
The Automatic Level Generator is an Editor tool that batch-generates playable picture-assembly levels. It controls grid size, block count, scramble moves, time budget, booster allowances, axis-constraint chance, and wall density — all scaled along a front-loaded difficulty curve so hard levels arrive earlier in the batch. Generated levels always satisfy the shape-footprint / occupancy invariants used by the runtime; the in-game Shuffle, Hint, Undo, and Grid Expander boosters give players a way out of any stuck state (a forward-BFS solvability check is intentionally not run — it was rejecting harder scrambles and producing levels where pieces landed conveniently close to their solved positions).
In the Unity menu bar, go to Tools > Picture Block Puzzle 2D > Auto Level Generator. This opens a settings window where you can configure all parameters before generating.
| Setting | Description |
|---|---|
| Levels to Generate | How many new level files to create. New levels are appended after existing ones (never overwrites). |
| Grid Size (Min & Max) | Range for the grid width / height. Early levels lean toward the minimum, harder levels toward the maximum. |
| Block Count (Min & Max) | Range for the number of blocks (distinct pictures) per level. Default 2 → 6. |
| Scramble Moves (Min & Max) | Number of legal reverse-slide moves used to displace pieces from their solved positions. The effective total scales with piece count internally so each piece receives ~N moves on average. Default 8 → 30. |
| Time Limit (Min & Max) | Seconds of countdown budget per level (Max used on the easiest level, Min on the hardest). |
| Booster Counts (Min & Max) | Per-booster min / max uses to write into each generated level's JSON. |
| Random Seed | Set to 0 for an unseeded run (different every time), or any non-zero integer for reproducible output. |
t = pow(levelIndex / total, 0.55)) so the player reaches hard levels soonermoveAxis constraint (Horizontal or Vertical) when the chance roll succeeds — only on pieces whose scrambled → solved delta is already purely along that axis, to keep the constraint self-consistentResources/Levels/PictureBlockPuzzle2D/Level_N.jsonThe generator never overwrites existing level files. It always starts numbering from the next available index (e.g., if Level_30 exists, new levels start from Level_31). Use the “Delete ALL Levels” button if you want to start fresh.
The game includes four booster abilities that players can activate during gameplay. Each booster has a configurable number of uses per level (set in the level JSON data) and an optional first-use tutorial popup. Each booster unlocks at a specific level so new players learn one mechanic at a time.
| Booster | Unlock | Effect | Activation |
|---|---|---|---|
| Time Freeze | Level 1 | Pauses the level countdown for 10 seconds. Enables the on-screen FrozenImage indicator for the duration, then hides it when the freeze expires. Multiple presses stack the remaining freeze time. |
Tap the Time Freeze button (Booster-Button-1). Consumes one use immediately. |
| Hint | Level 2 | Picks a displaced non-zero piece at random, spawns a translucent ghost of it at the solved position, pulses the ghost for ~2.2 seconds, and briefly scales the real piece so the player sees which piece should move where. | Tap the Hint button (Booster-Button-2). Consumes one use immediately. |
| Shuffle | Level 3 | Calls GridManager.ShuffleBlocks() which reseats every block on a random valid head cell using CanApplyShapeToGrid to guarantee no two shapes overlap and every footprint stays inside the grid. If a block cannot be placed, the whole board is rolled back and the charge is not consumed. |
Tap the Shuffle button (Booster-Button-3). A charge is consumed only when the shuffle actually succeeds. |
| Grid Expander | Level 4 | Calls GridManager.ExpandGrid() which extends the playable grid by 1 cell on every side, rebuilds the tile map, shifts every block into the new coordinate system, and repositions the border walls. One expansion per level is typically plenty. |
Tap the Grid Expander button (Booster-Button-4). Consumed on start of expansion; no-op if an expansion is already running or the level has ended. |
Booster buttons live in the scene under GameHUD_Panel/BottomHolder. Each button has:
Bg) that shows / hides based on availabilityPowerUpCountText) showing remaining uses, or the unlock level ("lvl N") if still lockedBoosterManager and can be tuned in the Inspector per-projectBooster-Popup-1/2/3/4 GameObjects; the first use of each booster fades its popup in and out. Keys are stored in PlayerPrefs (BoosterPopupShown_Undo, BoosterPopupShown_Hint, BoosterPopupShown_Shuffle, BoosterPopupShown_GridExpand)Press the U key during gameplay to unlock all boosters and refill their usage counts (wrapped in #if UNITY_EDITOR || DEVELOPMENT_BUILD so it's stripped from release builds). The hotkey reads both the legacy Input.GetKeyDown and the new-Input-System Keyboard.current.uKey so it works regardless of which backend owns focus. It calls BoosterManager.DebugUnlockAndRefillAll(), a self-healing variant that re-hooks scene button references if the scene hasn't yet initialised.
Press Right Arrow / Left Arrow during gameplay to jump to the next / previous level (wraps at the ends). Handled by PictureBlockPuzzle2DGameManager.Update().
The Developer Settings Panel also ships with Next Level / Previous Level / Reload buttons.
To add a new block colour (the game already ships with seven — yellow, red, magenta, purple, blue, mint, lime):
Ecolor.cs and add a new entry to the EColor enum:
MyUtils.cs and add the RGB for the new entry to GetColor. Open JsonLevelData.cs and mirror it in the BlockColors dictionaries (colors, toEnum, toKey, AllKeys)LevelGeneratorWindow.cs and add the new key to the COLOR_KEYS array so the generator picks from itNew colours are automatically available in the Level Editor, Auto Level Generator, and at runtime.
The grid layout is controlled by GridManager.cs. Key Inspector properties:
cellSpace — Spacing between grid cells in world unitstilePrefab — The visual prefab placed at each grid cellshapeData — Lookup that maps shapeType integers in the JSON to concrete Block prefabsstarParticlePrefab — The burst VFX played when a picture completesborderRoot — Optional invisible Border with 4 collider walls; repositioned to the current grid size at runtime if assignedBlock rendering is driven by Block + per-piece sprites under Resources/BlockIcons/. To retheme:
Resources/BlockIcons/ (keep the same filenames to avoid retagging every level JSON)SpriteRenderer defaults if you want a new fallback tintJsonLevelData.cs → BlockColors to change the tint of every block of that colorAudio lives on a single SoundManager singleton. Replace any clip on the SoundManager GameObject in the scene to retheme a specific event. Add a new clip field + matching PlayX() method if you introduce a new gameplay event — the existing pattern is documented inside SoundManager.cs.
New boosters can be added by following the existing pattern in BoosterManager.cs:
HookUpExistingBoosters() by adding a fourth named child (Booster-Button-4) to the scene and matching it by stringOnMyBoosterClicked())JsonLevelData / LevelData and populate it in BoosterManager.Init()UpdateBoosterUI() to draw the new button's lock / unlock / count displayEach level is a JSON file with the following structure:
The blocks array defines multi-piece pictures. Each block has a colorKey (one of yellow / red / magenta / purple / blue / mint / lime), a blockSize, a spriteName (resolved from Resources/BlockIcons/), and a list of pieceDatas. Each piece has:
startPos — where the piece spawns on the grid (x, y in 0-indexed grid coords, (0,0) at top-left)headPosition — the piece's offset inside the assembled picture, with (0,0) reserved for the zero pieceshapeType — index into the shape library (0: 1×2 horizontal, 1: 1×2 vertical, 2: L top-right, 3: L bottom-left, 4: 1×1 single)isZeroPos — exactly one piece per block must be true — that piece is the solved-image anchormoveAxis — per-piece movement constraint: 0 = Any, 1 = Horizontal, 2 = Vertical. When non-zero the piece renders a double-headed arrow overlay and drags lock to that axisNote on field name: undoBoosterCount is the legacy serialised name kept for save-file compatibility; at runtime it drives the Time Freeze booster.
Note on moveAxis placement: the per-block moveAxis field is legacy — at runtime the per-piece moveAxis inside pieceDatas is authoritative. The generator only constrains one piece per block (on an axis where that piece's scrambled → solved delta is already purely along that axis) so levels stay self-consistent.
| Issue | Solution |
|---|---|
| No levels load / empty grid appears | Ensure JSON level files exist in Assets/Picture Block Puzzle 2D/Resources/Levels/PictureBlockPuzzle2D/ with the naming convention Level_1.json, Level_2.json, etc. Use the Auto Level Generator to create levels if the folder is empty. |
| Pink / magenta materials on objects | The project requires URP. Go to Edit > Project Settings > Graphics and ensure a URP Render Pipeline Asset is assigned. Check that the Settings/ folder contains valid URP assets. |
| Time Freeze booster icon doesn't appear | The FrozenImage GameObject must exist in the scene (child of WorldCanvas). It uses the sprite Textures/frozen-button.png. If you've deleted it, re-add the object or re-import the package. |
| Blocks pass through each other | Every Block prefab needs a Rigidbody2D and matching Collider2D(s). Also verify the Border walls under GridManager.borderRoot are enabled — they constrain the play area for the drag physics. |
| Booster buttons don't respond | Ensure the GameHUD_Panel/BottomHolder hierarchy contains children named Booster-Button-1, Booster-Button-2, and Booster-Button-3. Each needs a Button component. If you added a Canvas component for sorting order, you must also add a GraphicRaycaster. |
| First-use booster popups never show | The popups Booster-Popup-1/2/3 must exist in the scene with m_IsActive: 0. GameObject.Find skips inactive objects, so BoosterManager uses an inactive-aware scan — if you renamed the popups, restore the literal names or update the constants at the top of BoosterManager.cs. To replay the tutorial, click “Reset Booster Popups” on the Developer Settings panel. |
| Shuffle booster consumes a charge but nothing changes | On a tightly packed board the shuffle occasionally can't find a valid layout for every block and rolls back. In that case the charge is not consumed (the method returns false). If the count still ticks down, ensure no other script is decrementing shuffleBoosterCount behind BoosterManager's back. |
| Level Editor shows empty grid | Click “Reload from Disk” in the Level Editor window, or ensure the Resources/Levels/PictureBlockPuzzle2D/ folder exists and contains valid JSON files. |
Resources/Levels/PictureBlockPuzzle2D/ folder regularlyIf you get stuck or have any issues, feel free to reach out to us at ragendom@gmail.com. We are happy to help!