However fine an engine Unreal Engine 4 is and however great its tools and visual scripting, there are definitely a few areas it doesn’t quite measure up. One of those things is its not-supported-really-but-kinda-in-there Paper2D component, which Piczle Cross Adventure relies on quite heavily. Now of course I could (and perhaps should) be called foolhardy for not choosing an engine better suited to 2D game development but for speed of development I’m sticking with what I know. So instead I deploy a raft of sneaky tactics to bend UE4 to my pixelly will.
The faux CRT effect is a post-process applied to everything in the game. However, Slate Widgets are not affected by post-process effects. This means all the user interfaces, dialogues, options, menus and even the nonogram puzzling has to “physically” be in the world.
Post-processes are currently applied to everything in the game, so adding unique effects on parts of the world is a much harder task. I can’t really isolate the interface from the game with custom depth, so as it stands I have to be more creative with additional effects. Some effects, like an incomplete puzzle’s fuzzy, reality-distorting field is simply a material on a quad in the world that uses SceneColor to mess up the visuals.
Another issue is using the orthographic camera. UE4 and lighting and orthographic cameras do not like each other. As such I am pretty much tied to unlit (or self-lit) graphics and can’t rely on cool lighting techniques much. A lot of the “lighting” effects in the game are done with either materials that use SceneColor or are hand-animated into the art.
A lot of widgets are created at the “true” resolution (320×180 pixels based on the readability of the clues in the largest puzzles). This means a lot of menu animations and such can use nice and chunky pixel steps for that authentic retro feel. Characters, however, are controlled Pawns and Actors that slide smoothly through the world. Having a 320×180 scene scroll smoothly in 1920×1080 resolution is very jarring. To combat this I “lock” both the camera and the player characters to full pixel positions.
What this means is that, for example, Score-chan’s Actor BluePrint uses its capsule component as both its collision sphere and its true location, but the attached sprite (FlipBook really) is only ever rendered at a full pixel coordinate. E.g. if the capsule (true Actor’s location) is, say, x: 103.44567, z: 99.4432122, the sprite component (the actual visible character) is rendered at x:103, z:99. The same goes for the player camera. It looks at the player actor’s capsule component and similarly rounds off those coordinates to place itself at an absolute pixel position.
Of course I cheat all over the place. There are particle effects that utterly ignore this, and I even scale certain objects with no regards to the actual pixel density of the scene. But I’ve made a decision to be okay with this, as it’s not as noticeable as the smooth scrolling of characters and the whole background.
Scaling widgets and graphics from 320×180 to 1920×1080 is no issue. With nearest neighbour filtering everything remains sharp and as long as I stick to the right ratios it all looks like it should. Text, however, turned out to be a real problem. I created, by hand, a chunky pixel font that fits nicely with the chosen resolution. However, I have as of yet not found a way to scale fonts with nearest-neighbour filtering meaning all fonts were a blurry mess. As such, widgets that rely on text are actually made at 1920×1080 but feature graphics that are scaled 600%. Sometimes it is a combination. The puzzle widget, for example, runs entirely at the smaller resolution, but when the puzzle’s solution appears a new widget is shown over the puzzle widget just to handle the text.
Personally, the most fun parts of game development are unravelling problems and finding cool solutions to them. Some of the issues above could have been avoided by using a different engine, but that choice would have presented a host of other issues I’m currently not having to deal with. As it stands, dealing with some self-imposed and engine-imposed limitations has been motivating. Finding solutions to some of my issues has been a great, fun challenge. I fully expect to learn about techniques that could have helped me further in the future, but that is what game development is; a constant learning curve, even if all I’m doing is using modern technology to imitate very old technology.