Skin SystemI implemented EverMerge's Skin System. Much of EverMerge is code driven and this made most of its systems rigid and difficult to change. I wanted to move away from that and so I designed the skin system to be as data driven as possible.
During one of my previous tasks, I encountered the game's Content Override System. It was a system that kept track of Dictionaries that had the original piece name as the key, and the replacement piece name as the value. When a piece is about to be spawned in the game world, the piece creation system first checks these Dictionaries to see if it should return a different piece instead. This system was used for a different event, but I saw how it could be utilized for the Skin System. The Content Override System defined these Dictionaries in code, and so I had to create a system that made it easier to change. I created a config file whose entries contained a piece name and an accompanying skin name. I created a Skin Data Manager to handle the ingestion of this config file and an accompanying Skin Logic Manager that handled things like unlocking skins. By doing this, I was able to leverage the benefits provided by the Content Override System while still keeping the system data driven. |
Glitter BombI implemented the glitter bomb for EverMerge’s Villains Event. The glitter bomb was a tappable piece that, upon detonation, damaged specific pieces within a predefined range.
I wanted the glitter bomb to be as modular as possible. In EverMerge, you can add components to a Piece, and I wanted one component to be responsible for one functionality of the bomb. In the end, I had components like the CellHighlighterComponent and DamagerComponent. This separation of concerns made it easy to track bugs and made it so each script had one reason to change. I revisited this system when our designer wanted to change the pattern the bomb targeted. My initial implementation made it easy to change as it was just a list of positions defined in code. I wanted to refactor this because I didn’t want designers or artists to have to touch the code if there was another change in the pattern. I decided to move it out of the code and into a config that was then ingested by the game and used the bombs. Now changing the pattern is as easy as adding or removing positions in the config. |
Minion SystemMinions are the new type of Pieces for EverMerge’s Villains event. Minions acted like obstacles, pieces that produce rewards when “mined” by the player. Unlike obstacles, Minions cannot be mined and must be damaged by bombs. Their visuals also change when they receive damage. I was responsible for implementing this new piece behavior.
The biggest hurdle was the changing of the Minion visuals when damaged. One solution I considered was just having one piece that had different animations for its stages. Unfortunately, it would have had lots of friction with our other systems like our Piece Creation and Reward System. I would have had to define complicated, specific logic for each system, cluttering our code base. Instead, I went with the approach that conformed to our existing systems. Fortunately, we already had a similar mechanic with obstacles. Upon fully mining an obstacle, it turns into a chest. I was able to reuse this behavior for Minions. That would have been the end of the task if Minions did not have LifeComponents. A LifeComponent tracks the lives left for a specific Piece. When Minions change visuals, they are no longer the same Piece so they lose the reference to their previous LifeComponent. The fix was fairly straightforward and involved storing the reference before removing the original Minion and then reassigning the component to the resulting Minion. |
Content Generation Tools
EverMerge relies on a set of Unity tools to generate content. The initial tool to generate events was rigid and relied on values defined in code. When our designers wanted a new event, I had to manually edit those predefined values. One of the changes was increasing the length of event chains. I had to scour through multiple scripts to locate where the chain lengths were defined and edit them. I didn’t want anyone else having to do that so I decided to expose those values in the tools UI. Now, whoever was generating the event could directly define the lengths of whatever piece chain they wanted without having to change the code. This degree of customizability wasn’t necessary, so I made sure to create presets for the most common values. This simple change made the tool more resistant to future design requirements.