A few weeks back we looked at soft vs hard references and how a single hard reference can quietly drag half your project into memory. Casting is the most common way beginners create those references without noticing. Drop a Cast To BP_Door in your player Blueprint and you've just told the engine: whenever the player loads, load BP_Door too — and everything BP_Door touches. Do that a dozen times and your "small" player class pulls in a tree of meshes, sounds, and particle systems you never asked for.
Interfaces are the fix. This is the practical version: what casting really does, when it's fine, and how to replace the bad cases.
What a Cast actually does
A Cast To node takes a generic reference — like Other Actor from an overlap — and asks: "is this specifically a BP_Door?" If yes, you get a typed reference and can call BP_Door's functions and read its variables. If no, the cast fails and the failed exec pin fires.
That part is genuinely useful. The hidden cost is the dependency it creates.
Why casting to Blueprints costs memory
When your Blueprint contains a Cast To BP_Door, the editor records a hard reference from your Blueprint to BP_Door. Unreal loads dependencies before the asset that needs them, so the moment your Blueprint loads, BP_Door loads too — plus BP_Door's references, and theirs, all the way down.
Casting to one Blueprint isn't a disaster. The problem is the chain: player casts to BP_Door, BP_Door casts to BP_KeyItem, BP_KeyItem references three meshes and a sound. Now loading the player pulls all of it. Right-click an asset and open Reference Viewer, or use Size Map, to see what your class actually drags in.
When casting is totally fine
Casting isn't evil. Casting to native (C++) classes — APawn, ACharacter, APlayerController, or your own C++ classes — creates no asset hard reference, because those aren't uassets. Casting is also fine when the target is already loaded anyway: casting the overlapping actor that's already sitting in your level costs nothing extra in memory; at that point it's just a type check.
Rule of thumb: cast to native classes freely. Be careful casting to Blueprint assets, especially from classes that load early — Player, GameMode, GameInstance, HUD.
What an Interface is
A Blueprint Interface is a contract: a list of function names with no implementation. You create it (right-click → Blueprint → Blueprint Interface), add functions like Interact or Take Damage, then any Blueprint can implement it via Class Settings → Interfaces.
The key property: calling an interface function doesn't require knowing the concrete class. Your player can call Interact on whatever it's looking at without ever referencing BP_Door. No cast, no hard reference.
How to call an Interface
You call through the Message node — e.g. Interact (Message). Drag off any Actor reference, search the function name, pick the entry marked (Message). If the target implements the interface, it runs. If it doesn't, nothing happens — no crash, no failed pin to handle. That silence is the feature: a button, a chest, and an NPC can all answer the same Interact call, and a wall just ignores it.
When you actually need to branch on "does this thing support it", use Does Implement Interface before calling.
A quick refactor
The casting version of "press E to interact":
CB0
Three casts, three hard references, and it breaks the moment you add a fourth interactable. The interface version:
CB1
One node. Every interactable implements Interact its own way. Adding a fifth type needs zero changes to the player.
Common pitfalls
- Interface functions with return values can't be Events. If your interface function has an output, the implementing Blueprint must add it as a Function (it shows up in My Blueprint to override). Only output-less functions can be implemented as Events. This trips up everyone once.
- Calling the non-Message version. The plain call assumes the object implements the interface and can error if it doesn't. Use the (Message) variant unless you've already checked.
- Interfacing everything. Interfaces add indirection. For a one-off call to a class you already hard-reference for other reasons, a plain cast is simpler. Don't dogmatically rip out every cast.
- Forgetting to actually add the interface. Implementing means Class Settings → Interfaces → Add. Just matching the function name isn't enough — the Message call will silently do nothing.
30-second recap
- Casting to a Blueprint asset creates a hard reference — that asset and its tree load whenever your class loads.
- Casting to native C++ classes is free; casting an already-loaded actor is just a type check.
- Interfaces let you call functions without referencing the concrete class — no hard reference.
- Call via the (Message) node; it does nothing if the target doesn't implement the interface.
- Functions with return values must be implemented as Functions, not Events.
- Use Reference Viewer and Size Map to find what your casts are dragging in.
Next up: Event Dispatchers — the other half of clean Blueprint communication, for when the caller shouldn't even know who's listening.
— Marco
Comments
Leave a comment