Download

Organizing large Character class

The UTCharacter class is 7000 lines of code, with logic dealing with movement, first person view, skins, weapons, game rules, and everything else. If I wanted to separate all of this out into smaller logical units, what would be the best approach? The standard way of doing things seem to be to just put everything in one big class file, which I don’t like very much.

The docs say ActorComponents are meant for behaviors that are reusable on different Actors. Would this still be the best solution? Other options are to use my own non-unreal classes that are entirely contained within the Character class, or to just put different functions in different cpp files.

Thanks for any help, just looking for some tips or experience on this issue.

There is no “best approach”, it’s all personal preference.

You can a more Object Oriented approach and break things into various classes, components, etc, or just do a single class.

I tend to do a mix of classes/components/lots of methods that are self descriptive, since I’m not a fan of large source files when I can avoid them.

You can do a few things. You can break your class into multiple .cpp files such as MyCharacter.cpp, MyCharacter-Movement.cpp, MyCharacter-SomeComponent.cpp. You can utilize OOP by making Inheritance Classes such as MyCharacter, MyMobileCharacter, MyComponentBasedCharacter. Finally my personal choice is to compartmentalize special functionality into ActorComponents. ActorComponents always have a reference to the Actor they are attached to so they can call public functions of your Character, they can be ticked for frame updates or not. You can also initialize them from your Character in the constructor (if they are not optional), you can also use the C++ function FindComponentByClass if it is optional and may or may not exist for C++ sake. All of these strategies can be utilized just make sure no matter what you do you pick and stick with it, if you change your strategy make sure you go all the way with the changes.

I personally utilize Components. I have
TraitComponent
CombatComponent
InventoryComponent
EquipmentComponent
CustomMovementComponent

All of these things are design with a specific purpose, some may rely on each other, some may be independent. My PlayerController handles input which calls functions on the possessed Character Class. My CharacterClass is responsible for Actions not Input, that I feel is an important distinction, I like to stick to a Brain to Body sort of idea where the Controller is the Brain which tells the Body how to function. I Also utilize a Custom Movement Component for all Movement Related actions such as switching between Walking, Running, Sprinting, etc. Camera Systems also do not Exist ON my Character Class/Blueprint my PlayerController is responsible for Creating the Third Person Camera System which attaches and Detaches to from the Pawn, this allows me to utilize any Character Class for my PlayerController and not have to alter it for an AIController. If I need Access to the Inventory on the Character the PlayerController can call a function such as GetInventoryComponent() or I can use the FindComponentByClass if it is optional. HUD and User Widgets have a reference to the PlayerController directly so HUD Actions all go through my Player Controller. Say You have an InventoryItemWidget where you double click on it to use or equip the item. The Widget simply calls PlayerController->UseItem(inventoryIndex) and the Player Controller is responsible for triggering the Use Operation on that item. I like this approach because it is applicable to the same functionally being called using an AIController who does not receive input from the user to perform actions like use an item.

Thanks for the info, these are definitely helpful. Now I’m wondering why Epic does it this way for UT. Is that just what happens when you are on a tight schedule, or is there an advantage to having everything in one place?

The advantage may come from having several Actor components that Tick on their own. Each Actor must be ticked and Each ActorComponent that can be ticked is also ticked. So there may be something there. You may also be able to chalk it up to “Epic just knows what they are doing”, so familiarity with a specific pattern is a huge benefit if everyone is used to looking at massive class structures without flinching…

The only thing single file per class gets you is slightly faster compile times. If you break things up in many files (and then include those files), the compiler has to go grab them in order to compile things. That may be intentional, or, again, it was just personal preference to the Author.