PlayerCharacter and PlayerController General Advice

So im just messing about with character classes and player controller class.

Previously I was doing all my inputs in the character class. But I wanted to have a proper player controller and derive from the base character class for the AI characters.
So. Im after some pointers.

I have changed my character class around a bit and created a player controller class to control all the inputs n what not.
My baseCharacter class holds functionality for calculating health and energy and thats about it.

My player controller handles Input as well as two functions.
One is a ray trace which calculates if you can use an actor in the world, the other calculates the nearest actor of a particular type to use as a respawn point.
Im curious as to the best place to keep those functions. Should they exist in the character/pawn class or within the player controller.

Here is the function for getting a usable actor which is in the player controller

And here is how its called in the event graph

The problem is, after i kill and respawn the player the log is spammed with
Blueprint Runtime Error: Attempted to access Nox_BaseCharacter_C_0 via property BaseCharacterRef, but Nox_BaseCharacter_C_0 is pending kill from function: ‘GetUsableActor’ from node: LineTraceForObjects in graph: GetUsableActor in object: Nox_PlayerController with description: Attempted to access Nox_BaseCharacter_C_0 via property BaseCharacterRef, but Nox_BaseCharacter_C_0 is pending kill

Here is how I kill the character. This is within the base character class
The playerDied function at the end is an event which exists within the player controller class.
Which looks like this

And here is how I respawn the character. In the gamemode.

Previously, just using a character class. This all worked a bit better. After respawning, the HUD reappeared and I didnt get the log spam from the usable actor.

Im just trying to find out if im going about this sort of behaviour in the right way.

Any help is very much appreciated.
Thanks all!

If you happen to try to use a pointer variable (a blue variable referencing an object) which references an object which has been destroyed (let’s say you removed it from the world), it throws errors at you. That’s what happen in your error log, you must be trying to get the reference to the character you just destroyed.

In your case the culprit variable is “BaseCharacterRef” in your “GetUsableActor” function.

I suggest you to add a simple check here that makes sure the reference you are trying to get is valid. Drag a pin out of your “BaseCharacterRef” variable and search for the “IsValid” node, the macro or the function it doesn’t matter they are the same. Use this node in your function to make sure it doesn’t spam errors in your log.

But this is just a trick to “hide” the errors. If you build your code well you might never need to ask if something “IsValid” because you know you won’t be passing through that function if a variable is not valid. In your case, you could just be instantly swapping the value of “BaseCharacterRef” when you possess a new character, before destroying the previous one, leaving no room for errors.

Regarding the organization, the first question you can ask is: “will enemies need / use this?” if so, you’re likely to be coding this in your Character (if I understood correctly you want to create a child class of your character Class for your enemies).

In my opinion it’s better to put the input listeners in the Controller and the action themselves in the Character.
For instance I have a Character used for my Player avatar and my Enemies. It has a function called “MoveTowards” which takes a float and a vector as parameter.
I then have a “PlayerController” and an “AIController”.
The PlayerController listens the input “AxisMove” and calls the “MoveTowards” function on its Character.
The AIController receives information from its Behavior Tree and calls the “MoveTowards” function accordingly.
My EnemyCharacter overrides “MoveTowards” and performs an “AIMoveTo” node.
My PlayerCharacter overrides “MoveTowards” and performs a “AddMovementInput” node.

Quote me if you want more details.

I was planning to use a single character class for the player and the ai. Then use a PlayerController or AiController to move control them.
Initially I was doing it with a base character, then two child classes of that, one for AI one for Player. But that just seemed wrong.

Would it be possible for you to show me some examples of how you would set up player input?

This is how my input looks inside the player controller
Is this a logical way of doing it? Or even the correct way?

Thanks a tonne for the help!

So I think I was being stupid. It all makes a lot more sense to me now.
I was creating the reference to the player character on BeginPlay within the player controller. Obviously, this reference is only ever created once!

So I figured that the best place to create this reference is in the gamemode. Every time I run the re-spawn player event, I recreate the reference to the player controller.
The game mode always exists and the reference to the player character is re-created every time it re-spawns. So the reference to the player character is always valid! Boom!

Thanks a lot for all the help Yun-Kun!!