Hi, I started using Unreal Engine and I got this dilemma. What should I use? Blueprint or C++?
The best answer is... Yes! ;)
There's no dilemma. Your project should use both, if possible. Blueprint visual scripting hasn't been designed to entirely replace C++, although it's an amazing form of scripting. It allows people in non-programmer roles to script logic of the game.
Yes, it is possible to finish and publish a game using only blueprints.
- Blueprint-only project might an awesome way to develop game if you're hobbyist, solo dev or simply learning how to create games. There's a lot to learn in gamedev, so skipping learning of traditional programming language at the beginning would be a huge time-saver. And not everybody's mind is able to easily digest text-based programming. Visual scripting is more compatible with the brains of artists, level designers or writers.
- You might be interested in reading this: Solo dev Gwen Frey explains how she developed puzzle game Kine using only Blueprints
- However, a team of people would typically include a programmer. Or many of them.
If you have programmers in your team or anybody that spend time partially on C++ programming, you would simply mix both solutions. Visual scripting is meant to supplement text-based programming/scripting, free up programmers from scripting things that can be easily done by content creators.
- Scripting languages are typically less efficient than C++ code: slower to execute, using more memory.
- Most of the time performance impact of blueprint script wouldn't be noticeable, though. There are literally a few common performance traps in blueprints that you can't avoid by applying Fundamental Blueprint Practices.
- The bigger issues are caused by messy blueprints created often by people who work exclusively with visual scripting. They simply never had an opportunity to learn programming concepts and practices. These might severely impact iteration times and the quality of the entire codebase. Yes, assembling code from nodes can be quick, but messy code results in technical debt - it's difficult to work with it or build other features around this messy code.
- Blueprint people obviously can learn proper programming, but blueprints are so easy to use, so many people love to script things "any way it just works". "Any way" is often a terrible way. Bad code simply means that is difficult to understand, even for its author. Changing small things in messy code takes much more time and it's error-prone. It's easy to create bugs if code is over-complicated and badly designed.
- Learning any regular programming language helps a lot to learn how to efficiently use blueprints. Even learning C# in Unity would help you a lot since it would introduce you to programming concepts.
- People who don't know even basic C++ are unable to read and debug engine code. It means they won't ever understand what happens in the engine, what actually happens when the given function is called in blueprints. They can only guess how the game works, so they need support for a programmer person. Engine documentation and the internet won't ever answer all the questions.
- In consequence, the team without programmer won't be able to modify the engine code - which is quite common practice when working with Unreal. It's totally optional but extremely useful.
- A small change in the engine code might allow for implementing a game-specific feature that wouldn't be possible otherwise. The team would have to forget about that feature or implement it in a dirty way (workaround for unmodified engine code).
- You can quickly fix bugs and crashes in the engine. Often is a matter of changing a few lines of code. That's might very important when the game is about to be released - you simply need to release the game on the current engine version, but there are some critical engine bugs to fix.
- Sometimes you can easily integrate "changes from the future", a relatively small engine from developer branch of the engine (a bugfix or improvement to some system).
- The point above also applies to the code of plugins downloaded from the marketplace. Code of many plugins isn't perfect, it sometimes requires debugging and modifications.
- Node-based scripting offers only a limited subset of possibilities possible in the underlying programming language. Blueprints offer so much of Unreal C++ that is possible to implemented prototypes and a large chunk of the game scripting with nodes. Still, it's only a portion of general-purpose, multi-paradigm language known as C++.
- Only things exposed to Unreal Property System (Reflection) can be exposed to blueprints. That means we can use in blueprints only these data types and features of C++ that Epic handles in the engine. You might think you don't lack anything in blueprints only because you aren't aware of C++ features.
- In effect, not every feature implemented in C++ can be exposed to blueprints, i.e. Programming Subsystems would be a simple example.
- Blueprints support Object-Oriented Programming only. Every blueprint represents some kind of "object", inheriting after UObject class. Check Basic Object Classes to see the place of "actor" and "components" in this. Such setup is quite natural and intuitive for creating virtual worlds (everything in the real world is a kind of object, right?), but it's not the only way of programming.
- Slate - UI framework used to create all the editor UI - utilizes another programming paradigm called "declarative syntax". There are no UObjects here, Slate can't exist in blueprints. Editor UI can be created and customized only in C++ and Slate.
- In-game UI is created with UMG (see UMG UI Designer Quick Start Guide)) which is Slate exposed to UObjects through a special class called UWidget. Every in-game element created with UMG is a "widget", a kind of object that can't be placed in the world itself.
- Rapid prototyping. It's super easy to prototype mechanics, events, any kind of wild idea with in-editor tools, including blueprints. This can be done by non-programmers. Instead of wasting time preparing documents of fresh ideas and trying to explain to programmers, you can simply implement your own ideas. Often it's enough to start assembling blueprints to notice that given idea won't work. You need to abandon it or re-design while implementing it. You don't wait for a programmer and you don't waste programmer time on implementing rough concepts that are often impossible to properly explain in the early stage.
- Operating on assets. Blueprint is a marriage of code (every blueprint is a class based on UObject) and data. It's natural and easy to hook up any assets in blueprint code, i.e. material, textures, audio, you name it. The exact same thing might be very cumbersome in the text-based code. Often programmer would have to create a new variable just to get asset reference, hardcode the path to the asset (so code needs to be manually updated if asset name changes...) or create asset serving as a list of other assets...
- Small scripting. Any scripting of a single actor, i.e. how the door behaves or what happens when player interacts with the chest. There are dozens and hundreds of such scripts in heavily-directed games. Where every unique object, every minute of the game or every place on the map has some specific script enriching the experience. It would be pointless and counter-productive to hide such things in C++. Although it's recommended to put define a base of common classes (i.e. NPC, spawner, door, chest with loot) in code - ensuring easy interoperability between systems that should be written in C++.
- Scripting animation and UI. Developers can script animation states through animation blueprints. And implement UI with UMG blueprints. Even the procedural animation system - Control Rig - is partially based on blueprints.
- Simple editor scripting. It's possible to script some editor actions through editor blueprints. Although recently we can also use Python for editor scripting, which is a language commonly used in the art/VFX tools.
- Complex math and algorithms. It's slow and annoying to assemble complex logic in visual scripting. This might take a lot of clicking in blueprints, nodes wouldn't fit in the window (it's difficult to operate on big node networks) and runtime performance would be worse. While it would be super fast to write the same thing in C++, by adding only a few lines of text.
- Access to all engine and programming features. We don't write game code in raw C++, we mostly use the so-called "Unreal C++". C++ extended by Epic with its own core C++ library, designed for developing video games. Please read a separate article describing Unreal C++.
- Most of the engine is written with Unreal C++. If you know to write C++ for your game, you will already understand a lot of the engine code.
- Ability to write UI customizations and custom editors. There are dozens of editors in UE4 dedicated to the specific game system. This what makes this engine such powerful creation toolset. Nothing stops from creating your own project-specific editors which might be an incredible upgrade for your team.
- Blueprints are binary assets. You can't simply merge blueprints. It's possible to see a diff of blueprints version, but only in the visual form (two graphs displayed side by side). Refactoring complex blueprints take more time. Blueprints aren't a great solution for critical parts of the code, core of your gameplay.
- Systems. For all these reasons above makes C++ the only place where you should implement game systems. It gives you fast iteration times, the best performance and perfect control over what is available to non-programmer users.
- Efficient implementation of networked games. Blueprints can handle a lot of multiplayer features: replication, executing code only server or client and much more. Gameplay Ability System allows designers to take advantage of advanced multiplayer API which can't be simply exposed to blueprints. However... multiplayer game adds an entire layer to game development. Every object, function and piece of data have to be considered. Does it alive on the server only? Or this object is updated on the server but the change must be replicated to all clients? Or maybe to the owning client? These things