What are you looking for?
Games
How Fika Productions set sail with their peer-to-peer multiplayer hit Ship of Fools
DANIEL CROUGH / Senior Content Marketing Manager
Apr 11, 2024|8 Min
How Fika Productions set sail with their peer-to-peer multiplayer hit Ship of Fools

When Fika Productions set out to fill the market gap for a co-op roguelite game, they had their sights set on couch co-op. And then 2020 happened. We sat down with lead gameplay programmer Daniel Carmichael and developer Yannick Vanderloo to discuss their game and explore some of the development challenges they had to solve to get Ship of Fools to market during a complicated time for the industry.

What was the inspiration behind Ship of Fools? Do you have any colleagues with a nautical background?

Daniel: Our inspiration was first and foremost about filling the market gap for a cooperative roguelight. We’re all fans of the roguelite genre, and although there are a lot of great roguelite games, we felt that none of them did the co-op part really well.

Thematically, we loved the idea of a boat because if the boat sinks, everyone sinks. That’s the main core idea: work together to keep the boat afloat. No one had any nautical experience, and we’re not sea creatures or anything like that.

No octopi or salty sea dogs on staff. Got it. What does market research look like for you?

Daniel: Our market research was really just a small Reddit research activity, but we got a lot out of it. On 25–30 subreddits about couch co-ops and roguelites, we asked the question “What do you feel is necessary to have a successful co-op roguelite game?” We received a lot of suggestions, summarized them into a document, and looked for overlaps and themes. This process validated some of our ideas and also gave us some new ones.

What was your favorite moment of working on Ship of Fools?

Daniel: We had a small running gag in the office. Every time we shipped a small feature, someone would say “We have a game!” And, one day, we merged a big part of the game that was really important, and I playtested it and I’ll always remember saying to the team “We have a sellable game!” and that felt really different. That was a very proud moment for us.

Navigating network decisions

Was there a particularly challenging aspect of the game’s multiplayer development, and how did you overcome it?

Yannick: Networking in games is usually straightforward when either the host or the client takes full control. However, things get tricky when control needs to be divided, like when some elements are managed by the local player and others by the game host.

Projectiles were particularly challenging in this setup. We wanted them to feel snappy when fired, and that involved numerous scenarios to consider. Moreover, when an enemy fires back and a player deflects the shot, we had to meticulously plan the interactions and ensure they felt right for all players, even in high-latency situations. There were a lot of edge cases to think about. Especially how to make it fast and responsive for both players.

Daniel: Another big snag we ran into was networking. We spent a good year and a half designing the game for local co-op, not even thinking about online play. Then bam! The pandemic hit. Suddenly, our local-only game didn’t make much sense since everyone was stuck at home, not hanging out together.

Originally, we were all about that face-to-face, in-the-moment vibe. That was the heart of our game. But with the pandemic, our publisher was like, “Hey, we gotta go online,” and we were like, “Alright, let’s do this.” And man, it felt like we had to rework a year’s worth of stuff, tweaking every part of the game for online play.

So, a little tip for fellow devs: always have online play in mind from the start, even if you’re not 100% on it. Designing with online in mind is generally a solid move, and it’s way easier to strip it out later than to shoehorn it in after the fact.

Tell me more about managing projectiles, and how did Netcode for GameObjects come into play here?

Yannick: Networking our game ended up being a unique twist. We don’t have a traditional Netcode for GameObjects setup. Instead, we have objects that exist on both the client and host sides, each aware of the other’s actions and who’s in control at any moment. It’s like they’re constantly in a conversation, updating each other on what’s happening.

For instance, in a scenario where a bullet is fired, if it hits the target on the host’s side, the game waits for the client to confirm the hit. The client might agree, or it might say, “Nope, I dodged that one,” or even, “I reflected the bullet!” Depending on the client’s response, the game adjusts the outcome, ensuring both sides are in sync.

This setup allows for a lot of flexibility. Players on the client side can see immediate reactions to their actions, like a bullet being deflected, making the game feel responsive. However, the final outcome might need adjustments based on the host’s input, which can override initial reactions if there’s a discrepancy.

It’s a bit of a dance, with authority potentially shifting back and forth. We found the simplest solution was to let each side do its thing, then reconcile differences as they come up, based on feedback from the other side. It’s a collaborative process, ensuring both host and client contribute to the game’s flow.

Here’s a bit of a visual explanation for your readers.

Screenshot of Ship of Fools with two players on a boat
A multiplayer setup in Ship of Fools

In the first image, we’ve got our multiplayer setup, where I’m playing as Todd, the host on the left, and my friend is Hink, the client on the right.

Screenshot of Ship of Fools with an enemy shooting a projectile
Coordination via a remote procedure call

Then, a crabster enemy pops up and launches a projectile. It’s all about coordination here: both the host and client are informed via a remote procedure call. Both players see the projectile, but whether it hits the boat or gets deflected depends on player reactions, and the host needs to wait for the client’s input to confirm the final outcome.

Screenshot of Ship of Fools with a player deflecting a projectile
The client response as the projectile is deflected

Finally, here we see what happens when the client, playing Hink, deflects the projectile. There’s a bit of a delay if there’s high ping, so while the host might initially see the projectile hitting the boat, it’ll correct itself once the client’s reaction is confirmed. This way, the client feels no lag – it’s as if they’re playing in real-time, and their actions are mirrored by the host to keep the game in sync.

The whole idea is to make sure that when you’re in the heat of the moment, taking a shot or fending off an attack, the game responds instantly, making the multiplayer experience feel seamless.

Addressing Addressables and memory management

Any other specifics you could share? Anything our readers could take away as a powerful lesson learned?

Daniel: We hit a bunch of challenges, but one biggie was all about memory management. Getting our heads around assembly and Addressables was a steep learning curve, especially since this was the first multiplayer game for the whole team.

What’s funny is our game isn’t even that asset-heavy, but the load times hit two minutes at one point, which is crazy for a smaller game. That definitely caught some heat from the players.

So, yeah, we learned the hard way about keeping things streamlined, memory and asset-wise. We should’ve nailed down the basics from the get-go.

What about Addressables? What specifically did you learn there?

Yannick: The deal with Addressables is pretty straightforward. You’ve got to organize your assets into groups that make sense to load together at the same time. This way, you’re not bogging down your game with stuff you’re not even using in a particular scene.

For example, our game has different sectors, each with its own set of enemies, scenes, and scenery. Initially, we lumped everything into one massive group, which was a nightmare for loading times. To streamline things, we started grouping assets by sector. This made a huge difference because now, we can load just the enemies or just the scenery of a sector as needed, making everything way more efficient and smoother in the end.

Why did you choose Netcode for GameObjects (NGO) for networking?

Yannick: We went with NGO for networking mainly because it’s backed by Unity. This means it’s likely to evolve alongside the platform and get long-term support, which is crucial for us. Plus, NGO had all the features we needed.

The key thing we wanted was a peer-to-peer connection to avoid server costs, which can be a big deal for a game whose future sales and player base are uncertain. With NGO, we felt confident we were making a safe bet for both our present needs and future development. It seemed like the smart choice to stay within the Unity ecosystem and ensure long-term support for our game.

What’s next for Ship of Fools?

So far, we’ve rolled out two big updates, packed with fresh content, and launched two DLCs, introducing new characters to mix things up. These DLCs are totally optional, giving players more choices without making them feel left out if they decide not to grab them. The cool part? Those major content updates were on the house, and from what we've seen, folks really dug them.

As for what’s coming next, we’ve got plans, but we’ve got to keep a lid on them for now. However, when we’re ready to spill the beans on future updates, you’ll definitely be in the know.

Interested in multiplayer development? Explore the multiplayer section in the 2024 Unity Gaming Report to get insights from successful studios, fresh data on why more studios are developing multiplayer games, and a wealth of tips to help you and your team stay ahead of the curve.