Sponsored By

Into the Vortex: Procedurally Generating a Hearthstone Clone

My latest #procjam entry was an exercise in generating complex artifacts out of a single Energy value, along a few procgen paintings to go with them. This covers tricks and design rationale I used to make such a project (kinda) fit a jam timeline.

Yanko Oliveira, Blogger

December 6, 2019

17 Min Read
Game Developer logo in a gray background | Game Developer

You can play Vortex here. This post was originally published on my personal blog.

I've been developing prototypes for a project about meaningful procedural generation and early science called Bestiarium for a few years now, and #procjam (a yearly chill game jam for all things procedural) is my excuse to build individual mechanics and experiments that will feed back into it. You can read a bit more about its current state and history in the uncut version of this post.

Previous prototypes like Herbarium and De Daemonici Corporis Fabrica were both exploring the same mechanic: passing an item through different tools/processes to find out what it is or what it does. Both of them seemed to have gathered some attention, with mentions in a couple of articles and even YouTube let’s play videos, which really surprised me.

This time, however, I decided to visit something I was running away from for a while: Energy.

NOT ENOUGH MANA

In Bestiarium, Energy is the thing that knits all of the items in the game together. It’s the metric which would allow anything to be combined and produce results that are worth pursuing. It’s the “common currency” for the procedural generation, so it’s the backbone of the game’s balancing. That means it’s as horrifying as it’s important and if I can’t properly get it to work, all of the core loops fall apart – in that case, Bestiarium might as well be just what it already is: a bunch of disjoint experimental prototypes.

Energy has 2 main facets: how it scales, and how it’s used to generate artifacts. I decided to focus on the generation aspect first: how to, given a single numeric value, generate something complex? Fortunately, #procjam 2018 was around the corner, so I had the perfect excuse to work on that.

To focus on the relevant parts and fit the jam timeline, instead of trying to invent some crazy mechanic, I’d just do the simple thing: clone some existing game! Too bad my wife was playing Hearthstone again at the time, which inevitably led to “OH, I KNOW, I’LL MAKE A PROCEDURAL VERSION OF HEARTHSTONE! WHAT COULD GO WRONG?”

I know that sounds stupid, but hear me out.

“Legend has it” sounds more lyrical, but it’s a fact that Hearthstone was originally prototyped in pen and paper for a few months by a couple of designers, and it was a matter of getting the rest of the team together and saying “there, now just make that” while pointing to the Flash implementation that the duo had made.

The game is, inherently, very, very simple, and good core mechanics make for good games. It’s the bells, whistles and polish that make it great.

Trying to emulate THAT was the stupid part.

However, there’s no Hearthstone without the juice. And I’m not gonna lie, when I did Chimera for 1 Class Jam, it was fun just poking around with pretty things and polish for a change. So I started with that.

SURVIVING PROGRAMMER ART

My 2d art skills are pretty limited to photobashing and hacking together textures for FX tests. It did seem like a good opportunity to shove Cronus Hog into a game, so why not as a hero character? That called for an opponent hero, which came after a visit to The National Gallery.

When it came to the cards, I wanted to do a pretty much 1 to 1 copy of Hearthstone’s layout, for clarity in UX. Because of my 2d deficiency, I decided to try modeling all of it in 3d, and using the standard Unity PBR shader to give it a metal look. I used a quick and dirty version of DOTA 2’s baking techniques to create the diffuse maps and make the shapes a bit more pronounced, while using gradient maps to color things.

I could use the same assets for the card and the minions on the board, but it came with a problem: the camera was perspective and moving the card around made the text parallax in weird ways, so I had to flatten the icons – if you look closely, you might see some deformity, especially in the mana counter sphere.

I could have opted for simply baking all of it down and making things 2d, but that would require repositioning everything on the board and tweaking the animations (which by the way, are all done with DOTween). Doable, but time intensive, and this was still a game jam – sometimes, you just /shrug and carry on.

With that out of the way, it was time to focus on the card portraits. If you don’t have fancy card art, might as well just do everything with a pen and some post its. Obviously, there’s no budget to make hundreds of hand painted art pieces, so I guess the only way out is generating it. Should be easy enough, right?

I decided to go for a beast deck because… well, basically because Google Poly had just came out back then, and searching for “animals” returned a lot of results. I managed to snag about 15 models (from bisons to shrimps), which meant I was just some combinatorial magic away from hundreds of possible variations. I made some quick and dirty 3d models of biomes for the animals to sit in: grasslands, desert and snow, which basically were a few tree models and a ground texture swap from each other. But that was not even 100 permutations yet, so another cheap out was changing the time of day: this would provide different moods. Finally, getting the advantages of having everything in 3d to work in our favor, I threw in different camera angles, with a different light setup for each.

That’s quite a bit of variation, but let’s face it: it doesn’t fit any art style at all, and everything is super low-poly. Not to mention it looks like crap. That’s when the oil painting style comes to the rescue: the hero portraits had a really cool vibe, so I decided to do the same for the card art. Also, any form of filtering would help the raw 3d art being used by… fudging it.

Enter the Kuwahara Filter. Not that I knew that that’s exactly what I needed before I searched for “unity shader oil painting”, obviously.

Unfortunately, the filter made everything too smooth, and just looked like your off-the-mill Photoshop slap. One final thing did the trick: UV distortion. By distorting the UV coordinate based on a texture, we can add a rougher brush stroke feel on top of the image; that gets it closer to what a painting would look like (and hides even more of my crappy 3d art).

This pretty much covered all my card art needs: nowhere near actual art, but it created the right amount of visual noise for them to read as “oh, sure, this is a trading card!“, with enough variation for a few hundreds. Now, it was time to get to business.

 logo in a gray background |

THE META-HANDCRAFTING OF PROCEDURAL GENERATION BALANCE

The generation is very simple, really. It started by selecting the features I could quickly implement, and trying to double down on those – or as Appropriate Tributes would say, COMBINATORICS FOR THE COMBINATORICS GOD! RANDOMIZATIONS FOR THE RANDOMIZATION THRONE!

The route from that to meaningful generation, however, comes with iteration, and the best way to balance a game like this is with analytics and a bulk of players – the designers of Slay the Spire have a good GDC talk on that topic – but this was a game jam, and I’d have neither. I could simply attempt sourcing the data from one of the many Hearthstone dumps, and creating a system that statistically paired the mana values with the strength and health values. However, this whole project was an exercise in coming up with the meta design, so this was out of the question. I did manage to complete a first pass on that, had most of the mechanics done, even a very basic AI implemented aaand…

#procjam 2018 was over! I had spent so much time with polishing and juice and generating paintings of… *checks notes*… gorillas taking a winter stroll at dawn, that I didn’t finish a game. I did however have the strong feeling that if I only had 1 extra week, I could actually wrap it up.

Fast forward to 2019, another #procjam came up, so I decided to use it as that extra week. The sole focus would be working on the balancing and card generation. That’s why I started on the first weekend by visiting Sketchfab (which turned into a great place to search for Creative Commons assets) and giving the game a major face lift with shiny PBR-ready assets, some proper lighting, adding the card generation UI and using the always handy blend-add technique to make a chunky vortex for the intro (if you don’t know what I’m talking about, make sure to watch this Diablo 3 VFX talk). Besides the nice UI elements and logo made by my friend Thiago Rocha, the microtrailer below looks pretty much exactly as the game did on the first weekend. Generation and balancing were still completely busted tho – WHO WOULD HAVE GUESSED I’D PROCRASTINATE ONCE MORE?

 logo in a gray background |

NO, REALLY, THE META-HANDCRAFTING OF PROCEDURAL GENERATION BALANCE

This came with a lot of iteration (living with someone who plays A LOT of Hearthstone helped immensely), but this is what I’ve settled with:

There’s 2 types of cards, Spells and Minions, and there’s 2 types of deck, Warlock and Pilgrim. The Pilgrim would favor a greater amount of minions and healing spells, while the Warlock would have more spells than minions, most of those dealing damage. Every card has a mana cost and, in the case of minions, they have a total power, given by summing their strength, health and possible effects. The possible effects are Protector (the minion must be attacked first and doesn’t lose health at first hit, 1 point), Charge (the minion can attack as soon as it’s summoned, 1 point) and Multi-Attack (the minion can attack twice in the same turn, 2 points). So, eg, a card that costs 5 mana, has 5 attack, 3 health and is a Protector has a power of 5+3+1= 9, and a power ratio of 9/5 = 1.8.

Every minion card starts with a power rating of 2: the same value for mana, attack and health. The deck balancing configuration has a setting that picks if the card will have greater health, or attack. The stat that is not picked as the main is then reduced based on a curve which varies with mana cost. This allows tweaking to remove overpowered cards, but still have decent cards for the first few turns. In hindsight, the curve the game shipped with was too fond of 10/10 and 9/9 cards, but the dip in the mid range felt pretty natural in playtests.

I implemented a very limited set of Spells, but the system is there to be expanded upon. Every spell Effect implements an interface that takes one or more minions as targets. They’re also ScriptableObjects, so both data and custom code are self-contained, and you could even make very scripted behaviour upon casting, like making an opponent’s minion attack a friendly unit.

There’s a weighted chance for picking types of effect, which is mana cost agnostic (at the wrap up rush, I did have to hardcode some rules like not generating cards that gave Protector above 4 mana). Balancing is then done by what a spell can target: the player Hero, random minions, specific minions, groups of minions, all characters etc. So for example, a 10 mana card will likely target big groups, while very low value cards will usually target random minions, possibly even your own, which is something that I’m pretty sure in a real game, a lot of players would hate – I got cursed every single time it backfired but hey! You get what you pay for!

 

THE CHYMICAL WEDDING OF BAD AI AND BUGS

Game jams are about scope management and convincing people to invest time in a game that is inevitably not as a good as a finished product. This means multiplayer games are a silly idea, as you have 3 options:

  1. Convincing someone to try it against themselves

  2. Convincing someone to convince someone to try it with them, locally

  3. Do a networked game, which has the previous problem, plus you know, actually implementing network code

  4. Implementing an AI, that could go from doing random stuff just to show what the game would be like, to something you actually feel like you’re play against

Ergo, making multiplayer games on a gamejam is a very, very silly idea and you’re a very, very silly person if you do it.

I went for option 4.

Just like on X, a game of YZ, I started by hardcoding the simplest heuristic I could think of, and went from there. Unlike that game, where I originally did (1), saw poor Jupiter Hadley playing it, updated it with basic AI the next weekend and promised myself I’d never do that to anyone ever again, I knew that even on the first release I wanted to have AI in, and I’d like it to be something you felt like you were really playing against.

When doing proper science, you need to take your time, isolate parameters and poke and prod at them individually, so you can verify what makes a difference and how. In the case of Vortex, when the game started coming together, it was hard to know if it sucked because it was completely unbalanced or because the AI was very, very silly. That’s why iteration was king: I’d poke around, ask my in-house Hearthstone expert to play it, see all the bugs, pain points, weird behaviours, tweak those, rinse, repeat.

The AI obviously got beaten again and again by someone who would, you know, think before making a play, but with balancing improvements, it was showing the game off pretty well. However, the matches were very short, and I noticed that as soon the player got a bit of board dominance, it was GG for the AI.

There was only one way: actually make the AI think a few moves ahead, which would require completely restructuring everything and focusing just on that until the end of the jam.

Or cheating. So I cheated. I gave the AI a “hail Mary” card that could be cast after a certainpoint, if the player had too much board dominance, which would… wipe the player’s board. It sounds terrible, but it actually added a lot of spice to the game, and allowed the player to explore more of their deck and play around with their high mana cards.

Having most of my experience as a gameplay programmer had me seeing my fair share of bugs that were so cool that should be turned into features, and they never did because, you know, who in their right mind would do that.

Me. I would do that. It’s my game jam and no one can stop me! And I’ll teach the AI those rules as well, HAH! So yeah, if you ever have a card that reduces opponent strengths in absurd amounts just… be careful.

All in all, these “broken” interactions are the very thing that increased the longevity and fun in a match – it was awesome watching my wife changing plans and preparing for the minion wipeout after I told her what the rules were.

 logo in a gray background |

WRAPPING UP THE DRAFT

There’s obviously a bunch of things missing, but it’s by far the most complete and polished jam game I ever released. It did come with a ton of “outsourcing”: it was a clone, so the design was done and proven, most of the art is CC, I had help from a great UI artist, and most importantly, the QA and playtest passes my wife did were the real reason why the game turned out as good as it did.

Ironically, almost no one played it, and it got 0 buzz. Maybe because it was a clone, maybe because #procjam got to a point where it’s established enough for people to know, but not to be click material on game journalism sites. Maybe it was just not as good as I thought it turned out to be, even. The funniest thing was deciding to copy the Hearthstone UX 1-1 and considering that people would instantly get it, just to be reminded a few minutes after posting that not everyone has played Hearthstone before.

It was good fun though; it helped me practice for yet another tiny part of a long term project and to have some ideas for what Bestiarium is supposed to look and feel like. So what’s in store for 2020? I’m pretty sure it’ll be a clicker game, to explore how to deal with exponential values and economy balancing. Oh yeah, and maybe getting some early prototype out for Bestiarium itself – there’s only so much I can productively procrastinate if I actually want to get it released someday. If you're interested in the project, keep an eye out for my blog posts or hit me up on twitter @yankooliveira.

Read more about:

Featured Blogs
Daily news, dev blogs, and stories from Game Developer straight to your inbox

You May Also Like