From Unity to UE4 - Part 1

· by Steve · Read in about 30 min · (6179 Words)

Almost 4 years ago now I blogged about my decision to use Unity for our new game development adventures, and in that time we’ve shipped one game (Washed Up!), stealth-shipped one polished prototype (only to our bestest fans 😏), participated in 4 game jams, and noodled with another 2 prototypes that never saw the light of day. All of those have used Unity, and generally speaking we’ve been quite happy with it.

But for our next game, we’re switching to Unreal Engine 4. This post will be a summary of why I made that decision, because it seems from Twitter that quite a few people are interested in that.

This is going to be a long one, but if you flag in the middle, I will absolutely peer over the top of my glasses and remind you that you asked for this. πŸ˜‰

I’ve split this into (at least) 2 parts because it got too long. But this part covers probably the most important / controversial bits!

An important note

This post is not going to consist of me bashing one engine and praising another. If you were looking for that kind of content, apologies; the rest of the Internet will no doubt provide an ample supply of tribal bloodlust elsewhere.

I still like Unity, and still respect the people working there. I’d even call some of them “Internet friendos”, although I expect they’d have mixed feelings about that. And who knows, I might go back the other way some time, so let’s not burn any bridges, right? πŸ™‚

Why revisit UE4?

In general, I always think it’s a good idea to re-examine your past decisions when reaching a new junction point. I’ve never believed in just continuing the trodden path because it’s easiest - that’s led me to switch languages, platforms, and sectors in the past. I’ve (almost) never found this to be wasted time, you always learn something even if you decide your previous choice was correct. Things constantly change - what project you’re working on, your level of experience, your preferences, the tools themselves.

Of course you can’t just mix up your toolset randomly all the time, you’d never get anything done. But it’s not unusual to have natural break points between projects sometimes, and if you have the option it’s good to use those brief periods of downtime to take stock.

I had one of those breaks as we came off our previous project. A number of things had changed from 4 years ago, and in the back of my mind pressure had been building to have another look at UE4.

Reason 1 - Experience

Happily, we have actually learned something over the last 4 years about game development. This might sound obvious, but matching your level of personal development with the tools you use is important.

Unity has always been very beginner-friendly, while UE4 is less so; it’s not insurmountable to go from scratch to UE4, but it’s more daunting. I feel a lot more at home in gamedev projects than I did 4 years ago, despite my decade plus of graphics dev before, and that does make a difference.

Reason 2 - Moving from 2D to 3D

We started by working on 2D games, which was sensible not only for scope containment, but also Marie could transition her existing art skills more easily to 2D. Unity is great at 2D games, and I’d argue is probably best in class for the particular kind of “lit 2D” look we like. Neither of us are particularly into pixel art, so engines which prioritise that approach (pixel units etc) don’t have any benefits for us. Unity’s “2D in 3D” style was a great fit.

However in the last 12-18 months Marie’s been learning to 3D model & animate, and we’ve been increasingly working with full 3D - so far on only 2 cancelled prototypes, although the last one was shipped to mailing list subscribers at least. So the 2D pipeline advantages of Unity don’t apply anymore.

Reason 3 - The Noodle Graphs are Alright

I have a history with visual coding from about 2000, and it wasn’t pretty. I was a member of a mid-size team of developers working in an early visual coding system called VisualAge for Java, working on a non-trivial enterprise system. We encountered all the problems you’re all no doubt listing in your head about visual systems - and I’ll talk about them in more detail in the dedicated Blueprints section later in this post.

But, I’ve changed my mind. Specifically for this team scale, and specifically with the tooling that UE4 has provided, which is really good. Being OK with visual coding has been a major shift in my perception of how productive I could be with UE4, which otherwise would require C++ (again, discussed in more detail below).

Reason 4 - Built-in Features

UE4 has quite a few things built-in that you have to find/buy for Unity as extras.

I really like using Behaviour Trees for AI and had bought a Unity asset store plugin for that. UE4 has a really good implementation of behaviour trees built-in.

I also bought the Amplify Shader Editor - Unity does have its own Shader Graph now, but it was missing a few features I wanted, like GPU instancing support. Amplify had more features and was just generally more mature. UE4’s material graph system is very fully featured and mature (I’ll talk about it in more detail another time).

UE4 also has very long-standing support for networking, and for our next project we’re considering supporting networked co-op. Unity’s own networking system UNet has been deprecated since 2018, and no-one knows when/if a new one is coming along, so really you have to use a 3rd party library.

Reason 5 - Feature Stability

The primary reason I chose to use a 3rd party engine for my gamedev adventures is that I felt it essential to get away from working on the “guts” of the technology underpinning games. I’d spent more than a decade doing that, and what I really wanted was tech that had been designed specifically to make games, and had been road-tested by enough people that I could be confident that all I had to concentrate on was using it.

In the last couple of years Unity has gone through some pretty fundamental changes. The two big ones are DOTS and the Scriptable Render Pipelines, although there are others. It’s been combined with quite a granular release system, where each feature can now change on its own release schedule in packages.

The result has been a lot of churn in Unity since 2018. These new systems will be great when they’re finished. Of course, unavoidably, major change takes time and has wobbles along the way, there’s no avoiding it. My problem is that I used a 3rd party engine so I could hand off worrying about this kind of instability to someone else, and I found trying to develop products against this moving backdrop to be quite stressful.

Features have remained in Preview for a long time, with significant, sometimes breaking changes. Documentation is often incomplete (of course, it’s Preview). Advice in forums etc becomes out of date. And because the change is in core systems, with similar names / terminology / concepts to the old systems, it can be super confusing to find information.

For example: if you’re searching for a rendering question, you can get potential hits from the legacy renderer, or one of the new scriptable render pipelines. They all have slightly varying nuances. Then, add the fact that the SRPs have been changing over the last 2 years so some of the SRP advice is out of date. One of the SRPs has been renamed as well. Finding reliable information about something in a core area can easily become a minefield of dead ends and misinformation. It’s quite frustrating.

Change is normal in tech, but I’m afraid this has ground me down over the last year. Yes, I could ignore all the new stuff until it came out of preview, but given how long it takes for that to happen it feels like developing on a burning platform that no-one maintaining it will care about. All the effort is going into those multi-year preview packages after all. And all this tech is right in the core, it’s not something you can (easily) tack on later, which increased the pressure to try to keep abreast of it.

After a while I recognised how much stress this uncertainty was causing me. Some of it is an emotional reaction, part FOMO part change aversion, but it was really bothering me. So, I started to cast glances at the seeming relative stability of UE4.

Note 1

This will most likely pass in time. Unity’s new systems will eventually settle down, mature, and build up a repository of community experience - it’s just not there yet, and I don’t really know when it will be. When DOTS and the SRPs were announced in 2018, I was excited. I figured I’d tinker a bit, but wait until late 2019 or so for them to be stable before using them in production.

By and large the SRPs are now stable, although still under significant change. DOTS isn’t stable, and you really have to re-learn how to use Unity with it, and write a lot of “enginey” things right now. It feels like it’s going to take another year or more for everything to mature to the stage where you don’t have to worry about it.

Note 2

UE4 does have things in preview (they call it Experimental). However, my experience with 4.24 is that it’s never large features in the core; it’s either on the periphery (like Localization, AI Environment Queries, destruction systems) or small QoL improvements to core things like in-editor HDR monitor support. It feels considerably less disruptive / anxiety inducing.

Also, UE4 hasn’t always been like this. Looking back at some older forum posts it’s clear UE4 has gone through its own periods of wobbly feature migration as well. Change has to happen sometimes, it’s just not nice to balance on top of it while it does.

Note 3

This is also the reason I chose to look at UE4 specifically and not an open source project like Godot or Ogre, despite my background. I’m too old & broken to work long hours these days, so to maximise my productivity I need to be able to ignore the engine parts and concentrate on game production, in an environment I can assume that other people have almost certainly encountered all the problems in real world game production before me.

My evaluation process

I didn’t want to make a snap emotional decision, so I put a fairly large amount of time into this evaluation process. I figured that since this decision will affect the next several years, a few weeks on proper evaluation is time well spent.

My experience of actually shipping games over recent years has had the benefit of providing me me with a shopping list of things I need to know how to do. I had a Trello board of about 20 practical subject areas, each with 10-20 things on checklists inside. It included some really boring things, like “efficient localised text rendering with parameter substitution”; things that you don’t even think about when you’re imagining what being a gamedev is like.

My goal wasn’t to become an expert in UE4, but to take a horizontal slice of all the problems I needed to be able to solve. I went into enough practical depth (I made a ton of little prototypes) to have a strong grasp of the topology of each, without necessarily getting into all the deepest crannies. The devil is always in the detail, and there’s always a risk that you’ll be tripped up later by something too small to be on your radar during evaluation, but I was happy with the breadth & depth of what I managed to explore in the time.

I can’t put the full detail of my evaluation in this post, I’d be here all week. But I’ll try to tease out the main things which stood out to me, some of which are the main drivers for my decision, and some of which serve as caveats to consider if you’re going through the same thought process.

A caveat though: I may not know what I’m talking about. πŸ˜ƒ I haven’t shipped a game with UE4 yet, I’ve only done as much as I can within the time limit. In 4 more years maybe I’ll look back at this post and laugh at how little I knew. But all any of us can do is make calls based on the best information we have at the time.

The Major Evaluation Points

Let’s Talk About C++

Let’s start with what is, IMHO, the biggest downside of UE4 - the fact that if you want to write regular code, you have to do it in C++.

Before you yell at me, I’ve done my time in C++, squirt. I started working in C in 1990, and C++ from about 1995 through to 2010. I wrote engines in it. I defended it quite a lot. But I’ve also used a lot of other languages as well, so I think I have a pretty agnostic view of the pros/cons of different environments.

Unity’s use of C# makes it pretty friendly and approachable, even if you do have to be aware of a few more constraints and performance implications than if you’re, say, writing web applications. It’s far from ideal, and I find C# a bit “wordy” sometimes, but writing game code in it is pretty productive. Most game code doesn’t need to be particularly clever; simplicity and fast turnaround is more valuable than cleverness.

At the risk of controversy among game developers, my current view is that if you’re used to any other “modern” language, C++ is going to feel pretty bad to you. Stop writing that tweet at me, like I said I’m someone who wrote a shedload of C++ for a long time. I read all the Effective C++ books.

C++ is an extremely powerful language that affords you unprecedented control and expressiveness in an efficient runtime. It’s great at letting you build fast native code and controlling every nuance - although I won’t in this context say that it “avoids garbage collection” because in fact UE4 has its own GC for most of the main classes.

C++ is good for many things, including low level engine development. But we’re not doing that, we’re trying to write a game, and compared to the experience of more “modern” languages, I can’t help but roll my eyes at C++ sometimes. πŸ™„

C++ is finicky, slow to compile (in comparison, and in regular Hot Reload mode, see below), needs twice as many source files with lots of repetition (and pedantic consistency) between them, and is obtuse as hell with its error messages. The syntax is littered with symbolic noise which is simultaneously distracting and absolutely essential to get right. I wouldn’t quite describe it as a “user-hostile” language, but I would go as far as to describe it as “user-aloof”. C++ expects a certain amount of expertise and razor-sharp attention from you, and if you fall short, it has zero interest in helping you out. It’s the ‘git gud’ of programming languages. That does make it rewarding when you put the effort in to be an expert, no doubt.

I would have classed myself in that aspiring expert group a decade ago, but now I’ve no interest in being a language expert. I just want to make things as simply and productively as possible; C++ is not optimised for that. I would not call C++ a “productive” language for most above-engine-level game development. The fact that it’s the only “real” code (see Blueprints in the next section) you can write for UE4 is a negative mark on the engine in my book. If you’re grinding your teeth at that, fair enough - you’re entitled to your opinion too πŸ˜‰

With that taken as written, let’s talk about the extra nuances of writing C++ for UE4.

Dance of the Macros

There are a lot of macros / preprocessor symbols that you need to use. UE4 runs a preprocessor called UnrealHeaderTool over your code during build time, which expands all these into the boilerplate code you need to integrate with UE4.

It looks a bit like this:

UCLASS(config=Game)
class UMyCharacter : public ACharacter
{
	GENERATED_BODY()
protected:
	UPROPERTY(EditDefaultsOnly, Category = "Health")
	float MaxHealth;

	UFUNCTION(BlueprintPure, Category = "Health")
	FORCEINLINE float GetMaxHealth() const { return MaxHealth; }

	UFUNCTION(BlueprintCallable, Category = "Health")
	float TakeDamage(float DamageTaken, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override;

There are quite a lot of options you can use in those macros. This is not so bad if you use a tool like Resharper C++ or the upcoming Rider for Unreal Engine, which are both UE4-aware and will autocomplete them for you. Without these tools I found it pretty clunky, but then I’m used to using Rider with Unity.

It’s not so bad, but you can imagine that when you make a mistake, this codegen is yet another vector of confusion in the already deep quagmire of esoteric C++ errors.

DLL Heck

Your game is actually one or more DLLs that plug in to the editor / engine runtime. This is a pretty standard approach. However, this is all native code so it’s not as easy to reload into a running editor when you recompile. There are 2 ways UE4 has to deal with this: Hot Reload (default) and Live Coding (Experimental).

Hot Reload

The game DLL is typically locked by the editor process, so the Unreal build tool builds to a separate DLL called something like YourGame_1234.dll. The editor then detects this and switches over to that DLL so your changes are visible.

In my experience most changes work fine after this Hot Reload, including new classes and structural changes to those classes, although occasionally you have to restart the editor to pick some things up. It also means you end up with a lot of redundant DLLs in your build directory that you’ll want to tidy up periodically.

Live Coding

This is UE4’s integration of Live++. This iteration is much faster and doesn’t create all the DLL detritus, because Live++ is re-linking the compiled object files directly into memory. The turnaround time is really quite impressive but it has one major drawback: you can’t make any structural changes to your classes.

So you can only really use it when your headers are static, and you’re just iterating inside .cpp implementation files. You can’t even reliably change method signatures for example.

Personally after experimenting with both I found Hot Reload to be the most workable solution, but if you have a large codebase with most of the iteration going on in existing method implementations, Live Coding might work better. Certainly my Twitter feed can’t agree on which is the better option, with strong opinions in both directions. Pick which one matches your project I guess?

What’s not great about either is that both have caveats around how ‘sometimes’ you have to reload the editor to make things work properly after a C++ change. Experience might make this easier to judge, and people used to working with C++ engines will probably take this as a natural limitation, but when you come from Unity where hot reloading basically always works (in my experience), this uncertainty can be a bit disconcerting. It’s a natural result of the technology of course, but it’s still an unwelcome wrinkle.

Blueprints to the rescue

So, C++ is clunky, pedantic and less productive. That means I probably don’t want to use UE4, right? Well, 4 years ago that was definitely a big factor in my choice of Unity. The alternative is to use Blueprints, which are a visual coding system - and I used to have a very dim view of visual coding systems.

But - shock - as of May 2020, I’ve completely changed my mind and am embracing Blueprints (almost) fully. My previous concerns about visual coding still apply, but a combination of factors has mitigated my concerns, for our specific circumstances anyway. A lot of this is down to seeing my wife being happy to create node graphs in Maya, and my own recent experience of visual tools like the Amplify Shader Editor, before spending some weeks with Blueprints.

I figured the best way to talk about Blueprints for a crowd who probably have similar misgivings was to start with all the things that are bad about visual coding, and tell you why I’ve decided I can live with them. After that we can talk about some of the other benefits.

Problem 1: They’re quick to create but hard to unpick

I’ve experienced this first-hand; building something quickly in a visual coding system and realising too late that what I’ve made really hard to read later. And it gets worse if someone else built it.

This problem still exists, but is mitigated significantly by UE4’s specific implementation. You definitely can build awful sprawling monstrosities, but it actually gives you a lot of tools to help you not do that:

  • Support for local functions, and global function libraries
  • Local variables to avoid data spaghetti
  • Math Expression nodes so you don’t need a rats nest of nodes for y = a * pow(x, 2) + b * x + c
  • Named entry points (custom events)
  • Comments on both individual nodes and groups of nodes (that are visible when you zoom out)
  • Finding references across blueprints
  • Collapse unused pins, make things “pure” data (no execution pin)

I’ve found that if you’re careful about structure, comment things well, and refactor things into functions when they get too big, the resulting blueprints are not hard to follow. And if you realised those are the exact same things you do to make code better quality, you’d be right!

You can write good and bad visual code in the same way you can write good and bad text code. They’re just different.

Problem 2: You can’t diff / merge them

In fact, UE4 does have a blueprint diff / merge tool. However, it’s not always very easy to use, and even when I’d made the changes myself I found it not that easy to trace them. So this is slightly mitigated by the tools, but not that much.

The main mitigation for merging is locking: because Blueprints are stored in a binary format like all assets (see the next section), we enforce locking on them in our source control system (which has reverted to Subversion because of this). Only one person can edit them at once, so no merge problems. This works at our scale but would get more difficult the more people in the team who might need to edit things.

The mitigation for log diffs: even though I’m a source control nerd, the number of times I actually look at the diff of changes on game code now is…very low. In other projects I would use it most when reviewing other people’s code. Given that our team is so small,
in practice the number of times I actually look at logs is tiny compared to how much I used to do it on bigger teams. So diff tools have actually been a lot less important to us over the last few years. I would never have believed this 5 years ago when working in larger teams. But when there’s only 2 of you, the log is helpful from a “oh shit something broke let’s bisect until we find where” but not so much for picking through the diffs - you find the vast majority of your bugs by just looking at the latest.

When you’re used to working in larger teams, doing code review, merging multiple streams of dev, this blasΓ© attitude about log diffs probably sounds insane. It would have done to me too. But hey, when you work in different team setups with different kinds of assets (a lot of other game assets that can break things are binary too), sometimes your views change. Like I mentioned earlier, I think larger teams would have to use more C++ to mitigate these issues.

So yes, diffing and merging is a lot worse with Blueprints. But that just doesn’t matter to me as much as it used to. YMMV!

Problem 3: It’s slower than C++

Yep, it is. Blueprints run in a VM, so you can’t get away from that - well, there are options to compile BPs down to C++, called Blueprint Nativisation, but there’s caveats to that and I haven’t tried it.

But guess what? C# is slower than C++ too. So is Lua, GDScript, and lots of other things, but people ship games with them all the time. And C++ isn’t even the fastest - if you really cared about speed above all you’d be writing everything in assembler πŸ˜‰

Ultimately, how relatively fast something is doesn’t matter. All that matters is that the absolute speed it runs hits your performance targets for the game and its target platforms. Only a relatively small amount of your code is going to be critical for that, and the tolerance margins will vary depending on your project.

I know for example that I’m never going to be writing a AAA competitive FPS targetting 240Hz screens, so I have a little more wiggle room than some. I also know that there are plenty of much bigger projects than ours that heavily lean on Blueprints.

Besides, I know that if I need to squeeze a little more power out of a core segment, I can migrate it to C++. I won’t enjoy it, but I can do it. The best way to construct your projects if you like Blueprints seems to be to root everything in a thin C++ class, and add all the state there, but implement everything in Blueprints until you need to push something “down” to C++.

Problem 4: It can’t deal with complexity

If you start making very complex logic, even with all the function refactoring, Blueprints do become cumbersome. At that point, it’s time to push that code into C++. It’s not as nice to iterate with, but for complex core functionality (e.g. procedural geometry generation or something) it’s going to be the best solution. There are also a few things that you can’t do in Blueprints yet, although third party Blueprint Libraries can help with that, like Rama’s Victory Library.

By structuring your project around C++ base classes with Blueprints underneath, providing some core functionality in C++ is pretty trivial. Also if that C++ functionality is more general you can create a Blueprint Function Library with it, meaning you can use that code anywhere you want.

Having a strict C++ > Blueprint structure does mean you’re limited in how you construct your class hierarchy, you can’t go C++ > Blueprint > C++ for example. But, it turns out that deep hierarchies are generally a bad idea in UE4 anyway, particularly BP hierarchies, because of the way references are resolved. Most complexity is better built up via composition of components and general libraries; keeping your class hierarchies simple is good. I’ve preferred this approach in general dev for a while now so it wasn’t hard for me.

Problem 5: They’re hard to debug

This is an easy one: the UE4 blueprint debugger is really good. Breakpoints, stepping, watching variables, just like you would in code. No complaints.

Benefit 1: A ton of game code is really dumb

Now let’s talk about some of the positives.

The thing is, a large percentage of game code is pretty damn simple. If you assume that the really complex things like procgen and the underlying engine tech itself are all handled in C++, most of the logic you’re left writing for a game tends to be “query X, combine with Y, wait a bit, do Z”. It’s not rocket science.

So much Unity code I wrote was pretty low brow. Code to check a few conditions before firing up the next sequence. Basic number comparisons. Code to spin up a counter so I could tell whether a delay had happened yet (without using a coroutine). So much of it is really rudimentary stuff. The hard bit is finding the right combination of things that feels good.

Blueprints do these things really well. They’re not complex, and you can glance at the graph and immediately see where it might go. BPs also have a lot of shortcuts built in, such as:

  • Cancellable/resettable timers
  • Delays
  • Flip/flop switches to alternate between 2 states
  • Execute something only once regardless of how many times it’s hit, until reset

These are all things you can do in code, but they’re stupidly fiddly for such as simple concept. They’re one node in Blueprints, it’s better than what I could come up with in code.

Benefit 2: More role overlap

There’s only 2 of us in our little gamedev company, and so far our roles have been fairly separated. I write code, Marie does art.

Well, actually I’ll tinker a little bit in the art dept to try things out. Sometimes I’ll even make some simple assets. That’s because it’s helpful sometimes to be able to quickly try something, rather than having to interrupt someone else.

And I want that for Marie too. She’ll often have ideas for tweaks, and if it’s something only I can do in code, she has to wait for me. But, while code is a bit too much of a sheer cliff to tackle, she’s quite capable of understanding node logic. She once showed me a rig she set up in Maya for root motion control that had math/logic nodes doing everything and I said “Welp, you realise you’re basically writing code here, right?”. πŸ˜€

That, on top of my growing acceptance of node graphs for other things, convinced me to really examine my prejudice against visual coding. In a 2 person team it can’t just be about what works for me, what my background and preferences are. We’re a team, so if our joint productivity is improved by changing to something I’m a bit less familiar with, then so be it.

Benefit 3: Iteration is really fast

Iteration time in UE4 with C++ is…not great. Unless you’re using Live Coding (with all the caveats about never being able to change any class structures), the iteration time will definitely be slower than what you’re used to in Unity. Don’t at me about this, I’ve built similar sized projects with both. It may not seem that significant a lot of the time, but it compounds and accumulates. And sometimes it is significantly longer (like adding a new class). And if you say “but it’s only like 10 more seconds”, you clearly don’t understood what true productive iteration feels like.

Iteration time is critical to lots of projects, and games are one of them. So much is about tiny changes to how things feel, look, sound, flow - any slowdown in this process is awful for productivity.

And here’s the kicker: iterating in Blueprints is really fecking fast. Faster than a Unity C# change. Faster than almost anything I’ve used before; maybe Go gives it a strong fight (it’s optimised for build time, and its designers don’t get enough credit for that).

With Blueprints it’s just tweak, F7, play, BAM. Basically instant. It’s glorious.

Iteration time is so important, I can’t even express it fully without you seeing how much I’m waving my arms around right now. I don’t care how elegant your code is, how cleverly it’s all structured, if I can try 20 different tweaks in Blueprints in the time it takes you to do 3 builds, I win. That’s just science baby. πŸ˜‰

Conclusion: Blueprints are go

After weeks of using them, I really like Blueprints. Yes, there will be times when I’ll have to write C++, but apart from rooting all my classes there, I’ll be avoiding it whenever possible and writing Blueprints instead.

Now, this only really works because we’re a teeny tiny team. The larger the number of people writing logic in a game, the more likely you’re going to want to put most of that in C++ I think, because the ability to perform code review, merge parallel changes, enforce more structured design etc becomes increasingly important. For our scale majoring on Blueprints seems fine though.

Assets / Content

Another area that UE4 differs quite a lot from Unity is how it stores assets; basically any resources you need to reference in your project (meshes, materials, textures, sounds, animations etc). On the surface things look very similar; Unity has an Assets folder, and UE4 has a Content folder - everything you use in your game has to be somewhere underneath.

However, what differs most is how this data is primarily stored for use. When you use any assets in an engine, you typically have to import them. This pre-processes the asset in some way, often with some user-specified preferences, so that it’s ready for use in the game.

In Unity, the primary storage of the asset remains in whatever file format you exported from your content creation tool, such as .png, .wav, .fbx and so on, and Unity imports the data into a local asset cache (not stored directly in your project). Any settings for this import process are stored in .meta files, which most people configure to be text. This means for the simplest setup you just have the ‘normal’ exported file format and a .meta file in Assets.

In UE4, all assets, regardless of type, are stored in binary .uasset files. This includes all the data required for the asset, and the settings used to create it. Import from exported files (.png etc) located in the Content folder is the easiest way, since new and modified files are refreshed automatically, but you can import from other locations. The important thing is once the import has occurred, all you need is in the .uasset file, and any export file it originated from (.png, .fbx etc) is redundant - assuming that you have some original file outside the Content folder (e.g. a Blender or Maya file) that you exported it from.

This has a number of ramifications:

1. Import setting changes are binary

Changing import settings on an asset is a binary change in UE4 that can cause merge conflicts. Remember, in Unity if you only changed import settings, it’s usually a text change in .meta which is very mergeable.

So in UE4 you have to be a little more careful and ensure that you don’t have 2 people altering the same uasset, even if one person only changed a minor import setting rather than the actual content.

This, along with the fact that I intend to use Blueprints as much as possible, prompted me to start using Subversion instead of Git + LFS, since UE4 supports automatically locking files on edit, making accidental unmergeable changes far less likely.

2. Import times are better

Because all assets are stored post-import, everyone getting an updated version already has all the pre-processing done. In Unity you can use a cache server to share post-import assets, but it’s a lot more faff.

Therefore doing a big update or branch switch with a lot of asset changes is generally a lot faster. Although the shader compile step is still done locally which can take a little time.

3. Export files in Content should be excluded from source control

It’s most convenient to export your .fbx, .png etc files into Content so UE4 will auto-import them, however they’re duplicate content. So really you want to add all export formats in Content to the ignore list of your source control system.

I’ve written a setup script that does all this for a new UE4 Subversion repo.

On the whole, there’s pros and cons to UE4’s approach vs Unity’s. I’d say it’s mostly a wash; faster asset updates due to the single import step, but I do have to use Subversion again now really, due to locking needs on more things. 😐

But the flipside to that is that Git’s push/pull has always been confusing to Marie, and the distributed aspects have never had any real benefits in such a small team. So I’ll curse about the tooling sometimes, but it’s probably a better fit for this team overall.

To Be Continued

I knew this was going to be a long post, but it’s exceeded even my expectations. I still have a lot of feature points to talk about, but I’ll save that for another post.

In part 2 I’ll talk about a few more specifics I like in UE4, including:

  • The UE4 Game Framework
  • Networking
  • AI
  • Materials
  • Animation

I hope this has been useful so far!