“Parallax” is, quite simply, the name for the visual effects where objects seem to move differently depending on the viewpoint – in media we typically refer to parallax scrolling as a way to add depth to a flat scene by having several layers of background that we move at different speeds. It has been used in animated movies more or less since the beginning and in videogames since the early 1980s. While 3D rendering removes the need to take specific steps to create parallax effects it is still used heavily in most 2D side-scrolling games.
Parallax scrolling existed in the Backworlds engine even before we started working on the original prototype, but I’ve recently had to change the workflow a bit to make production more streamlined so I thought I’d talk a bit about how it works today.
The implementation of a parallax layer is remarkably simple – essentially we just multiply camera movement on the parallax layer by the ratio between the parallax layer size and the full level size to cause the edges of all layers to meet up in the corners. For instance, if we move the camera 100 points to the right we need to render all objects 100 points to the left, but if a parallax layer is only half the size of the full level we would only move the objects on this layer 50 points to the left. Note that if this method is used you need to detract the window size from the size of the parallax layer, as you are actually looking for the max scroll position rather than the full level size – if a scroll layer is equal to or smaller than the window size, you do not want it moving at all.
The way this is implemented in our engine is something of a hack – everything we render has a priority that determines the order in which they are rendered (and thus, what is rendered on top of what else) and the parallax layers just define a priority range and a layer size. When we render the scene, we check the priority of every object we render to see if we entered a new parallax layer – if so, we update the scroll multiplier setting before we render it. This solution has the advantage of being decoupled from the rest of the rendering and making levels without parallax layers very light, but it does mean we have to add a large amount of extra verification to make sure we do not move objects between layers when we are changing the render order. In hindsight, I should have made the parallax layers hold lists to the objects they wanted to render to make a cleaner and more easily modifiable scene hierarchy, but since the system does not require much change it has not been worth the effort to rewrite.
Originally the size of the layers were stored per-level and the sizes were in pixels – this was useful for scenes where we had a good idea of exactly we wanted to fit into the background layers, but it took a while to set up for every individual layer and could be difficult to calculate. We recently changed the layer sizes to be percentages of the full level size to make it easier to maintain a consistent scroll speed. We also moved the layer setup itself to the shared world settings to remove the need to set it up for every new level and keep scroll speed consistent across levels of the same world – unlike other settings these cannot be overwritten so individual levels cannot have a different number of parallax layers than what the world decides for them. This is not really an issue though – we just make sure to have enough parallax layers to accommodate all levels in a world and ignore the ones we do not need for the individual levels. Since the layers are just a priority range and a size, there is practically no overhead for empty parallax layers.
Levels typically get a lot more objects when we introduce scroll layers and it can be difficult to handle editing, while we can edit all layers at once we typically set the editor to freeze the layers we are not working on, or hide foreground layers completely when we are working on background layers. Background art is one of the last things we add to a level, so there is typically not a lot of changes to game objects and geometry when we start working on them. Also, we try to be somewhat sparing with the use of parallax layers as they add a lot of visual complexity to a scene which can be confusing when there is a lot of painting going on.
Juha has been working a lot on getting production-quality art on some of our finished levels lately, this has been interesting as we have had to tackle a lot of questions about workflow and how some of our artistic guidelines work with the puzzles. We’ll have more on the art in future updates!