Referencing a BP class (Actor) in C++

Hi All,

First post here hopefully I don’t mess this up, any help would be greatly appreciated!

I’m really struggling with how I should properly reference a BP Actor class I’ve created, here is the situation.

I have an Air Hockey game I’m practising on and I have created a BP class derived from the Actor class, this BP class houses the 'Puck" for the game. I had also created a “Striker” (The thing to hit the puck) as a BP class derived from the Actor class. Within BP the Striker would look for all classes of type “Puck” and update the position, and this works as expected. However, because this is happening on every tick I thought I’d try to place it into a CPP function instead to make it more efficient.

This is where the problems began, I started by recreating the Striker & Puck classes into custom CPP classes derived from Actor. Then in editor, I create a BP derived class from the CPP classes.
In the Striker.CPP I need to be able to reference the Puck, so it can get its position and update its own position accordingly. This is what I’ve tried, in the Striker.h file, keeping in mind I’m exposing these through UProperty so I can assign the reference from the BP derived class.

AActor* Puck; - This does not allow me to select the BP_Puck in the BP editor
TSubclassOf<AActor> Puck; - This allows me to reference the BP_Puck correctly, but then I can’t seem to use the reference at all as it returns UClass. I.e. in the Striker.CPP I try to obtain Puck->GetTransform().GetLocation(); but it the UClass does not contain this property.
APuck* Puck - This correctly lists the BP class in editor but does not allow me to actually click on it, the box just stays empty as if it’s not a valid reference even though it returns only that one class.

I think I’ve searched every forum post I can at this stage and I’m guessing I’m going about this the wrong way, but I can’t figure out how you’re supposed to achieve this. From my understanding, blueprints are meant to be a good starting and prototyping place, then transition to CPP implementation as required for performance.

But I can’t figure how you can possibly reference any object in your scene that is a BP derived class. Which from my understanding this is relatively common, to create a CPP base class then derive BP classes to alter meshes and what not? Am I going about this completely wrong or have I just missed something, all I need to be able to do is create a reference to a BP class in my header so I can interact with it accordingly in-game.

Appreciate any help on this one!

This worked fine for me when I added a property of type AActor*. It let me pick anything within the same map. What are you specifying within the UPROPERTY macro? It would need to be EditAnywhere or EditInstanceOnly in order to work (I think).

Also, it potentially sounds like you might be trying to set it in the Blueprint editor which won’t work because there are no instances there to select. You’d have to place your Striker instances in a map, place a Puck instance in the map, and then the Striker should be able to select the Puck.

Alternatively you could skip trying to hook it up manually and in C++ the Striker could use TActorIterator to find the Puck instance (since you’re only expecting one to exist anyway).

1 Like

This was 100% it, thank you so much, it was throwing me for a loop because it would show the puck as an available reference in the BP editor but once you selected it nothing would happen. Incidentally, it was updating the in scene version with that reference as you said it should be.

Hypothetically, if there were multiple pucks, is there any way to store a reference to all actors of a given class, so that you can then iterate through them? I had searched into TActerIterator but it didn’t seem to work as I had hoped, but maybe I just need to revisit it after this new revelation.

1 Like

Sure, you could make your variable a TArray< AActor* >, that would let you track multiples. But at that point you’re probably better off with a runtime option like TActorIterator. I can’t say what you were hoping to have happen with it, but it’s always done me pretty well. Another option would be to build things in a way to not need those references in the first place, but that probably involves physics and collision work I’m not really familiar with.

1 Like

TSubclassOf<AActor> Puck
This references the BP class itself not the instance(or class default object to be more correct). So you can create a new instance of that BP class inside for example BeginPlay() method. Then save this instance and use it however you want. Something like that:

void AStriker::BeginPlay()
{
    PuckInstance = GetWorld()->SpawnActor<APuck>(PuckClass, ...);
    PuckInstance->...
}
1 Like

This is definitely something that I’ve struggled with grasping, currently I’m using the game state to control spawning on the pucks based on the score. One thing I’m still figuring out how to do properly is to obtain a reference to an in-scene actor at runtime. At the moment I have the underlying Striker & Puck classes and have just added into the ‘OnBeginPlay’ Blueprint event to fetch the required references, while most of the heavy lifting is performed via cpp. This works, I’m just not sure if this is the best approach.

The primary reason I was looking at doing this way was to avoid having to loop through TActorIterator each tick and intead keep a TArray reference that is updated on each puck spawn and destroy event. It is actually working properly now, but I seem to have run into a new “issue?” where the array is being copied, from what I understand this is generally a bad thing in CPP? I believe you’re meant to always utilise pointers and references but can’t seem to figure out how to reference the array instead of copying it, or is this a restriction of cross class communiation?

Apologies as I’m asking too much of you but I’m not sure if this is trivial and I’m missing something again…

(Paraphrasing these H & cpp files to the relevant parts)
AI_Striker.h

public:
	TArray<AActor*> GetPucks();
	void SetPucks(TArray<AActor*> PuckArray);
private:
	TArray<AActor*> Pucks;

Puck.cpp

void APuck::BeginPlay()
{
	Super::BeginPlay();
	if (StrikerClass)
	{
		Pucks = StrikerClass->GetPucks();
		if (&Pucks) 
		{
			Pucks.Add(this);
			StrikerClass->SetPucks(Pucks);
		}
	}
}

The above works as expected, but my IDE is ‘warning’ me that StrikerClass->SetPucks(Pucks); is copying the Pucks object and I also don’t understand why I need to input if (&Pucks) instead of just if (Pucks)

You’ve gotten ideas about how to do the relationship chaining, but I thought I’d offer another observation:
In an actual air hockey game, you will make each actor be independent, and let the physics/simulation system update them, rather than tying pucks to strikers.

That makes sense, I hope I haven’t caused any confusion, the pucks are entirely physic s controlled objects. The primary reason I’m doing it this way is for the player to verse a computer opponent, so the enemy striker needs to know about the closest puck so it can update its own position accordingly. Ideally, you’d be able to verse another actual player and in that case, they would use the standard Striker class, not the AI_Striker class I created to simulate versing another person.

There’s no reason that you’d have to do it on every tick. You could do it once as part of BeginPlay, you’d still have the array it’s just being populated differently.

For the rest of it:

is being expected because Pucks is an array and isn’t implicitly convertable to a boolean. But it doesn’t make sense here because Pucks appears to be a member variable of APuck so you don’t have to do that sort of validation. GetPucks returns an array by value/copy so it will always be valid.

Your IDE is warning you because you are making a copy. You can avoid the copy by having the parameter be a const TArray<AActor*> & instead. Alternatively you could give your AI_Striker class an Add & Remove function that takes Pucks and manages the list completely hidden from the outside.

It’s hard to say if this is really doing what you want. Normally you’re not going to edit classes, you’re going to edit instances. So you’d still have the same problem regarding an Actor reference of finding the AIStriker instances to call Get/Set/Add/Remove/etc.

1 Like

Appreciate the input, seems at the core of it I had some design choices that worked, but were not ideal. Slowly understanding the more optimal ways of achieving the same outcome, thanks for the advice!

Honestly, attempting to do that is usually a sign that you’ve gone about something in a less than optimal way to begin with.

You have complete control over the game, why do you need to search the actors to find a specific one? Either you spawned it to begin with, so you should have a reference to it, or you placed it in a level, and it can notify other things of events of interest with it.

To make this work you either have to a) break encapsulation or b) populate it with delegates. Solution B still requires you to enumerate the objects somehow (manual level references or a search of the actors).

Solution A is just bad engineering. Let’s say you have an object type “Point of Interest” (or POI). Let’s also say you’ve got a system “Explorer” that cares about POI’s. A POI could poke the Explorer every time something happened, that’s not so bad. Now we add a new system “Territory” that also cares about POI’s. You could extend the POI to also poke the Territory system every time something happened. Again, not terrible but it doesn’t scale. The POI now is being updated for and has to know about every other system that is interested in them and becomes a bottleneck.

The only only system built into Unreal to solve this are delegates (that I’m aware of). Which are nice, except that (to continue the example) the Explorer and Territory systems have to find all the POI’s and add themselves to the POI delegates which the POI can broadcast. But to do that they have to be able to find and modify the ones you want to hear from. Static delegates could work, but it really depends on the systems. There really are good reasons why you’d enumerate them at runtime like this instead of trying to making one system aware of every other system that might care about it.

I just can’t figure out any real situation you would need to do something like that. I’ve been doing this quite a while now, and the only times I’ve ever iterated a large quantity of actors in a level is when I am modding an existing game, so I don’t have complete control over what I can do, or when I’m working with Unity, because Unity basically forces you to do it.

In general, if you created it, you should already have a pointer to it.

Perhaps it’s a matter of scale or team size. I can’t imagine that working in my professional projects (AAA, around 100 people). And I’ve been doing this quite a while too.

If I’m a level designer and I’m placing an actor, am I supposed to know every single place that should contain a reference to that actor so that it can query it? What about gameplay systems that don’t have any actors that I can modify (the recently added sub-systems for instance)? Does that system need some random actor in the world just to contain lists of actors it’s interested in?

If I give/remove a component from an actor, am I supposed to know everything that cares about actors with that component type and manually update them? That’s madness!

The only possible way that one person can know everything on a project is to be a team of one. And even then you discount the very real problem of “present you” vs “future you”.

Just about any process that can be automated, should.

The TActorIterator and TObjectIterator are both pretty performant. If you have a specific actor type to iterate that’s a great way to be sure to find all the things in the world (there may also be a get function that returns them in an array but then you probably have to iterate that anyway if you want to do any sort of filtering). TObjectIterator is great if you want to setup a component and find all the Actors that have one attached to it.

In C++ you’d have a static set of points-of-interest that you could iterate. Each PoI created would put itself in there on begin play, and remove itself on death.

It’s a little harder to do this in blueprint because of the lack of obvious globals/statics, but it can be managed in a few ways (e g, make a global registry object that they all get on construct and/or are configured with.)

That being said: Some cases, like “find player start object,” are perfectly fine use cases of “get all actors of class.” Sometimes, that’s the right choice.
You can even see collision detection as an instance of “get all actors with components that collide,” it just happens to be more optimized :slight_smile:

Absolutely, I would classify this as a “Solution B” solution where you’ve just provided another way to enumerate all the POI’s. It’s a perfectly fine way to approach it.

I think, mostly, it’s best to do as much in an event driven fashion as possible. What I’m working on has a few actor iterators, but almost all of that is in object pool management, save-state/restore-state, and debug/cheats.

For OP’s problem, with the pucks and the strikers, I’d have the Strikers and Pucks spawned by some sort of game-centric class (such as a GameMode or one of it’s related classes), put the movement code for the Puck inside the Puck, and the movement code for the Striker inside the Striker, and handle collisions inside the appropriate class. Why does a Striker need to know about a Puck unless it collides with it?

I agree. It’s just too bad that Unreal doesn’t really have a event mechanism beyond the use of delegates (which are powerful/nice, but have their limitations). I’ve even got an event system that lets the generators-of and listeners-for events remain separated from each other and not need any sort of enumeration. It’s a great, for certain things.

Overall, I agree with you. That’s basically how I’d generally set it up as well. However the question wasn’t “Am I setting up PONG correctly?” but “How do I setup Actor-to-Actor references?” Whether those references are the best way to do it is difficult to judge from the limited information usually posted for questions.

The OP made it pretty clear (at least in a followup post) there was an AI controlled version of the Striker which would obviously need to know about the Puck before it collides. You could argue that the Striker still doesn’t need to know about the Puck and that the AI controlling the Striker does, but you’re just moving the same problem to a different class in that case.

OP did ask “Am I going about this completely wrong?” and to that end, I say yes.

Some game related class should spawn the pucks and the strikers, and then you’ll have the pointers to them. You’ll need a couple of TSubclassOf UPROPERTYs to know which blueprints to spawn, but no need to figure out at runtime how to grab a pointer.

As for the AI needing to know where the puck is, then you could pass that pointer when you spawn the AI, since you have that information in that place. If you’re only going to have one puck ever, I guess an ActorIterator would be ok inside the AI Controller to find it, but if you’re going to change pucks, or have multiples, best to notify the controller when they come into play so you don’t have to iterate actors at runtime.