Rival Megagun is a split-screen PVP battle shmup (or shoot ‘em up, shooting game, STG) where you transform into a huge boss ship - your “Mega Gunship” - to invade your opponent’s screen.
Released November 29, 2018 on PC, PS4, Xbox One, and Nintendo Switch. Here are some reviews.
In 2014 I started building a simple prototype written in Java called Project Rival. I worked on Project Rival in my spare time on evenings and weekends. As the game started to take shape it was moved to Unity to reduce development time.
Project Rival - Java prototype
Rival Megagun - First day in Unity
In 2017 I began working full time on Rival Megagun. Shortly after that, I partnered with Japanese publisher Degica. Quickly Rival Megagun transformed from a cool idea into a full-fledged project. Over the next two years I built Rival Megagun with the help of a small team: Jordan Ivey, sound designer; Brooke Fargo, narrative designer; Aarne Hunziker, artist; and Dominic Ninmark, musician.
Rival Megagun now
In 2018 I met with Yoshiyasu Matsushita in Tokyo, Japan. He is the creator of Twinkle Star Sprites, the original game that sparked inspiration for Rival Megagun. As you can imagine this was very exciting for me.
4Gamer interviewed us together. Check it out here (Japanese).
Meeting Yoshiyasu Matsushita
Rival Megagun has been showcased at many events all over the world. Below are just a few examples.
I showcased Rival Megagun at BitSummit 2018 in Kyoto, Japan. Unity interviewed me at this event. Check it out here (Japanese).
BitSummit 2018
I showcased the game at The MIX 2018 in Seattle, WA. Shacknews interviewed me at this event.
Shacknews Interview
I also showcased Rival Megagun at PAX South 2018 in San Antonio, TX.
Rival Megagun at PAX South 2018
The first convention I showed Rival Megagun at was the Seattle Indies Expo 2016. At the time I didn’t have many features planned beyond a simple local versus mode. I had no plans for online multiplayer. Lots of people came to play Rival Megagun at the Seattle Indies Expo, and such a huge number of them were asking me if there would be an online mode that eventually I just started saying “yes”. I implemented online multiplayer first thing when I got back from the event.
Shmup networking is known for being particularly challenging. These types of games have very small hitboxes and lots of bullets and enemies on the screen, so every pixel counts. With Rival Megagun we are lucky because it is a split-screen game. To put it simply, there is never an instance where both players need to dodge the same bullet. This give us much more leeway for hiding lag and synchronizing online play.
In Rival Megagun’s online battles, most of what you see on your opponent’s side of the screen is running locally, with the exception of the player’s ship position, which is simulated with movement prediction. This makes for very smooth online play because you never encounter teleporting enemies or bullets due to lag spikes.
Synchronization of the “Mega Gunship” had to be implemented differently from the normal player ships. During this mode both players share one side of the screen and fire bullets directly at each other. This requires more precise synchronization. Fortunately, there is less need for finesse while controlling your character in the Mega Gunship, so the solution was to implement input delay for the Mega Gunship. This keeps these head-to-head battles smooth and synchronized.
Here’s a video I found of some online battles:
Rival Megagun online battles
Rival Megagun’s online multiplayer was implemented for all platforms using the platforms’ online services (Steam P2P, Sony PSN, Xbox Live, Nintendo NEX/Pia).
I shared details about how to implement online multiplayer on Steam with Unity here.
Rival Megagun has a single player arcade mode where you are pit against the other characters and fight them one by one in the standard split-screen format. For this to work, the CPU player requires bullet hell dodging AI.
The dodging AI is fairly simple when you break it down:
There are three noteworthy lines in the image below: the line connecting the subject to the closest hazard (red), the closest hazard’s direction (green), and the subject’s direction (yellow). If the three lines form a triangle, switch the subject’s direction.
Debugging player ship AI
Below are just a few examples of how I implemented the UI in Rival Megagun.
The gameplay UI must be completely independent from the game logic. In other words, if I delete all of the UI, the game must continue to function without it. For this reason, all of the gameplay UI components use an event system to update themselves based on the current state of the game.
For example, here is the Win Counter:
public class UIWinCounter : MonoBehaviour {
public UIIconCounter totalWins;
public UIIconCounter currentWins;
void Start ()
{
EventManager.Instance.Subscribe<RoundEndedEventArgs> (RefreshWins);
totalWins.maxIcons = GameConfigManager.Instance.gameplay.winsNeeded;
currentWins.maxIcons = GameConfigManager.Instance.gameplay.winsNeeded;
totalWins.SetCount(GameConfigManager.Instance.gameplay.winsNeeded);
currentWins.SetCount(0);
}
void OnDestroy()
{
EventManager.Instance.Unsubscribe<RoundEndedEventArgs>(RefreshWins);
}
void RefreshWins(object sender, RoundEndedEventArgs args)
{
currentWins.SetCount (GameplayManager.Instance.GetWinCount(gameObject.GetSide().ToPlayer()));
}
}
Win Counters
Much of the UI in Rival Megagun is built using my custom “popup” system. A popup can be anything. Character dialogue, the pause menu, and the game over screen are all examples of popups.
The game over screen is just a full-screen popup with a transparent background.
The popup system is simple and versatile. Here’s the Alert Popup, one of the most basic popups in Rival Megagun:
public class AlertPopup : Popup {
public TMP_Text label;
private Action onClose;
private bool onCloseTriggered;
public override void Setup(object[] args)
{
LanguageManager.Instance.SetParameters(label, args[2] as object[]);
LanguageManager.Instance.SetTerm(label, args[1] as string);
onClose = args[0] as Action;
onCloseTriggered = false;
}
public static object[] BuildArgs(Action onClose, string locKey, object[] locParams)
{
return new object[]
{
onClose,
locKey,
locParams,
};
}
void Update()
{
if (IsTweening())
{
return;
}
if (InputManager.Instance.GetInputDown(GameData.InputController.ANY, InputActionID.CONFIRM))
{
Close();
}
}
public override void Close()
{
base.Close();
if (!onCloseTriggered && onClose != null)
{
onCloseTriggered = true;
onClose.Invoke();
}
}
}
The popup is displayed with a simple function call:
PopupManager.Instance.ShowPopup<AlertPopup>(AlertPopup.BuildArgs(locKey, onClose, locParams));
Alert Popup
BuildArgs
is implemented for each type of popup to feed arguments into Setup
. This structure makes it easy to implement any type of popup.
Many complex popups have been implemented using this structure. Here’s a few:
Popup Prefabs
I built a system for displaying UI elements inline with text.
For example, this dialogue data:
"dlg_tutorial_04_a":{
"id":"dlg_tutorial_04_a",
"characters":[
"HOST"
],
"next":"",
"locKey":"Dialogue/Tutorial/04",
"inlineElements":[
{
"elementId":"BUTTON_0",
"type":"BUTTON_ICON",
"attrs":{
"action":"fire",
},
}
]
}
Maps to this text:
Oh yeah baby! Now let's shoot some stuff. Press <style=inline>BUTTON_0</style> to fire.
,
And has an inline element named “BUTTON_0”.
In this particular example, the element is a button icon, which is a special type of inline element that detects the player’s controller type and displays the button mapped to the desired action (in this case the “fire” action).
Here’s how it looks in-game:
Rival Megagun inline element example
Here are some of the development tools that I created for Rival Megagun.
The Bullet Builder is used to create enemy bullet patterns and export the data to JSON. Bullet patterns are customized and attached to various emitters (or “guns”) on each enemy. With this tool you can play and experiment while designing bullet patterns at runtime.
Attaching bullet patterns to an enemy’s guns
Configuring bullet pattern
The Wave Creator is used to create enemy “waves” and export the data to JSON. A wave is essentially a group of enemies and some rules defining how and when they should spawn.
Each wave is assigned a difficulty range in which it is able to spawn. In any Rival Megagun match, the difficulty increases over time, causing the gameplay to get more hectic as more difficult enemies and bigger or more complex waves spawn on the screen.
Configuring wave’s spawn rules
Configuring wave’s enemies
Rawchars is a collection of raw text files containing characters in different languages. When localizing games, generally you should generate your fonts using your localized text. However, you may also need to display user content (i.e. user names). I created “Rawchars” to help cover all the bases.
Get it on GitHub.
When we were localizing the game we noticed that some of the characters in Chinese, Japanese, and Korean (CJK) fonts had inconsistent baselines. Unfortunately this was because the OpenType Base table is not supported by the font plugin we were using, and our only option at this point was to manually adjust individual characters. I am not versed in CJK, so I couldn’t trust my own eyes with this issue. I created a tool for translators to fix the fonts using in-game text examples.
Font Correction Tool
Rival Megagun was released worldwide on November 29, 2018 on PC, PS4, Xbox One, and Nintendo Switch.
We have teamed up with First Press Games to release Rival Megagun physical and collector’s editions on PS4 and Nintendo Switch!
Rival Megagun Collector’s Edition
More info here.
An arcade version of Rival Megagun is now playable in arcades across the globe on the exA-Arcadia platform.
Rival Megagun XE
More info here.