Built and Released a Polished Match-3 Game Using AI

Match 3 with AI

Overview

First off, this project was an experimental initiative by WINR Games to explore how AI can support the development of a casual mobile game from the ground up—handled entirely by a single developer. Big thanks to the WINR Games team for their support and for allowing me to share this journey.

 

Second, for anyone unfamiliar, WINR Games is a studio that rewards players with tokens based on skill—the better you play, the more you earn. These tokens can be exchanged for crypto or cash, functioning like a loyalty rewards system. I won't dive deep into that here—feel free to check out the WINR Games website for more details.

 

Third, a bit about my background: I have experience building mobile games from scratch, and I started out as a technical artist. My education and work in Interior Architecture, 3D visualization, and Game Development gave me a solid foundation in both visual design and technical implementation—skills essential for game dev. I wanted to document this project not just to share the end result, but to give a transparent look at the real development process—the wins, the messes, and how AI meaningfully impacted my workflow as a solo dev.

 

Lastly, while many projects show how generative AI can help non-coders create web or game applications, I wanted to highlight a different angle—how AI can help fill in your skill gaps and elevate your solo work by acting as a smart, collaborative assistant.

 

Now, let’s dive into the process.

Note: This game was developed for WINR Games (where I work as a Senior Engineer). This post reflects my personal development experience and is hosted on my own site.

Objectives

We set a few clear goals at the start of this project:

 

  • Use agentic AI in Unity to speed up development and eliminate repetitive tasks.
  • Build a standalone game that we can easily integrate with our platform's engine (for server communication and rewards).
  • Follow our Unity coding guidelines and project structure that we have already established.
  • Save time and cost by avoiding the need for any third-party help with art touch-ups or reskinning.
  • Create an original game that puts a twist on familiar casual match-3 mechanics.
  • Push the boundaries of AI usage in development (for better or worse) within a short timeframe.
  • Ensure the game is fun and polished—comparable to popular match-3 titles on the market (this was the hardest part!).

Week I

Concept, Planning, Experimentation, and Prototyping

At the start of Week 1, I had nothing—no assets, no design, not even a name or clear game idea. The first couple of days were all about setting up my development environment and brainstorming. I researched the best IDE to work with Unity’s C# scripting, since I’m a daily VS Code user and rely heavily on GitHub Copilot. Around this time, “vibe coding” was a hot topic, and two AI coding tools—Windsurf and Cursor—were being discussed a lot (shout-out to our CEO, who encouraged us to try them). I experimented with both; Windsurf had a nice UI and was easy to use, but its model flexibility and results didn’t quite work for me. I ultimately chose Cursor and even grabbed the pro subscription to unlock its maximum AI performance. (It’s all personal preference, so feel free to explore both tools and see which suits you best.)

After picking my IDE, I set up some project rules in Cursor. In fact, I incorporated our own internal Unity coding guidelines as well as some community-provided ones (thanks to a colleague for pointing me to the Cursor community’s Unity rules). Also, check the Cursor rules for more details on how to set up.

Multiple rules

Note: If you're like me and want Unity to open files in Cursor when you double-click a C# script (similar to how it opens VS Code), there's a handy package by user boxqkrtm that makes this possible. Check out the Unity IDE Cursor integration package on GitHub for a convenient setup.

With my AI-assisted workflow ready, I prompted the agent to generate a few simple game prototypes to spark ideas. I tried prompts like “create a clone of <Classic Game> in Unity” to see what it would produce. I generated a basic Connect-4 clone and a Pentris clone (Pentris is like Tetris but with 5-block pieces). Eventually, I decided to focus on a match-3 game as our project, which the team agreed was a solid direction.

Connect 4 (Unity AI)
Connect 4 (Unity AI)
Pentris (Unity AI)
Pentris (Unity AI)

Using Cursor with those initial prompts taught me a lot about how the AI agent handles game layout and core structure, and what its limitations are. I noticed that if I repeated the same prompt or task, the AI sometimes “hallucinated” – it would give inconsistent results or code that didn’t quite match previous outputs. To counter this, I leveraged Unity’s powerful Editor scripting to enforce consistency. My approach was to have the AI generate the core game scripts (basic game mechanics, UI, and game flow), and then have it create an Editor script to assemble the scene: setting up prefabs, sprites, scriptable objects, and any required data. This Editor script essentially automated the scene setup in Unity, ensuring that repeating the setup produced the same result every time. (If you’re familiar with Unity, you know how powerful Editor scripting can be for exactly this reason.)

Match 3 - Scene setup script

As the AI-generated project took shape, I learned which parts worked well and which didn’t. I soon had a functioning match-3 prototype with the objective of cloning the feel of popular games like Candy Crush or Royal Match. The initial output from the AI was a very barebones game: just four core game scripts and one editor script that created the whole match-3 setup. The editor-driven game setup created everything needed — a grid prefab, some ScriptableObject assets for level configuration, and placeholder sprites for tiles. The basic game flow was there too: it kept track of score and moves, and included a simple UI that let you restart the game when you ran out of moves.

I structured the code generation this way because it made it easier to manage and update. If we needed to modify something, we could open a specific script or ask the AI to adjust that part without confusion. I’m a fan of classic OOP and SOLID principles (I know those might be considered basic or even a bit outdated these days, but bear with me!). That clean structure makes it easier for me to read, fix, and extend code as needed. I actually baked those principles into the AI’s instructions (along with our WINR coding rules) because I realized early on that AI-generated code can be tough to extend or add features to if it isn’t well organized.

Level Editor

By the end of Week 1, I had the game’s skeleton and a prototype level editor in place. We could define a level’s layout, save it to a ScriptableObject, and it would automatically get added to our level config asset. This made it super convenient to generate multiple levels quickly. In short, we had a working match-3 prototype ready to build upon.

Week II

Features, Coding, and Game Mechanics

At the start of Week 2, the core gameplay was working, so I shifted focus to content and features. I spent some time playing popular match-3 games (mainly Candy Crush and Royal Match) to analyze their special mechanics. If you’ve played these games, you know they have special power-up tiles when you match patterns beyond the basic three-in-a-row. For example, matching 4 tiles in a row often creates a special tile that clears a whole row or column, and matching in an L or T shape creates a bomb that clears a chunk of the board. They also have various obstacle tiles that can’t be swapped and must be cleared by other means (like breaking a crate or ice block by matching adjacent tiles).

Obstacles Editor

I started by asking the AI (via Cursor) to implement obstacles in both the level editor and the game’s runtime mechanics. I introduced a variety of obstacle types and defined their behaviours:

  • Ice – a tile covered in ice. It can be moved (swapped) like a normal tile, but is considered “covered” until you break the ice by matching something on it or adjacent to it.
  • Box – an empty blocker on the grid (no tile spawns in that cell). It blocks movement and requires multiple hits (e.g. match adjacent to it 1–3 times) to clear.
  • Chain – a chained tile. The tile is locked in place and cannot be moved until the chain is broken by a match.
  • Double Chain – a stronger chain that needs two breaking actions to fully clear (after one break, it becomes a single chain, then break again to clear).
  • Grass – a spreading obstacle. It occupies a tile and, if not cleared, will gradually spread to adjacent tiles, “locking” them as well (similar to how spreading slime or chocolate works in some match-3 games).

With obstacles in place, I next asked the AI to add the special power-up tiles for larger matches. We implemented the following match combo outcomes:

  • Match 4 in a row (horizontal) – spawns a special tile that, when activated, clears an entire row.
  • Match 4 in a column (vertical) – spawns a special tile that clears an entire column.
  • Match in a T or L shape – spawns a bomb that clears a 3x3 block of tiles.
  • Match 5 in a row – spawns a “cross” special that clears both a full row and a full column (like a plus-shaped blast).
  • Match 6 in a row – spawns a colour bomb that clears all tiles of the same colour on the board.

Implementing these was a fun challenge, and I was grateful for Cursor’s MAX mode, which allows a larger context for the AI. As the project grew in complexity and the scripts got longer, the larger context window helped the AI keep track of the whole project when generating new code or making edits.

Cursor Max Mode

With the prototype foundation laid, development started to accelerate. My AI assistant helped me build a background grid system editor (essentially a tool to customize the board’s appearance). This allowed us to easily swap out the tile sprite graphics and to support different level layouts dynamically. By this point, I had also implemented the basic matching logic (detecting horizontal or vertical matches of 3 or more) along with the gravity (tiles falling) and refill mechanics to fill empty spaces.

One tricky part was handling diagonal movements for when tiles get blocked by obstacles. In match-3 games, when you have irregular layouts or blockers, sometimes tiles need to fall diagonally to fill gaps. I attempted to have the AI handle this logic, but after several tries and messy results, I decided to code the diagonal fall logic myself. (Even my manual solution isn’t perfect—it took a while and really tested me, because the AI’s approach wasn’t flexible enough to cover all scenarios—but it’s good enough for now.) Fortunately, the rest of the matching and gravity logic worked well in tandem with this tweak.

I also began building a more efficient match resolver engine to optimize how matches are found and cleared. I used a HashSet approach to track matches and prevent duplicate scans of the same combo. This made the matching process more reliable and efficient, especially as the board got larger or when multiple cascades happened.

By the end of Week 2, I was moving quickly, and the game’s feature set was growing. One thing I noticed, however, is that refactoring the AI-generated code was getting harder as the project scaled. The prototype code structure was somewhat limited, and at the time, I hadn’t discovered certain Cursor extensions for handling larger codebases.

Honestly, I also didn’t expect that we’d end up using this experimental prototype as the base for a production release! This meant I had to be careful and sometimes do manual clean-up or restructuring of code as we went. But the core game was taking shape nicely by the week's end.

Week III

UI, Art, Concept, and Game Name

By Week 3, the game was fully playable, but we still hadn’t decided on a theme or name. Thankfully, our CEO already had some ideas (with a bit of help from ChatGPT for brainstorming names). We decided to go with a space theme, since WINR’s brand has a space vibe, and we landed on the name Planet Pop for the game. With a theme in mind, I dived into asset creation. I used a combination of tools, including ChatGPT (for ideas and even some basic code or text generation), an AI art tool called Scenario, and good old Photoshop. Between those, I generated a ton of space-themed art assets: tiles, backgrounds, effects, UI elements, etc., making sure I had all the necessary resolutions and file formats needed for Unity.

This week, I also gave some love to the user experience (UX). I added satisfying animations and feedback effects to the game: tiles now moved smoothly and had fun squishy animations, and matches triggered particle effects. I even used AI to help generate some of the animation curves and easing functions, which saved time tweaking values. Additionally, I built a prototype of a level generator using AI-generated logic and began integrating actual level data beyond the single test level we started with.

Throughout Week 3, I was constantly using Cursor with different AI models to assist me. I primarily switched between Claude Sonnet 3.7 and Gemini-2.5-Pro, both running in Cursor’s high-capacity mode. I used these models to refactor code (e.g. reorganizing code or renaming variables to be more intuitive), and even to help with generating complex logic for things like new blocker types or special tile behaviours.

I noticed an interesting difference between the AI models: In my experience, Claude Sonnet 3.7 was better for large-scale code edits, especially when adding a new feature that touched multiple scripts. It could scan through the entire project and handle multi-step instructions, likely by doing multiple passes when it hit token limits. On the other hand, Gemini-2.5-Pro offered a huge context window (up to 1 million tokens), which sounded great, but when I pushed it to the max, it tended to lose track of some details. I suspect it wasn’t able to perfectly retain everything once it reached its context limit. Because of this, I developed a pattern: I’d use Sonnet for big feature additions or sweeping changes across many files, and use Gemini for smaller refactors or tweaks in one or two scripts. (This might have been a limitation of the tools at the time, but it’s what worked for me.)

Week IV

Polishing, Visual Effect, and Meta Systems

Week 4 was a heavy one. The game was content-complete by now, so this week was all about polishing and fixing things. I went through several rounds of code refactoring and bug fixing. I also spent a lot of time finding just the right visual effects to make the game feel juicy and satisfying. Luckily, we have some existing effect packs in our Unity asset library, so I didn’t have to create every sparkle or explosion from scratch. But even integrating and testing these pre-made effects in our game was time-consuming. It was a lot of trial and error to see which particle effects or animations fit well, and unfortunately, I couldn’t really use AI to speed up this part — it was manual labour and tinkering.

Another big task this week was integrating the WINR platform framework into the game. This framework connects our game to WINR’s backend for things like the token reward system, player profiles, etc. Thankfully, our platform team provides a script that makes integration straightforward. I ran that script and only needed to do minimal setup, like configuring localization (for different languages) and a basic tutorial for new players. This process was quick, and it was nice to see the game hooked into the larger WINR ecosystem.

By and large, Week 4 was dominated by traditional development work and using our established pipeline scripts. There wasn’t much AI involvement here, aside from occasionally asking for small code improvements. It was mostly me rolling up my sleeves and polishing the game the old-fashioned way.

Week V

Level Design and the Level Generator

In Week 5, I turned my focus to level design and improving the level generator with my AI assistant. Designing fun levels is arguably the toughest part of a match-3 game, and doing it with AI is even trickier. The fundamental challenge is that an AI can crunch numbers and generate patterns, but it doesn’t truly understand what makes a level fun or well-paced for a human player. The best it can do is imitate patterns from data or follow rules we give it.

To make it easier to collaborate with the AI on level generation, I changed how we represent level data. Initially, each level was a Unity ScriptableObject (a custom asset). I decided to convert all our level definitions into JSON format. This made it much easier to feed levels to the AI and to manually edit them as well. JSON is just a text representation, so I could show the AI examples of level configurations and have it generate new ones in a similar structure.

I took a hybrid approach to level design. I manually designed the first batch of levels myself. These early levels serve to teach the player the game mechanics step by step. I made sure the first few levels introduced the basics: simple matches, then using a special tile, then encountering an obstacle, and so on. Once the basics were covered and the difficulty started ramping up, my plan was to let the AI help generate additional levels to keep the content going. My rationale was that handcrafted levels are superior for teaching and the early game experience, but after a point, we could rely on AI-generated levels to fill out the long tail of content. (Human-designed levels are usually better overall—AI would need a ton of data and iterations to approach a human designer’s intuition—but with some tuning, AI levels could be “good enough” to keep players engaged in the mid to late game.)

Designing a good difficulty curve requires balancing a lot of factors. Here are some key parameters I considered for the level generator logic:

  • Number of tile colours: More tile colours on the board means fewer automatic matches and a higher difficulty. Early levels might use 4 colours, while later ones might use 6 or more for complexity.

  • Grid shape/size: A smaller or oddly shaped play area is generally harder because there are fewer possible matches at any given time.

  • Number of obstacles: Introducing more blockers (like those ice tiles, chains, etc.) will ramp up the difficulty, as the player has to clear those in addition to making matches.

  • Targets and moves: The relationship between the level’s goal (e.g. score to reach or specific tiles to collect) and the number of moves given is crucial. Fewer moves or higher targets make a level harder; more moves or lower targets make it easier.

And that’s just a sample—there are many other factors (special tiles, spawn rates, etc.). It’s a complex equation and often requires a lot of tweaking. Another important aspect is pacing. If every level just gets progressively harder and never lets up, players will likely burn out. You want to mix in some easier levels or “break” levels as breathers so that players don’t feel the game is impossible. My difficulty design ended up looking a bit like a sine wave—waves of ups and downs in difficulty, but with an overall upward trend as you go further. (There’s a great GDC talk by one of King’s designers about Candy Crush’s level design philosophy, which inspired some of my approach here.)

I spent a good chunk of the week tweaking these parameters and playtesting levels. I’d generate a batch of levels with the AI, play through them, throw out the blatantly bad ones (some were too easy, others were literally unbeatable), adjust the rules or constraints, and repeat. It was an iterative grind, but each cycle got the levels closer to that sweet spot of challenging-but-fair. A colleague of mine helped playtest as well and gave valuable feedback. Together, we honed in on what felt “right” for our game.

Level Generator

Eventually, I reached a point where the level generator was producing decent levels consistently. I even implemented the ability for the game to auto-generate levels at runtime (on the fly) once the player reaches the end of the handcrafted and pre-generated level list. This means the game can offer infinite levels— after you beat all the designed levels, it will keep creating new ones so you can keep playing endlessly. I leaned on Gemini-2.5-Pro quite a bit for improving the level generator logic step by step, as it was great for those iterative code adjustments.

By the end of Week 5, we had a solid set of levels, a system to keep making more, and the game’s progression curve felt much better after numerous adjustments and playthroughs.

Week VI

Testing and Final Touches

The last week was all about testing and final polish. One really cool thing I did was create an autoplay script – essentially, an AI or automated player that plays the game by itself. This helped me observe how a typical player might play through levels without me having to manually play over and over. I intentionally tuned the autoplay bot to be good but not perfect, to mimic a casual player’s behaviour (making decent matches, but not always the optimal move). Watching the game play itself revealed some edge-case issues and gave me insights into how forgiving or frustrating certain levels might be. It’s a poor-man’s playtesting, but it was incredibly useful for balancing.

Autoplay
Autoplay Level Information
Autoplay Level Information

Throughout this week, I was also doing a ton of code cleanup. I refactored parts of the codebase that had gotten messy, removed unused scripts and assets, and optimized a few slow spots (like the match scanning and level generation) to make sure the game ran smoothly on mobile devices. This cleanup was partly guided by the AI (asking it to find inefficiencies or suggest simpler implementations) and partly just me combing through the code.

By the end of Week 6, the game felt polished and stable. That marked the end of the initial development journey!

Final Thoughts

How AI Helped Me
  • Code assistance: Refactoring, fixing bugs, writing logic, and even quick prototyping snippets.
  • Brainstorming: Coming up with game systems, mechanics ideas, and even names or themes.
  • Assets & Ideas: Generating or inspiring art assets and design concepts (with tools like Scenario, etc.).
  • Balancing formulas: Helping create and fine-tune game balance formulas and level generation rules.
  • Debugging: Catching edge-case issues that I hadn’t noticed, by analyzing code or via the autoplay tester.
  • Copywriting: Rewriting explanations, tutorials, and help text with a guided tone (to make it friendly and clear).

Challenges Faced
  • Time pressure: Building this in just 6 weeks meant we had to cut features and avoid any “feature creep.”
  • Mental fatigue: Solo development is intense, and juggling everything (even with AI help) was tiring at times.
  • AI code quirks: Debugging and refactoring AI-generated code threw some curveballs, since the AI’s approach wasn’t always how a human would structure things.
  • AI level design limits: Using AI as a level designer was tough — it’s hard for AI to judge “fun,” so a lot of human iteration was still needed.

What I Learned
  • AI is an incredible partner – Especially in the solo dev loop, having an AI assistant felt like coding with a knowledgeable pair programmer always on call.
  • Consistency beats perfection – Sometimes shipped is better than perfect. It’s important to keep momentum and not get stuck aiming for unattainable perfection.
  • Unity still delivers – Unity proved once again that it’s a great engine for 2D/3D hybrid casual games, allowing rapid development and iteration.
  • Prototype early – Having a playable build early on (even if rough) helped catch issues and validate fun factor, preventing wasted effort.
  • Human oversight is key – AI can assist in every aspect, but human involvement is needed to guide the quality, inject creativity, and decide what feels right.
  • AI doesn't understand "fun" – At the end of the day, an AI can’t truly grasp what makes a game enjoyable. Tuning the “fun factor” through testing still required human judgment.

Things to improve
  • Level Unit Testing: Set up unit tests for levels to quickly confirm that AI-generated content makes sense and is playable, instead of manually checking each level in Game mode. This will save me a lot of time and hassle.
  • Diagonal Movement: Make diagonal movements smoother and more intuitive for a better gameplay experience.
  • Level Generator: Keep improving the level generator by using more player data and manual edits, so the AI-created levels feel even closer to handcrafted ones.

The Final Result

We published Planet Pop on the Google Play Store. It’s a fully playable, smooth, ad-supported match-3 title with original art, catchy animations, and endless levels to enjoy. (If you want to check it out, you can find Planet Pop on the Google Play Store now!)

Android: Download
iOS: Download


What’s Next?

This release is just the beginning. I’m already working on a new game, continuing my experimentation with AI-driven level design and balancing the fun factor. My goal is to perfect a system that can reliably generate infinite, engaging levels for any casual game.

If you found this devlog useful or inspiring, please feel free to share it, try out the game, or drop me a message with your thoughts!

Follow my journey here:

Thanks for reading, and remember—yes, you can ship that game idea. Even solo. Even faster.

Note: AI tech is moving fast, and this devlog is just my experience over a couple of months (from April–May 2025). Things might change in the future, and who knows—maybe one day AI will understand the concept of “fun.” For now, I’ll keep my hand on the wheel when it comes to game design and player experience!