Ahoy, Matey!
Driven by the Age of Sail - Sails of War is an action-heavy, fast-paced, combat-game offering a fun and exciting experience of team-based multiplayer combat!
Powered by Unreal Engine 4, Eight players take control over various types of ships with the goal to outmaneuver and sink the enemy ships of the Coalition or Pirates.

  • View media
  • View media
  • View media
  • View media
  • View media
  • View media
Post article RSS Articles

Ahoy, Pirates, and Coalition Sailors - Battle-Stations!

Tobias here - Programmer for Sails of War! It’s been a while - I know again!

Last year in may we shared an article about our new buoyancy system, that’s been scrapped - things can and will change! Lukas has been busy and has also moved again - but hey congratulations on the new job! So on the Art front, there isn’t much to discuss. However, there’s plenty on other fronts to talk about. In this blog, we have a lot to go over. A lot of my time has been spent maintaining, overhauling, and updating our systems in our game. But there are several new things to show you! In this article, I’ll be talking about our new buoyancy system (yes, a new one), and our physics networking.


Here’s a video of our current buoyancy and movement in action:

After further testing and adjustments, we concluded that the previous kinematic system for ship movement just didn’t suit all our needs. So I looked at other sources, too many sources. Down the line, I’d love to make this hull and buoyancy simulation into its project but for now, we focused on one source - Jacques Kerner's set of articles on Just Cause 3's implementation. This became my main inspiration for our system. It’s a great set of articles and I highly recommend reading them. You can find links to them in the Appendix at the bottom of this article.

Our buoyancy algorithm is split into five sections in chronological order they are - water queries, updating our mesh data, cutting the mesh’s triangles, splitting those triangles, and finally the force calculations on those triangles. Because of the change from kinematics to physics, we have utilized Unreal 4’s ability to substep each frame for its physics simulations. This is worth noting because the algorithm may be run more than once per frame if the frame rate is lower than our threshold. This means our costs per frame can double with our threshold of 30hz and a target simulation rate of 60hz. So any framerate below 60 will result in sub-stepping. If you’re interested in sub-stepping in Unreal 4 our implementation can be found in the appendix.

Intersection Algorithm:

Visualization of the intersection algorithm in use.

A delicate balance between efficiency and accuracy must be maintained to obtain optimal results for the intersection algorithm. This balance is described by the two inputs - the triangle size and the grid size. Failure to maintain a balance between the two can result in dramatically different outputs at a less than optimal cost. The algorithm itself is an approximation of an object with many triangles intersecting a moving and dynamic plane of fluid. The reason this algorithm is an approximation is that real-time usage would be impractical. Instead of running the wave queries on every single vertex of the object, we create a grid of points that we update each sub-step. Using this we approximate the wave height for a given vertex by projecting the vertex onto the cell of the grid that it is above. Several optimizations and a few large refactors of code were required to obtain this level of performance. As shown in the charts below.

The primary and largest contribution to performance is the number of iterations the algorithm has to do for each triangle. By refactoring this input in the various stages of the algorithm we can increase performance substantially. Below is a chart detailing the inputs for each stage of the algorithm, refactored and optimized on the left and unoptimized on the right.

Buoyancy Algorithm Iteration

Unoptimized algorithm benchmarks below:

UnOptimized Buoyancy Graph
The X-Axis is the time in the simulation step when the section is run (in ms).
Y-Axis is the how long (cost) that section takes to run.

Optimized Algorithm benchmarks below:

Optimized Buoyancy Graph
The X-Axis is the time in the simulation step when the section is run (in ms).
Y-Axis is the how long (cost) that section takes to run.

The above graphs are generated from data we collected on one of our hulls. What’s great about the graphs is that they are themselves an equation - an equation that we can use to very accurately estimate the cost to run any given hull without even implementing it in Unreal. This means it’s effortless and efficient for us to roughly benchmark any mesh we’re contemplating on using. On top of this, the equation allows us to figure out roughly what our optimal parameters should be to get the best results for our simulation. After a refactor of the code for optimization purposes the performance was increased by a magnitude of ten - from 5ms per frame to 0.5ms!

In the future, I’d like to challenge myself to lower this even further. This has the potential to allow us to locally simulate the physics of other player’s ships rather than utilizing solely an interpolation buffer system. There’s a bunch of tricks we can utilize down the road!

A primary concern is the number of objects being simulated. The more objects the more water queries being requested, and triangles that need to be intersected. As the number of objects increases the cost increases as well. The simulation is run on a single thread even though the separate sets of inputs and outputs for the simulation do not interact with each other. A performance optimization here would be to run these buoyancy calculations on parallel threads rather than one after another. This would decrease the cost to the most complex and costly object being simulated.

The grid update requires us to make water queries, this makes up roughly anywhere between 25% to 50% of the total cost. An optimization here would be to refactor the grids and put them into our Ocean Actor class. Storing them there rather than individually on the player’s movement component. This itself does not necessarily mean a performance increase, however, it does allow for a performance increase when objects are adjacent to each other and have overlapping grids.

Further optimization with water height queries is running asynchronous tasks post physics simulation on individual threads while waiting for the rendering thread to finish. Doing so would result in a zero cost case in the performance of obtaining water heights. This zero-cost is only obtainable if the cost of the water height queries is lower than the cost of the rendering thread to finish its calculations. If the time the rendering thread takes is less than or equal to the performance cost of the water queries the cost may still be reduced, however, this also could provide the opposite effect of forcing the game thread to wait for these tasks to finish before allowing the simulation to begin.

Physics Networking

Before delving into this I’d recommend reading and or watching the related links in the Appendix. Glenn Fielder's GDC talk is fantastic.

We’ve partially fleshed out our physics networking system for Sails of War, our buffer system is up and running, however, the aspect of the player on player collision reconciliation from those collisions still needs to be implemented. I’ve followed Glenn Fielder’s articles and talks on the concept of a linear interpolation buffer system for physics. Currently, the owning client simulates their physics and notifies the server of its current physics state - client authoritative physics. The server then replicates that information to other clients. The server and those clients interpolate the physics state on their end. Here’s a diagram showing what is going on:

Snapshot Interpolation Diagram

There are a couple of severe caveats to this approach of networking our simulation. All clients and the server are technically in the past when it comes to the position, rotation, and simulation of the ship! How far they are in the past is determined by how large our interpolation buffer is - the maximum buffer size times the interval between snapshots being sent. The client is in control of their physics simulation, which means they can cheat! The Player on player collision is especially not easy to reconcile because each ship is in charge of its physics state and position. It’s an issue of he said she said. Both are “right”, but they’re both wrong! A future article will address these issues and future expansions of the networking system.

Thanks for reading, until next time
- Tobias

Don’t forget to join the discussions of Sails of War and stay up to date with developments on our social media platforms!
Discord: Sails of War Discord
Twitter: Twitter.com
Youtube: Youtube.com
Website: Sailsofwargame.com


While interacting with Unreal 4 Community's Ocean Project (now Environment Project) I have helped them overhaul and provide the new groundwork for a new buoyancy system. With the addition of Gerstner waves being standardized in Unreal 4.26, I have no doubt someone reading this will find this project useful. This is their discord:
Unreal Environment Project Discord

Jacques Kerner's Gamasutra articles on Just Cause 3:
Gamasutra Part I
Gamasutra Part II
Implementation of Sub-Stepping in Unreal 4:
Sub-Stepping in Unreal 4

Physics Networking:
Glenn Fiedler’s GDC talk on physics interpolation:
Article Presentation
GDC Video Presentation

Replicated Wave Interaction and more - DevBlog #8 - Sails of War

Replicated Wave Interaction and more - DevBlog #8 - Sails of War

News 1 comment

Tobias here - Programmer for Sails of War! It’s been a while! In December we shared footage of basic multiplayer online gameplay and explained the designs...

Online Play and Important Milestones - DevBlog #7 - Sails of War

Online Play and Important Milestones - DevBlog #7 - Sails of War

News 1 comment

Just before the end of an exciting year, we are finally able to share gameplay and more importantly online play with you. Including a video, in this Blog...

Good News, Updates and more - DevBlog #6 - Sails of War

Good News, Updates and more - DevBlog #6 - Sails of War


A couple months of hard work, coming updates, news and game ready Ship models.

All done and painted - DevBlog #5 - Sails of War

All done and painted - DevBlog #5 - Sails of War

News 5 comments

After more then 5 months of hard work we are finally ready to show some ingame screenshots!

Hrocker - - 7 comments

So, another Naval Action sort of speak?

Reply Good karma Bad karma+2 votes
PortsideInteractive Creator
PortsideInteractive - - 4 comments

Naval Action is all about simulation. Our game has more focused on a fun multiplayer experience. Sails of War will in many ways be easier and less complicated - less boring in places. Start the game, drop in a match, have fun.
I'll have a blog post about gameplay in the near future; keep an eye out for it.

Reply Good karma+2 votes
MrEmjeR - - 131 comments

Damn, ship games are the real focus of indie games lately. Not complaining, ships are my favorite thing to make :)

Reply Good karma Bad karma+2 votes
eniex.at - - 10 comments

Ich habe mich gerade durch die Bilder geklickt und die Infos gelesen. Einfach nur wow. Sieht schon jetzt verdammt gut aus. Bin schon echt gespannt, was weiter kommt ;-)

Reply Good karma Bad karma+2 votes
Post a comment
Sign in or join with:

Only registered members can share their thoughts. So come on! Join the community today (totally free - or sign in with your social account on the right) and join in the conversation.


Latest posts from @sailsofwar

Work in progress; our Frigate still needs proper sails and better rigging. But backgrounds are coming along nicely.… T.co

Nov 20 2021

A short demonstration of our Buoyancy and Sinking! This is all working online and replicated. #UnrealEngine #UE4T.co

Sep 10 2021

Soon to be in-game in all her glory. Our heaviest ship: The 3rd Rate. #UnrealEngine #IndieGameDev #indiegame #ue4 T.co

Aug 22 2021

More work on our Frigate. Can you spot which ships our references are? Textures and sails up next! #UnrealEngine4T.co

Dec 19 2020

RT @TobiasMoos1: Next post about Sails of War is out! Indiedb.com

Nov 10 2020

Drifting and fast turning movement in Sails of War!@UnrealEngine #UE4 #UnrealEngineT.co

Jul 27 2020

Splash! Full Buoyancy in heavy seas! @UnrealEngine #UE4 #UnrealEngine #IndieGameDev #indie Follow the development… T.co

Apr 7 2020

Splash! One step closer to full Buoyancy - with gameplay impact on ships and guns! @UnrealEngine #UE4 #UnrealEngineT.co

Mar 3 2020

The video below depicts a buoyant force being applied to each submerged triangle and summed without any dampening w… T.co

Feb 23 2020

Final steps for a per triangle-based buoyancy system before applying forces - Waterline intersection of the partial… T.co

Feb 6 2020