Casting explained?

Hi there,

I was hoping someone could explain or point me to an explanation of ‘casting’. I’ve only found these docs so far:

From what I gather, you’d cast on to another object to get control of it. Is that right? What’s the real power behind this rather than using a custom event?

Thanks,
John

well you cast to also call a function or to find out what pawn a controller it controlling as an example.

lets say you needed to know the health of the controller you would cast to controller->getpawn and then you could cast to that pawn to get its health.

A really good way i had this explained to me was to think of casting as “treat as”.

Let’s say you have made a player pawn blueprint that has some special functionality. If you want to call a function (or get/set a variable) on your pawn from another blueprint you can use the generic “get pawn” function. You can interact with that pawn reference in a very general way (get location, get rotation, etc…), but you can’t set any of the custom stuff you’ve set up in there. This is where you use casting.

Cast to My_Special_Pawn (or as i was saying, treat as My_Special_Pawn). When you cast to a specific class, you can now make the assumption that this object is exactly what you expect it to be. This is why you see the “fail” output on the cast node. It might fail the cast (It says- actually, I’m not your special pawn- you can’t treat me that way!)

On the other hand- If it passes the cast, it says “that’s me! Now you can treat me as your special pawn and call my functions!”

Hopefully that makes a bit of sense?

Let me know!

-nick

7 Likes

Building on what Nick said, the idea of casting basically comes from the world of programming. Without getting too much into programmer town, the basic gist is that blueprints and actors can be parented off of one another, which leads to separate, different blueprints that have some things in common.

A simple way to learn the concept might be with an example. Pretend you make a blueprint that represents a generic animal. Inside the blueprint, you implement some basic functionality that all animals have in common. For this example, pretend all animals have to eat and you make a function called “Eat.” Now, later on, you want to make a blueprint for a dog. A dog is an animal, so you make the dog blueprint be a child of the animal blueprint. This makes it so that the dog has gained all of the things you implemented in the animal blueprint, but also allows you to add some new things or to change things around (pretend the dog eats in a different way from the generic animal and we want to change what “Eat” does…we can do that). Likewise, now that we have a dog, pretend we want to make a blueprint for a particular breed of dog, like a Golden Retriever. Well, a Golden Retriever is a dog, so it makes sense to make the new Golden Retriever blueprint a child of the Dog blueprint, which itself was already a child of the Animal blueprint. We could continue to do this with many, many different animals, dogs, etc. At this point, we might have a simple hierarchy like this:

Ok, so that’s great, but how does that explain why it’s useful, or what casting is? Well first, the powerful part is that all of those things in the hierarchy share whatever was added in their parents. So if we added that “Eat” function to Animal, every child animal we add also can eat. They might eat differently (so their blueprint would change the behavior a little bit), but we are guaranteed that every animal can eat, which lets us do some powerful things. Continuing our silly example, in this case it means if we had a blueprint that was representing a zoo (it holds an array of Animals), it could call the Eat function on each Animal in its array of Animals without ever knowing a single detail about any one individual animal. It doesn’t matter that the array actually holds one tiger, an elephant, a bear, etc. We can just go through each element in the array and tell it to Eat, because we know all animals should eat and that each animal knows what that means to them.

So where does casting come in? Well, if we’re storing all of our variables just as simple Animals to enable this powerful behavior, it means at first glance we’ve lost access to specific features of particular animals. Let’s say when we made our Dog blueprint, we added another function to it called PlayFetch, because we wanted all of our dogs to know how to play fetch. Animals in general don’t know how to play fetch, but dogs do. However, in our zoo example, we only know we have animals, not if any of them are dogs…so how do we make them PlayFetch?! This is where the cast comes in. On each animal, we can attempt to cast it to a dog. In essence, we are asking the animal, “Are you a dog?!” If the answer is yes, then you are given back the same variable, but very specifically as a dog this time, which allows you to call the PlayFetch function if you want. If the answer is no (you asked a cat if he was a dog!), then the cast “fails” and you’re returned nothing, because a cat is decidedly not a dog!

13 Likes

That is a fantastic pair of explanations! Thanks guys. :slight_smile:

I’m a little lost on the whole “Make it a child” part of these explanations. How would I identify a blueprint that is a Child of another blueprint?

He wasn’t referring to ‘child’ in the sense of parenting in the game engine. He was referring to the fact that you would cast a class higher in the hierarchy to a class lower in the same hierarchy (the child).

I sometimes find it easier to understand with an example:

I have a vehicle that I have custom built by making a new BP using the pawn option. I named the BP ‘MoonRover’ because that’s a cool name, whether the game is on the moon or not.
Now, I want to be able to drop instances of ‘MoonRover’ all over and have the player be able to enter each one without having to specify each instance in my level blueprint.
So, I add a trigger box to the blueprint and have it overlap just pawns (to see if a player is near).
Now I can easily have a small block in my level blueprint just get overlapping actors, and filter by my “MoonRover” class.
However, this will return the overlapping actor as, well, an ACTOR. We can’t possess an actor, we can only possess a pawn.
So, I now would take the result of my overlapping actors array, grab the 1st element (which will be the ACTOR that is the instance of my moon rover), and CAST it to a PAWN.
I could then call the possess function to transfer my playercontroller to the moon rover, since it is now treated as a PAWN.
To take it further, if I wanted to activate an action specific to my “MoonRover” BP, I could CAST the moon rover’s PAWN reference to a “MoonRover” type. Then I’d be able to treat it as the BP I created and access things that would not be available in a simple PAWN instance, or a simpler ACTOR instance.

The “failed” exec pin comes into play if, for example, you had a trigger for opening a door and your ‘get overlapping actors’ pulled back the door instance. The door is an actor, but isn’t a pawn, so the ‘cast to pawn’ would fail and you could ignore or act or act on that failure. In this case you’d probably just ignore it, but you could use the ‘failed’ logic in other instances to tell the player they are trying to enter the wrong vehicle or something like that.

Hope that helps on some level,

You can actually tell this when you’re viewing the property window for a particular blueprint (or at the time your create a blueprint). So as an example, pretend you make a brand-new blueprint. You’ll see a dialog like this:


Notice the title bar says, “Pick Parent Class.” Whichever choice you make there would be the “parent” and your blueprint would be the “child.” If you clicked actor, your new blueprint gains all the functionality of Actor (which is written in C++ code) and then in the blueprint you can interact with or override that functionality. If you’re looking at a pre-made blueprint, you can check out which class or blueprint was its parent in the upper-right corner of the property window:


For my example, when I clicked new blueprint, I would have picked actor and made a new blueprint called “Animal.” Now if I want to make a “Dog,” that is a child of “Animal,” I simply right-click on my “Animal” blueprint and select “Create blueprint based on this” from the context menu:


This will make a new blueprint that has a parent of “Animal,” meaning my new blueprint would inherit any special behavior I added inside the “Animal” blueprint. One handy way to distinguish whether a parent of a blueprint is C++ code or another blueprint is when you look at the name of the parent, if it ends in “_C,” that means the parent is a blueprint. As you can see in this example, the “Dog” blueprint is a child of “Animal,” which is a blueprint, because it ends in “_C.”

2 Likes

Thank you so much Billy and Nick! Didn’t even know about making a child blueprint off of a an existing parent. That’s great info!

For my simple mind, the word cast was the thing causing most of the confusion. :slight_smile:

I was imagining something along the lines of a wizard casting a spell on something, in other words, whatever event I was calling was going to affect the thing I cast to. Obviously, that’s not correct. In fact, much as Nick Donaldson mentioned, it’s treating it as something else. You’re casting a character in a play. “I’m not actually a doctor, but I play one in this blueprint” sort of thing.

Really good explanations above. Hope I didn’t add to anyone’s confusion, but the meaning of the word ‘cast’ was the ah ha moment for me.

This is my take.

It’s all about c++ types and how the computer lays out objects sequencially in memory.

YourCustomGameMode is 100% identical to AGameModeBase in memory, before you added your new stuff. Just beyond that limit in memory is your stuff.

A pointer in C++ contains information about the object type it can point to, and its memory address. an AActor-pointer can point to the right place of an ACharacter object. But you can only access its AActor-part. But it’s the right place in memory.

Epic Games defined GetGameMode to deliver the memory address to an AGameModeBase object. Because your GameMode is based on AGameModeBase, it can point to the right place in memory, because that portion fits the definition completely. But you can’t access your new stuff through that pointer, because it is only allowed to access the specific memory layout of AGameModeBase.

Casting is a just a process of saying, “Look beyond the limits of this object in memory, and see if it fits with the new stuff”. If it does, you can use that part. Where your stuff is. Or where ACharacters stuff is beyond APawn.

I think of it more in terms of Casting Molds you use to cast iron. You’re taking the object you are getting and trying to fit it into another mold.

1 Like

Casting is for looking at or changing variables or firing events in another actor.
You can cast to a specific actor or an arbitrary actor, but it’s important to know how you are finding that reference. Whether you use a linetrace, getAllActorsOfX node, make an unset actor variable to eyedrop the scene, or whatever. Depending on your usage, there’s only one good way to get that reference to cast to.
In a projectile shooter game, you could build multiple guns with varying damage numbers, and only need one bullet asset. The gun actor would spawn a bullet, then cast to that bullet and set damage variable. That bullet would collide with another actor, cast to collided actor and get health, subtract damage, and set health. and


edit: 30 jun 2021. edited for health.

If you were planning to cast to bullet, then bullet cast to hit actor to apply damage: instead, forget about casting and use an interface . Casting to any actor will force the casting actor to hold a hard reference to that actor. It can become a detriment to even small projects. I’ve had projects load 1 actor, and that actor being the start of a web of pretty much every asset in the project, so loading the one actor means loading every actor. Forget loading the game in a start menu, load the entire game and every level and every asset. Your computer will hate you, your users will hate you.
Use the reference viewer to see what all your actors have a hard reference to. There should not be any spiderwebbing going on. With an exception of maybe a handful of UI elements to eachother, the gamemode to the player controller, the level bp to the gamemode.
Your gun actor should interface to your bullet projectile, the projectile should interface to its hit target. That way any number of bullet actors can be referenced generically, and all hit actors by any bullet can be referenced generically. Your actors won’t have any hard references to any other actor.

4 Likes

im a bit confused when casting to something…trying to use the animal scenario above…if im performing some action in a giraffe and for some reason i need to tell a dog to play catch…do i cast directly to the dog, or should i first cast to animal followed by a cast to dog?

what if im in some other unrelated heirarchy, like say a car…do i need to go to the top of the heirarchy and cast down?

also, if i have casted to a dog am i then “in” the dog? so if i want to then do something with the giraffe (or the original actor i was making code in before the cast) do i have to cast back again?

Perhaps instead of getting confused about how things are done it would be better to understand why Casting is even a thing.

An object reference variable* (lets call it AnimalRef), has a Type (eg. Animal) and its job is to point at a memory address of the type Animal. However initially it points at nothing which isn’t very useful so you Spawn a Dog and set the object reference “AnimalRef” to point at your Dog. This is possible because Dog Is-A Animal.

Now when you use AnimalRef (which only you for a fact know is actually also a Dog) and try to call the Dog function “PlayCatch” it won’t work because AnimalRef is of Type Animal and Animal Is-Not-A Dog.
Now since you already know AnimalRef points at a Dog reference you can Down-Cast Animal to a Dog and “PlayCatch” will work fine.

Why would you even want to save the Dog reference in an Animal Type reference and not a Dog Type reference straight away and avoid having to Down-Cast just to call "PlayCatch you might ask.
There is two reasons one being Inheritance and the other being memory management.

Lets say you have another class called Veterinarian and the Veterinarian wants to heal any Animal by simply calling a heal function on AnimalRef
In the Animal class you would create a function called Heal and because the Dog Is-A Animal the Dog can now be healed.

The Veterinarian can now set its AnimalRef of Type Animal to point at the Dog and without casting to Dog the Veterinarian can call Animal-Heal on the Dog because the dog inherited the Heal function from its parent.

Now why is it important for the Veterinarian to only know about Animals and not about Dogs specifically? This is where memory management comes in. Lets say you have a lot of different Animals. Cats,Dogs,Hamster,Tigers,Snakes etc. and the Veterinarian started casting to each individual type of Animal just to heal them then as soon as you add a Veterinarian to the level every single type of Animal has to be loaded. Every time you make a Cast you create what is known as a “hard reference”. A hard reference dictates that whatever it is you are casting to now has to be loaded.

Another way of “decoupling” (avoiding hard references) is to use Interfaces. If the dog implemented a DogInterface and this interface had a function called “PlayCatch” then the Dog could implement the DogInterface and the Veterinarian could send a DogInterface"PlayCatch" message on the AnimalRef and it would work fine. The Dog would only be loaded if a Dog exists in the level.

The simple answer to your question, if you should first Cast to Animal before Casting to Dog is no. The Dog Is-A Animal so if you Cast to Dog you can do both Animal and Dog functions, my long explanation above should help you understand why you might want to avoid Casting to Dog if it is unnecessary.

*Blueprint Object references are actually called Pointers in C++

2 Likes

Basically to me , there may be events or variables or functions or something in other blueprints that you cannot access in a current blueprint. But if you cast to (say your character bp) , you can then come out of the “as character” pin and now bring those previous mentioned variables or events or functions from your character bp into the current bp.

  1. You do Up-Casting all the time without noticing. Up-casting implicitly happens when you pass a parameter to a function that doesn’t need the specific Type. Eg. the Possess function on the Controller class needs a Pawn type to Possess. If you instead give it a Character Type it still works but the Character gets Up-Casted to a Pawn since that is all the Function needs.
  2. They reside at root level (Actor level) since the function is part of Actor.
  3. Not sure I understand this question. Any pointer has a Type starting with Object and while casting in Blueprint, checks are made at run-time if the pointer IsA MyWidget etc. If it is then it is Valid.
  4. Blueprints actually have a kind of multiple inheritance. Interfaces are implemented as a 2nd inheritance. Multiple inheritance is risky business and therefore Blueprint only allow inheritance that can’t clash like one Actor and Interfaces.
  1. It is an inheritance thing. With the Dog examle the Dog is not an entirely new object it is an Animal Object with an extension of Dog. When you call the Heal function it resides in the Animal part of the dog, and when you call PlayCatch it resides in the Dog part of the Dog object.
  2. A reference can be inspected 2 ways. One way is to look at its type and the type of a variable can never change. The other way to look at a reference which is what the Cast node uses is what is the memory address of this object. A memory address is just a simple number which is why it is so cheap to pass around Object references. With the memory address it is possible to check if that piece of memory contains the Type you specified. When Casting a reference the memory address doesn’t change only the Type changes.

This is why the notion of Cast is often “Treat as” because the address of the Dog the reference points to never changes only how you “treat” the address (the Type) changes.

2 Likes

yes, im fine with class heirarchy principles, maybe the problems are that i dont fully understand ue’s inbuilt class heirarchy and i often get errors casting to internal objects, especially the pawn, actor, player, character and controller setup…so i have to cast around until i get it right.

i did have some issues again today, so it would be good to know. if i am writing code in A and i cast to B to do something, am i needing to cast back to A before i can continue to interact with A. i did some tests and my conclusion was indeterminite.