Unity Engine - Foundation to Mastery
From your first line of C# to an official Unity certification
107 lessons·486 min·$153.60
Pathways in design, games and film — pick yours and start today
From your first line of C# to an official Unity certification
107 lessons·486 min·$153.60
Three specialisations in one course: modelling, sculpting and environments
50 lessons·279 min·$108.61
Whatever your game idea is — you will build it and ship it from scratch
61 lessons·296 min·$193.94
Learn from a AAA environment artist by mastering modular building kits and trim sheets
Starts 16 September·$231.18
From the idea to a complete short film — with Higgsfield
Starts 16 September·$77.58
Work and conversations the team picked, and what your classmates reacted to this fortnight
Nothing highlighted yet — the first project you post could be here
When you scale an object with S you are not changing the mesh. You are writing a number on the object that says "draw this at twice the size".…
When you scale an object with S you are not changing the mesh. You are writing a number on the object that says "draw this at twice the size". Blender respects that number; an engine sometimes does not. The familiar result is a model that looks correct in Blender and arrives in Unity or Unreal at double size, or with a physics collider that does not match what the eye sees.
The damage starts before export, too. Bevel measures its width in object units, so a non-uniform scale like (1, 1, 0.4) gives you a thick edge on one axis and a thin one on another. Solidify and cloth simulation behave the same way.
The habit: before exporting, and before any modifier that depends on distance, select the object and press Object ▸ Apply ▸ Scale, or Ctrl+A ▸ Scale. Then check the item panel with N — scale should read 1.0 on all three axes.
A reference in Unreal has three states, not two: null, valid, and destroyed-but-still-held. Comparing != None only separates the first from the other…
A reference in Unreal has three states, not two: null, valid, and destroyed-but-still-held. Comparing != None only separates the first from the other two, so the wrong branch runs for an enemy that had Destroy Actor called on it a moment ago, and the crash arrives inside the next function rather than where the mistake is.
The IsValid node checks both conditions at once, and it is a single node with two execution outputs, which replaces the hand-rolled branch entirely. In C++ it is the same call: if (IsValid(Target)), not if (Target != nullptr).
The habit worth fixing: any reference you store in a variable across frames — the current target, the last checkpoint, the vehicle you were driving — gets an IsValid check at every use, not at assignment. The moment you stored the reference says nothing about the moment you read it.
Profiler numbers taken inside the editor are not your game's numbers. The editor runs its own loop, loads assets uncompressed, and allocates memory…
Profiler numbers taken inside the editor are not your game's numbers. The editor runs its own loop, loads assets uncompressed, and allocates memory for its own tooling, so the graph shows spikes that vanish entirely in a real build — and a whole evening goes into chasing a cost that does not exist.
The right way: File ▸ Build Settings, tick Development Build and Autoconnect Profiler, build to the device the game will actually be played on, and attach the Profiler to the running build.
Before reading any number, open the GC Alloc column and sort by it. Per-frame allocation — a string assembled inside Update, or Physics.RaycastAll returning a fresh array — does not show up as steady slowness. It shows up as a hitch every few seconds when the garbage collector runs, and that hitch is what a player complains about, not your average frame rate.
By default every .cs file in your project lands in one enormous assembly called Assembly-CSharp. Editing any line recompiles all of it, and as the…
By default every .cs file in your project lands in one enormous assembly called Assembly-CSharp. Editing any line recompiles all of it, and as the project grows, changing a single number turns into a twenty-second wait before you can press play again.
The fix: Assets ▸ Create ▸ Assembly Definition inside each major system folder — movement, UI, saving, AI — then declare what each one needs in Assembly Definition References. After that, a change to the UI compiles the UI.
There is a benefit better than the speed. Having to declare those references makes your dependencies visible: if you find that the movement system needs a reference to the main-menu assembly, the compiler has just shown you an architectural mistake that was hiding behind a casual using. Start with two or three boundaries rather than ten — over-splitting trades a waiting problem for a references problem.
The Cast To node is convenient, and it quietly does two things. First it creates a hard reference to the class you cast to, so that class — and every…
The Cast To node is convenient, and it quietly does two things. First it creates a hard reference to the class you cast to, so that class — and every material, mesh and sound it references — loads the moment the Blueprint holding the node loads. One door that casts to BP_PlayerCharacter is enough to drag the whole character into the memory of your main menu.
Second, the failure is silent for every other class. You write a door that opens for the player, then the AI companion or the destructible variant walks into it and nothing happens, with no error anywhere.
Instead: Content Browser ▸ Blueprints ▸ Blueprint Interface. Declare a function like Interact or CanOpenDoor, then send that message straight to the actor rather than casting. Whoever implements the interface responds; whoever does not, ignores it. The door knows nothing about the player, and your level's memory footprint stays the size of your level.
The modifier stack evaluates top to bottom, and each modifier's result is the next one's input. That makes Mirror above Subdivision Surface and Bevel…
The modifier stack evaluates top to bottom, and each modifier's result is the next one's input. That makes Mirror above Subdivision Surface and Bevel a rule rather than a preference: drop the mirror below the subdivision and you are smoothing one half and then reflecting it, which prints a visible seam down the middle of the model no matter how carefully you place the vertices.
The order that works for most hard-surface models is Mirror ▸ Bevel ▸ Subdivision Surface, with Clipping enabled on the mirror so vertices weld at the plane instead of crossing it.
Where: Properties ▸ Modifier Properties (the wrench) ▸ Add Modifier, then drag by the six-dot handle or press Ctrl+Page Up to move a modifier up the stack. And before any Bevel, apply the scale with Ctrl+A ▸ Scale, or the edge width comes out different on each axis.