So it’s been a while since I’ve done one of my “Soap Box Rant”-style posts, but I keep running into something that kinda bugs me and I’d like to rant about it. I subscribe to a lot of game development forums and boards and I can’t help but notice certain patterns in posts. Lately, I’ve been seeing more and more posts like this:
Person A: I am looking for an engine to write my game in. Is Unreal Engine any good?
Person B: Unreal Engine is great, plus blueprints allow you to quickly wire up your game for prototyping.
Person C: Ha! You think blueprints are good?!?! (insert snarky comment containing multiple references to spaghetti) Just look at this!!
…sigh… Let me start out by saying I love blueprints in Unreal. I’ve dabbled in multiple styles of visual scripting languages in the past–Playmaker, Kismet, Blender–and generally I’m not that big of a fan as I find it easier and faster to just write the code, but there’s something about blueprints that I really like. Person 3 from the above post is in a strange, Schrödinger’s cat state of being both correct and incorrect about blueprints.
Yes, Blueprints can get very messy, but a blueprint doesn’t just messy itself. It takes a mess architect to create a monstrosity like the one in the above image, and the idea that messy unreadable code is limited to blueprints is ludicrous. I’ve worked as a software developer for nearly a decade in traditional coding languages, and let me tell you, I’ve seen some shit…. functions that are over 1000 lines long, for loops inside of for loops inside of for loops inside of for loops inside of.., variables named “myVar”, functions with only one line of code that just calls some other function… I could go on and on, but my point is that it’s still possible to write shitty code without a single blueprint. What is important is that a language gives you the tools to not have to write bad code, and a blueprint does exactly that.
That having been said I will admit that going through the images of blueprints posted to the unreal forums can sometimes be quite a nightmare. One of the great things about blueprints is that it makes coding accessible to people who have never written a line of code before in their life, but I also think that fact is responsible for why people outside of Unreal think blueprints look like someone left a cat unsupervised in the yarn section of a Jo-Ann Fabrics.
I’ve written before about needing to be OK with sub-par code. I still stand by everything in that post, but just as no great book was ever written in a first draft, so too should no game be written without a great deal of REFACTORING! Refactoring code means going through your hastily written prototype blueprints and making more readable, more usable code out of them. For a lot of developers this will mean writing them out in C++, but for the sake of this article let’s say you don’t know C++. There are still ways to clean up and refactor existing blueprints.
Note: I realize that a lot of these tips are personal opinion and should be read as such. I’m not trying to argue one way of refactoring over another but instead offer my method if you do not already have your own.
Things to look for when refactoring blueprints
Copy and Paste: The first way to massively narrow down the size of a blueprint is to look for areas where you hit copy and paste. If there’s a bit of code you find yourself needing in multiple locations, there’s a really good chance that section of code should probably be it’s own function. Got different variables you need to execute it against? Great, make them inputs for the function. Need to use the code returned in different locations? Great make them outputs!
Variable Spaghetti: So lets say you ran a trace or something that returns a whole bunch of variables that you need reference to in a whole bunch of other places. If you just drag and drop the connections you’ll create a mess. Instead consider promoting them to variables. If you’re in a function (which you probably should be if you are using a trace) consider making them local private variables.
Similar Functions Used on Multiple Blueprints: So let’s say you moved, copied, and pasted code to a function. That’s great, but now you want that same function to be able to be called on a different blueprint. Well there’s two ways to go about that. If the function is a utility that could be used on any number of blueprints consider making it a macro. If it belongs to a blueprint related to a second blueprint, for example you’ve written code on a car that honks it’s horn, and you’d like similar code on a truck, consider using inheritance to make a vehicle blueprint, moving the horn honking code to that and then making both the car and the truck inherit from that blueprint.
Awkward Names: Any function or variable names sound strange to you now? Well guess what. It will seem completely foreign to you when you find yourself trying to debug something in that same section of code a month from now. Typing out long explicit variable names isn’t fun for anybody, but the you from a couple of months from now will be more than willing to buy the you from today a drink for the effort. Trust me. Also it never hurts to come up with a naming convention and stick with it.
A Lack of Comments: Most of this is about making the code cleaner so that it’s easier to read and see exactly whats going on. Comments theoretically should do just that, so that you don’t need to read the code. The developer just wrote in plain English what that section of code does. The true strength in comments though is that they tell you what the developer thinks that section of code does. Being able to see what a section of code was intended to do can sometimes really help when making code actually do what it’s supposed to do.
Really Long Blueprints: Do you find most of your functions are just one really long sequence of nodes that you have to keep scrolling to the side to read? Consider using a sequence node to break that into discrete pieces and make your code way more readable.
Wires Crossing Nodes: Do you have any wires crossing over a node they do not connect to? Then you potentially have a graph that can be easily misread. Save yourself some trouble by using a redirect node to make the graph a little neater. It’s super simple now that adding it only requires double clicking an existing wire. I use it almost to a fault in my code.
Un-aligned Nodes That Make You Feel OCD: This one doesn’t make your graph any easier to read, just nicer to look at. Unreal Engine introduced node alignment tools a couple builds ago that made lining up nodes so much easier. Just highlight the nodes you want aligned and right click to open the context menu. Honestly this stupid little tool has become one of my favorite features in Unreal.
Anyways, thanks for listening to me rant. I hope some of my code refactoring tips help. I really just glossed over a lot of the ideas here. If you’re interested in having me go over any of these ideas more in depth (e.g. inheritance, macros, etc.) just leave a comment and I might make that the topic of a future post.