Building a Board Game in Unity

Mike Bischoff
4 min readMay 19, 2022

--

Image from Cuphead ©Studio MDHR

Basic Dice Mechanics

When I first started learning how to code C# in Unity I gave myself a simple task to prove I understood the basic underlying concepts I’d been absorbing: create a basic dice roll mechanic. As beginners tend to do, I thoroughly overthought the program. I created a Dice class and populated it with separate int variables for everything from a coin flip (d2) through every value of what some may derisively call “Dungeons & Dragons dice,” then similarly created methods for each to calculate their random values.

And when I attached the script to my player, the methods didn’t really work as I envisioned, I couldn’t figure out how to retrieve the result even if they had, and I certainly didn’t know how to implement it in a game-relevant way.

Fast forward [loud cough] years, and I can say my initial assumption was correct, though. The task is actually very simple:

In five simple lines you can abstract the Random.Range()* function out of your code and emulate any die roll value in a much more efficient and human-friendly way. Here’s how it breaks down:

The method is declared as public, because the intention is that it’s going to be called from any number of different systems that will need any denomination of die roll and will therefore live in some kind of manager class that communicates with other scripts.

Next is the int return type. This is one of the big pieces I was missing as that neophyte coder at the beginning of the story, and the reason I couldn’t extract the result of my calculations. The simple explanation is that with this return type declaration, this method will produce a piece of data (an int, in this case), that we can then use however we need.

For more on this, I’ve written about return-type methods before.

Remember all those redundant variables I thought I needed? The next part of the declaration renders them all irrelevant. After naming our method, inside the parentheses we tell it that whichever script is invoking it, they need to pass in an int parameter (dSides is just an arbitrary variable name, but in this house we give our variables plain-language names).

Think of it like a typical table-top RPG: each player has their own bag of dice that they’re responsible for rolling, the mechanics of the roll (physics and chance) are agnostic to which die they cast, just like our DieRoll() method. The script calling the method will be responsible for determining which “die” is “rolled.”

Next, we do our calculation, storing it in the rollResult variable, then return that variable as data and close the method.

Multi-Die Rolls

Going back to the tabletop RPG analogy, what about when the player’s weapon has a damage type that calls for multiple die rolls? Or rolling two movement dice, like in Monopoly? Instead of calling the DieRoll() method multiple times and adding the results together, we can simplify it even more using the concept of polymorphism.

That’s a $20 word for a simple idea: in this case, all we need is a copy of the original DieRoll() method with a new parameter:

This overload of the DieRoll() method will take the same dSides parameter, then adds a count called rolls to iterate how many times that die is rolled. The simple for loop adds the results of each roll together to get the total we need.

You can add as many overloads as you need to accommodate rolls that take in any number of rolls for any combination of n-sided dice your game requires.

Strip it Down

Six hundred twenty-eight words later, I have a confession to make: for the game I’m building out, we’ll only ever need to roll one six-sided die once at a time. If there’s any major difference between me now and me at the beginning of the story, it’s figuring out when to keep it simple:

With the first basic mechanic solved, next we’ll how to take the result of our roll and turn it into player movement.

*We need to add +1 to the end of the range because the int type of Random.Range() is max exclusive, meaning it excludes the highest value. This is convenient for cycling through indices of arrays and Lists to prevent out of range exception errors, as we’ll discuss later.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Mike Bischoff
Mike Bischoff

Written by Mike Bischoff

Author, motion designer, Unity developer, my producers’ favorite freelancer

No responses yet

Write a response