Setting up a Modular Unity Project

Motivation

An early Mighty stand-up at Bear Force ZERO

Early 2017, Mighty Bear was 7 people squeezed together on our CEO’s dining table working on the studio’s first game. The Engineering team was a small team of 3 and trying to build an MMORPG for mobile. Communication at that time was easy, we were working on a single project and we just talked to each other from across the table.

As we grew the studio, going from a team of 3 to a team of 8, and going from working on a single game project at a time to working on multiple game projects in the studio, we could no longer easily maintain multiple versions of a script across projects. Sometimes the same script used across projects have diverged so much that it was hard to merge bug fixes for them.

We needed a strategy to share code across projects. The solution needed to address the following:

  1. Updates and fixes to the shared code needed to be tracked and versioned
  2. Projects could choose which shared code and version to use
  3. Unit and/or functional tests could be written for the shared code without having game project dependencies and polluting the game projects

Unity Package Manager (UPM)

Unity had the same problem to solve. They needed to modularise the editor and runtime tools that constitute the Unity editor so that they can make changes or fixes individually without needing to release a new version of the Unity editor. Unity created UPM to help them with this goal and luckily they opened it up for developers to use it too!

The Mighty Bear UPM pipeline setup

  1. Setting up the Package
  2. Releasing a new version of the Package
  3. Installing the Package
  4. ???
  5. Profit

Setting up the Package

Create a new unity project with the corresponding git repository.

In the Packages folder create a new folder with your package name (e.g. Packages/MyModule). This is where all the scripts, for the published package, will reside in.

Add this file in the Packages/MyModule folder

Pro Tip #1: You can define sub-packages as dependencies for a package by adding the name and version of that package in the “dependencies” property.

Releasing a new version of the Package

Every time you want to release a new version of a package using UPM, you need to do the following:

  1. Update the package number
  2. Update the changelog
  3. Commit changes to git
  4. Generate release version and tag in git

We use the following setup for automatic semantic release to reduce the manual steps needed. To set this up, add this file in the root folder of the Unity project

  1. tagFormat — This must be consistent with existing tags otherwise the next release will reset back to 1.0.0
  2. plugins — Tasks to run in order
  3. semantic-release/commit-analyzer — Generate the type of release accordingly based on the commit comments
  4. semantic-release/release-notes-generator — Updates the existing CHANGELOG.md file based on the commits
  5. semantic-release/npm — Updates version # in package.json. Set npmPublish to false to disable publishing to the NPM registry
  6. semantic-release/git — Commits package.json and CHANGELOG.md to git. [skip ci] to avoid endless looping
  7. semantic-release/github — Creates a new release with the appropriate git tag

Commit messages must be in this format so that the changelog is updated accordingly:

chore(release): ${nextRelease.version}nn${nextRelease.notes}
Example
chore(release): 1.0.0  
* fix: if any additional notes
* feat: an exciting new feature

Create the .github/workflows folder and add this file:

These actions are run every time a push is made to the master branch:

  1. “Create upm branch” — Creates a new UPM branch based on our package root
  2. “Create upm git tag” — Generates a new tag whenever there’s a new release on the UPM branch

Pro Tip #2: Use namespaces to ensure that there will be no class name collisions.

Installing the Package

You should have something with the following setup after creating all the necessary files:

MyUnityProject
.github/workflows/ci.yml
.releaserc.json
Packages/MyModule/package.json

Once a release build has been made, we should see a release build version in git, with the corresponding tag for the build.

Automatic semantic release and tags in Git

To install the package, open up Unity’s package manager and select Add package from git URL…

The address with the following format:

https://github.com/MyRepository/MyModule.git#upm/[version_number]
Installing package with versioning

Next Steps

Now we can use UPM to manage our shared code across projects, but this is not a perfect solution yet. Our shared code are private repositories and we don’t want to publish package version updates to npm. This means that the Package Manager UI in Unity will not list the different versions. We will need to add a repository and version manually if we want to switch versions. An improvement to this would be to write a small UI tool that lists the versions available and enables switching with a button click.

Fresh popcorn doused in Peri-Peri seasoning was a weekly Friday treat!

This setup will be very useful for other small studios who are growing and working on multiple projects. For a more in depth discussion of UPM best practices, check out Favo Yang’s, founder of LittleBigFun, series on How to Maintain UPM Package.

Also a shout out to Fadzuli Said for co-editing and peekture selection!

If you are interested in joining us at Bear Force One to build our next breakthrough games, do check out https://mightybeargames.com/careers for more details!


Setting up a Modular Unity Project was originally published in Mighty Bear Games on Medium, where people are continuing the conversation by highlighting and responding to this story.