Masterclass of Decoupling: Diablo II Resurrected
Decoupling is hard work, especially when taken to extremes – as the team of Diablo II did when they decoupled the whole rendering stack of the original game from the rest of the engine to reuse both independently.
Today I learned that Diablo II Resurrected is a true remaster: new 3D graphics, but the engine hasn’t changed. In an interview with Eurogamer, Rob Gallerani pointed out that
- they don’t use projectile physics,
- grid based movement and damage zones are still in tact,
- the 3D graphics is just another coat of paint for the exact same game logic.
Here’s the quote:
But when you talk about the feel, that’s paramount to us. And so that’s why under the hood, all of the logic and the simulation is still being run by sprites. It’s still a grid-based game. Hitboxes - so in a modern game, you would probably have your character represented by a capsule, and it would do a collision check because it’s 3D. We don’t do any of that. Our engine that runs on top is a visual engine. But all of the things of, did this attack hit? Are you standing in the right spot? Did this arrow make it to its target in time? That’s still all being run by the original game at the original framerate.
Now, our visuals run decoupled, so we can have 60 frames-per-second of animations, and we can add turnaround animations, everything like that. But once again, that logic and your breakpoints are still going to be driven by what the old game was.
So the game engine is the old Diablo II engine. It is not a replica.
You can switch to the old graphics with a key press not only because they rebuilt the whole game to be compatible. You can switch graphics and actually be running the old game as it has been (more or less).
Remember the last time you decoupled a handful of objects in your code so you could replace the implementation of some of them.
Image the work they had to do to decouple the whole renderer from the game engine.
This must have been hard work. Diablo II’s development suffered from horrible crunch, and that usually leads to corners being cut and clean-up tasks and refactorings never performed. It has all the benefits of the eXtreme Go Horse approach to software development, namely you get stuff done, but you better not touch it again. But they did. I imagine Michael Feathers (of Working Effectively with Legacy Code fame) would be proud of what the team did.
The Diablo II story is an inspiration: they pulled this huge decoupling off, based on an old (and likely very strongly coupled) release of the game. I have not seen the code, but I don’t imagine that my code (or yours) is more complex or messed up.
With perseverance and proper techniques, achieving a decoupled UI is possible for apps as well.
Now why would you even want to decouple the user interface of your app from the rest?
To publish on multiple platforms like Windows and GNOME/GTK for Linux for example.