What is good practice for making something actor, pawn, character etc.?

For a long time I had the only used in my game immediate child class of the character and that was “FightingCharacter” which meant player or enemy. The NPC was an immediate child of the actor. But recently I have made moving NPCs and thus all NPCs became characters. Is this good? Or is it better to make all NPCs again only the actors and add something like Floating Pawn Movement or Projectile Movement only to the moving NPCs? And vice-versa, I planned for a long time to make characters that are necessary to kill to get resources, but the performance issues have appeared and forced me to do them just actors. So, what is good to be character, and what is good to be only actor or pawn? Are there common guidelines for the wide set of games?

1 Like

Hey @Etyuhibosecyu!

A pawn is an actor with movement ability through the Floating Pawn Movement component and can be possessed by AI.

A character is a more specialized version of a pawn. They are required to use a capsule collider and a static mesh. With a lot of extra work, an actor could become a pawn, and a pawn could become a character. They are in the engine to save you lots and lots of time fine-tuning an actor.

Does it move? If no, it’s an actor.
Is it humanoid? Use character. The Character movement component is there to save you days of work, and it only works on a Character or a child of character.
Is it not humanoid? Use pawn and add the pawn floating movement component.

Your performance issues are likely not related to this. I’ve spawned 1000 characters to test out movement of a crowd, all animated, and lost one frame of FPS. It could be related to the textures you’re using or something like that. Of course, your mileage may vary.

If you need lots of an enemy, and they are basic, use Pawn, I’d say. But if they are humanoid, try limiting the amount spawned at one time. How many NPCs are you working with?

Let’s continue the conversation and see what works best for you!

3 Likes

Hello @Mind-Brain!

So, projectiles should be pawns?

I agree, but it would be nice if I could add Character Movement to an actor or a pawn, or create a character without the skeletal mesh, but both aren’t allowed.

In my game I need 70k moving actors. 1000 is not serious.

I have changed type of those constructions from character to actor and got MUCH more performance. Texture remained the same.

Unfortunately, I cannot change the parent class of the enemy separately from the player.

1 Like

If it does not move, it’s an actor. Actors can also move, but so can Pawns and Characters. But because Actors do not inherently have the ability to be controlled via a controller, they are for things that aren’t supposed to “think”.
A projectile should be an actor, with projectile movement component.

Yeah, the character movement component relies on the capsule to drive its movement, along with a LOT of behind-the-scenes work. The floating pawn movement component can be just as useful, though! Just not out-of-the-box.

This seems excessive. You may need to explain the premise of your game a little more. 70k characters will DEFINITELY hurt performance. That’s a lot of AI controllers. Is it a large-scale strategy game akin to the Total War series?

Sure you can! There’s nothing stopping you there, unless you have to switch possession to that enemy.

2 Likes

I think so too.

Is not Projectile Movement enough, if I just need blocking collision, gravity and moving in the certain direction? But is it valid if the actor moves slowly (1.5-2 m/s) and every several seconds changes the direction?

I have faced this, and thus made them not characters but only actors.

It is a large-scale RPG.

No, because player and enemy are both fighting characters, and have very much common functionality.

This was saying the floating pawn movement could be as useful as the Character Movement component depending on your needs.

Projectile movement is… less of a parent-child, more of a sibling to floating pawn movement. Definitely don’t use pawn for gunshots, arrows, etc.

I suppose my biggest question is the need for 70k. Are we talking 70k people? Or does that include projectiles?

If it’s more like a Dynasty Warriors game, I see what you’re saying. But- you could make your player a child of the Third Person character, so it keeps all of that functionality, and add in player-specific code. Then you’d have another child of the third person character called “Enemy” and give it anything enemy-specific. Then keep anything they BOTH need on the third-person character, so they’ll both have everything a third-person character will have.

For instance, each fodder enemy doesn’t need a skill tree with 100 unlockable moves, only the player does, but each one of them loaded in will have that if they’re instances of the same actor.

The less you can have on your massively spawned enemy armies, the better.

Another thing you can do- look into lightweight actor instances. You might be able to get some use out of that functionality. It’s meant for large amounts of independent actors for large-scale games!

3 Likes

Neither first nor second. They are actors that are necessary to kill to get resources, visually similar to animals.

They are not enemies. They probably will have the health in the future (to shoot several times), but they do not have force, defense, effects, they cannot become aggressive, and so on.

Thank you, I will try to watch at the free time.
But the main question: FightingCharacter should be the only used immediate child class of the Character? Does NPC have to be character or just actor? Some of them move, whereas some don’t. Some of them have non-empty static mesh, some have non-empty skeletal mesh. They have various forms such as humanoids as well as, for example, crystal. But I cannot split this class tree because they have much common (for example, crystal is necessary to grab by task, so it is technically the NPC that gives task). Regarding this, what should be the parent class for NPC by good rules?

1 Like

I have partially watched the video you linked, and there is a question: will that system work with actors that are not abstract “crowd” but are functional, other blueprints will cast to their type and do some actions? If each actor has just a transform, will it generate hit events? And is it possible to add actors to that system at runtime?

So looking at your examples, you need a few different things.

First you’ll want to make a parent for all of them that are characters. Make the parent class of “Character” actor, and create this custom class with anything the children will need.

You’ll make any that are CHARACTERS, which are humanoids, all use this same parent Character, not ThirdPersonCharacter.

Next, you’ll want to do the same but with pawn instead of character.

You’ll make any that are not characters but animals or rocks or whatever, make those children of this class.

So it will look like

Character

NPC_Character

NPC_Character_A
NPC_Character_B
NPC_Character_C

Pawn

NPC_Pawn

NPC_Pawn_Rabbit
NPC_Pawn_Bird
NPC_Pawn_BigEyeball

There is a way around this with just using actor as their overall parent and creating custom character and pawn classes based on that, but trust me when I say you’ll spend much more time creating a custom pawn class and character class based on that actor when it’s usually a matter of adjusting variables.

Now, for another topic, you say 70k actors. Is this your entire world? Or the player’s immediate vicinity? Because those two things are very different optimization wise and you may simply need to have the AI controllers be inactive until the player comes near enough to interact with them. Because why would they need to be active if the player is 1 km away? That sort of thing. I’m thinking the reason the performance went up when you switched them to actors is there is not any AI controller on actors.

I know this is a lot, I myself kept getting turned around in my thoughts as I was writing it but I tried to be as clear as possible, let me know if I can clarify anything for you!

1 Like

It is the count all over the world.

But how to cull them when they are 1 km away? They are not visible but they are present on the client. How to fix this?

Ahhhh here we go. SO!

You create spawners!

Make an actor. Base actor. Let’s call it “BP_Spawn_Parent”.
Give it a collision volume as large as you want the distance to be.
When the player overlaps that collision volume, using OnComponentBeginOverlap, spawn your NPC using SpawnActorFromClass!

Set that spawn as a variable in the spawner actor. That will be on the Return Value of the SpawnActorFromClass node. What this does is sets your spawned actor as a variable- you’ll see why in a moment!

Next, make your variable for the actor to spawn. Make it a variable of “Actor” so you can pass ANY actor or their children in here, and make it a class, so the violet option. Then click the eye, so it is instance editable. This means any copies can have different values. It should look like this:
image

You’ll use the actor’s spot as the Spawn Transform for the Spawn Actor From Class node.

Lastly, as the first part of the Event, add an “IsValid?” check and pass in “Spawned Actor”. On True, which means the actor is spawned, you do nothing. On False, just spawn, because there isn’t one already there. What this does is make sure when the players run away and come back, it doesn’t cause them to multiply the spawn and put more instances of the actor there when there is meant to be only one.

You should have something like this:

Let me know when you get all of this done, and I’ll show you how useful this is when creating children! All you have to do is change ONE value and it will create a new spawner for a different type of NPC.

Then after that, I’ll show you how to cull actors beyond a certain distance. As long as they have a spawner, they’ll come back when they’re needed!

2 Likes

@Mind-Brain, here is my variant:


I guess the spawner must not be replicated?

@Etyuhibosecyu Casts don’t work this way. You’re attempting to use it as a check, I think?

For what you’re trying to do you need to use “GetClass” on the “other actor”, an “==” or “Is child of class” node, and a branch. :slight_smile: Only use “==” if that is the EXACT AND ONLY class that you want to trigger it.

Casts are for changing something into a more refined version of itself. So, you would do this if you wanted to access the code on “Ally” and only “Ally” would ever collide with this volume, which you’re not doing anything there so you don’t need the cast.

As far as replication… that’s a pretty big detail you have to add! :slight_smile: I was thinking of this as a single-player game. However, this should be executed on the server, and the actor should be replicated.
Non-player actors are server-owned objects and will not work correctly if spawned on the client.

But why? When the trigger sphere collides with anything, I guess the resource actor must not be spawned, only when that sphere collides with ally (player is a subclass of ally, I use this cast to avoid direct mentioning player and make the game more modular, as what links to player that links to everything). I understand that “Is child of class” makes the same, but I like more the cast because it is more brief.
And you were going to show:

I guess the spawner must not be placed in the editor?

Mind-Brain is certainly leading you in the right directions, here’s some solid tutorials and explanations that i typically look at when i don’t understand the WHY and want to slam my head into a wall

Useful depth sometimes but at least for me never a complete picture
Ryan Laley

Useful ways to quickly do stuff but not always the best way to do it
Gorka Games

Another similar to GorkaGames…
Matt Aspland

Really solid source on things to avoid doing with full explanations of why
Definitely check out this one out if you ignore all others: LeafBranchGames

Lighting type stuff
Love this guy, he’s actually partly deaf and makes the best lighting tutorials with reasonable explanations that I’ve ever seen William Faucher

1 Like

@Mind-Brain, I have just checked what is faster - “Class Is Child Of” or casting - by repeating one, then another, very many times in empty project - and have got that casting is even slightly faster - 67-68 against 80-81. So if you meant that casts “don’t work this way” because they are slow, this is wrong.

@Etyuhibosecyu Sorry for the confusion. I know casts have a common misconception of what they are used for. I am not saying “Because they are slow”, what I’m saying is that casts are not useful for checking if one actor is another actor, or another common misconception, that they are for communication. I was guilty of that one myself for months when I first began using Unreal.

During that time, I thought of a cast like casting a fishing pole and reeling it in.
This is wrong.
It is more akin to a mold that a smith would use to CAST a sword, or a CAST for when you have a broken bone.

Anything that the cast target CAN cast to will trigger the collision. This could provide issues.
An “Is Child Of” node means anything below the listed class in the hierarchy will work, but nothing above that will. Yes, it’s slightly slower than a cast, but will cause less issue IF you only want children of that class to trigger it and not any parents.

If you just want it to be “Ally”, use a == class node. That is 100% faster than a cast.

Yup! You replace any of the actors you put in the world with their corresponding spawner. If you need better visual representation, you can give the spawner a static mesh that has “Visible” set to true, and “Hidden in game” set to true as well, so you can see it in the editor, but not in game.

So, moving on, now you have a spawner. You can create a child of that spawner, then in Class Defaults, set the actorToSpawn variable to the class you need. Example:

BP_Spawner_Rabbit
would have the class set to “BP_Rabbit”.

You can make a different spawner for every type of NPC you want, then just drop them in for virtually 0 cost. You could even get fancy and add randomization to it later.

This will lower your overhead IMMENSELY.

1 Like

@Mind-Brain, well, I have changed cast to ClassIsChildOf. I cannot use == class node because “Ally” is abstract class and the actual actor class will never be exactly equal to it. I have done as you had written and I have really noticed significant performance improvement. But I don’t understand, what is the actual difference between some large number of the resource actors and the same number of spawners? The tick?
Anyway, let’s see:

The AI controllers is my biggest guess but there’s a lot going on behind the scenes for pawns and characters. Not really noticeable for any project I’ve done but 70k is quite a few.

So now what you’ll do is: On your resource actors, you give them an additional large collision volume as well, much like your spawner. Make sure it is at least 1000 units larger than the spawner radius at all times, so you don’t spawn it and immediately collide with this.

Now with that collider, use OnComponentBeginOverlap, just as you did with the spawner, and use DestroyActor!

I had an idea for another thing you could do when I wrote this, but that was before I knew it was a multiplayer game. I was going to suggest using “GetPlayerController” and “GetDistanceTo” and if it was greater than a certain distance, Destroy Actor. But that won’t work with multiple players.

1 Like

Maybe OnComponentEndOverlap?