Unity vs. Unreal: Deciding the Best Fit for My Next Game

Posted on

Starting out in game development, one is immediately confronted with the choice of an engine. While there are many options out there, such as Godot, MonoGame, Game Maker, and CryEngine, the two giants of the industry are Unity and Unreal Engine.

So many game engines to choose from
So many game engines to choose from

Unity was my first choice for game development, and I had fun creating my debut game with it. However, the allure of Unreal Engine’s impressive graphics proved too tempting to ignore. Some suggested I stick with Unity, but I ventured into Unreal territory out of sheer curiosity. Though I’m still finding my footing in both, I’d like to share my early observations on each engine.

Similarities

Plenty of great titles have been built on both engines. Unity has some good ones like Rust and Cuphead, while Unreal has an entire wiki page to track all the major releases using the engine.

Gameplay from Cuphead (Unity) and Ark (Unreal)
Gameplay from Cuphead (Unity) and Ark (Unreal)

It’s all the same concepts too, although they may be dressed up a bit differently. Both are object oriented and allow you to build up games by adding “components” to “game objects”. Both have concepts like vectors, rotations, meshes, rigid bodies, collisions, colliders, etc. Both have similar interfaces, although I like Unreal’s a little bit more. Both can develop games for almost any platform, and when one engine releases a new feature, you can bet the other will soon follow.

Differences

Of course, two engines built to do the same thing are going to have a ton of similarities, but what about differences? Some of the biggest differences I noticed are as follow.

C# vs C++

C# is the language Unity uses, and wow, does it offer a better developer experience! It’s significantly easier to read, write, and learn. It’s loaded with ‘nice-to-have’ features and makes programming a breeze. The same can’t be said about C++ which is archaic, ugly, and verbose, but oh-so performant, which is probably why they chose it to begin with.

Let’s take a look at some example class code from both languages/engines.

using System;
using UnityEngine;

public class ExampleClass : MonoBehaviour {
  [SerializeField] float Speed = 10f;

  void Start() {
    Debug.Log("ExampleClass Started!")
  }

  void Update() {
    Debug.Log("This gets called every frame!")
  }

  void OnCollisionEnter2D(Collision2D collision) {
    if (collision.gameObject.CompareTag("Kills")) {
      Debug.Log("You hit something that kills you!")
    }
  }
}

Above is your typical Unity C# class, it’s Clean, simple, and easy to read.

Now let’s take a look at the Unreal C++ equivalent. First we have to define the shape of our class in a seperate header file.

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "ExampleClass.generated.h"

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class PLATFORMER_API UExampleClass : public UActorComponent
{
	GENERATED_BODY()

public:	
	UExampleClass();

protected:
	virtual void BeginPlay() override;

public:	
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

private:
	UPROPERTY(EditAnywhere)
	float Speed = 10;

	UFUNCTION()
	void OnHit(
		UPrimitiveComponent* HitComponent,
		AActor* OtherActor,
		UPrimitiveComponent* OtherComp,
		FVector NormalImpulse,
		const FHitResult& Hit
	);
};

Once we have that we can create the actual class.

#include "ExampleClass.h"

UExampleClass::UExampleClass()
{
  // Constructor method where we can change settings
	PrimaryComponentTick.bCanEverTick = true;
}

void UExampleClass::BeginPlay()
{
  Super::BeginPlay();
  
  UE_LOG(LogTemp, Display, TEXT("Example class started!"));
  
  // Get the child mesh
  UStaticMeshComponent* StaticMeshComponent = FindComponentByClass<UStaticMeshComponent>();

  // Point the OnComponentHit event to our onHit function
  if (StaticMeshComponent != nullptr)
  {
    StaticMeshComponent->OnComponentHit.AddDynamic(this, &ASimpleEnemy::OnHit);
  } 
}


void UExampleClass::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
  Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

  UE_LOG(LogTemp, Display, TEXT("This gets called every frame!"));
}

void AExample::OnHit(
  UPrimitiveComponent* HitComponent,
  AActor* OtherActor,
  UPrimitiveComponent* OtherComp,
  FVector NormalImpulse,
  const FHitResult& Hit
)
{
  // Check that we're hitting what we're looking for
  if (OtherActor && OtherActor != this && OtherComp)
  {
    APlatformerCharacter* PlayerCharacter = Cast<APlatformerCharacter>(OtherActor);

    if (PlayerCharacter)
    {
      UE_LOG(LogTemp, Error, TEXT("You hit something that kills you!"));
    }
  }
}

Both examples essentially do the same thing, you tell me which you prefer.

Graphics

Let’s be honest, games developed in Unreal often showcase superior graphics. While both engines can produce visually appealing games, I’ve yet to encounter a popular 3D Unity game that rivals the graphical prowess of its Unreal counterparts.

Unreal comes with extensive post-processing capabilities out of the box, making everything look great with minimal effort. One particular feature that stands out is the Lumen lighting system. There were instances when I added assets to a scene and was initially unimpressed. However, I was stunned by their transformation once the lighting was enabled.

Lumen lighting off and on
Lumen lighting off and on

IDEs and compiling

Unreal projects are notably larger in size, which can cause IDEs to lag. Even Visual Studio Code, known for its lightweight design, didn’t perform optimally, it was completely bogged down trying to intellesense the project. The only IDE that offered a relatively decent performance for me was JetBrains Rider. However, it’s accompanied by a significant cost, priced at $150 a year.

Unity worked well with every IDE I tried, be it Visual Studio, Visual Studio Code, or Rider, they all worked smoothly.

While on the topic, let’s discuss compile times. This is another domain where Unity outpaces Unreal, being significantly faster. When using Unreal I find myself waiting a good 10-20 seconds every time I made a change, and this is with their live coding feature, a full recompile would take upwards of 30 seconds. My computer is not bad, but in this moment I definitely felt like I needed better hardware. I also found that I had to restart the engine sometimes for updates to appear.

The asset store

The Unreal Asset Store outshines Unity’s in many aspects. It boasts a plethora of free assets and even offers limited-time freebies every month. Many of the assets on the Unreal Asset Store appear as if they’ve been lifted straight from a AAA game.

Unreal asset store cars (free) vs. Unity asset store cars ($60)
Unreal asset store cars (free) vs. Unity asset store cars ($60)

Character controllers

Right out of the gate, Unreal sets the stage by providing a robust character controller. It’s quite flexible, allowing you to build upon it and mold it into what you need without breaking much of a sweat. Unity leaves much to be desired in this department, their CharacterController component feels like a minefield of issues, in Unity I write everything from scratch.

Resources

Both engines have thriving communities, but it’s definitely a lot easier to find high-quality free Unity courses and tutorials. I really couldn’t find anything free I felt confident in for Unreal, so I ended up purchasing a course from Udemy. Unity also appears more popular among indie and hobbyist developers, making online assistance easier to find. Nonetheless, both are sufficient.

What will my next game use?

I’ve decided to focus on Unity for the foreseeable future. Unreal has some impressive graphical capabilities, but with Unity I feel like I’ll be able to focus more on actual game development. With Unreal I could see C++ and compile times being a huge time sink. However, once I gain more experience in game development, I’d like to revisit Unreal and delve deeper into its features.