Modular/Scalable Blueprint Component Setup - Best Practice?

Howdy,

I’m new to the engine and putting together a simple target shooter game (with some semi-realistic ballistics) using the first person template as a starting point. As part of the learning experience, I’m trying to make my systems modular/scalable so that I have the option to expand on the project in the future. I’ve run into a roadblock in my understanding of how best to handle setting particular parameters onto a weapon (eg ammunition type used) in a way that doesn’t involve having to edit the blueprint each time I create a new one and I’m hoping someone might be able to help me out.

Current Progress

Building upon the first person shooter template:

  • The BP_Weapon_Component (Blueprint Component) controls the core weapon logic (firing the weapon, setting fire mode (semi auto, full auto, etc…), playing sound/animations and spawning a projectile. My goal is for this to be the basis of any weapon I chose to add
  • The BP_Projectile (Blueprint Actor) is spawned whenever the weapon is fired. The BP projectile uses the projectile movement component and references a data table I have created to get the relevant projectile properties (initial speed and energy, damage, drag calculation variables, etc…). My goal is for all parameters for ammo types I implement to be contained in this data table, and for the projectile to then use these properties based on what ammunition is currently being used in the weapon (hopefully to be grabbed from the BP_Weapon_Component)

My goal is for the BP_Weapon_Component to be used as the basis for every weapon I implement, by having exposed variables that I can update to control the characteristics such as usable ammo types, fire modes, etc… without having to re-create this logic for each one or go into the blueprint to edit. Once complete, I’m hoping this is as simple as attaching this component to any new weapon I create.

As an example, I’ve created 3 fire modes for the weapon component. These are controlled via enumeration and I’ve added corresponding booleans into the BP_Weapon_Component to control whether the weapon is able to use each.

image

This (mostly) works, but seems rather clunky. It’s easy enough to implement there’s only a few options, but if I was to use this method for the ammunition types, it would become much more bogged down as suddenly their could be 10+ bools just to control this.

Another issue I’ve run into is I’m not sure how to check what type of ammunition the BP_Weapon_Component is set to, and then have the projectile pick this row out of the data table. I’ve tried creating an enumeration (with the exact same names as the rows of the data table), setting this to a “Current Ammunition” variable in the BP_Weapon_Component, then using a blueprint interface with this enumeration to get the row name via the “Get Data Table Row” node, but this doesn’t seem to work, and I’m not sure if it’s actually the best way to approach this scenario?

image

Questions

  1. I’m confused about how the weapon component blueprint is referenced (attached?) by default in the First Person Shooter Template Project. As far as I can tell, the weapon component is attached to the player character on event ‘Begin Play’, but then the component is attached again when the weapon is picked up.


From BP_Weapon_Component


From BP_Pickup_Rifle

What are these two nodes actually doing, and how would I expand on this if I wanted to add a second weapon type that uses the same BP_Weapon_Component component? Can the component not just be added to a new actor BP for each weapon type?

  1. Is there a better way for me to setup the BP_Weapon_Component component to control functionality such as usable fire modes/ammunition types for each weapon type than just using bools? I had a bit of a play around with creating an enum array for usable ammunition types, but I didn’t want to go down that learning path if there’s a more obvious/better solution

  2. How can I reference the current ammunition type in the projectile actor in order to get the projectile properties via the corresponding data table row? Was using an enum and blueprint interface on the right track, or is there a better way to go about this? If so, how can I equate an enum to a data table row name?

Hopefully the above all makes sense. Please let me know if it’s helpful for me to provide any more details in order to answer the above questions. I’m having a lot of fun with UE5 so far and am hoping I can learn some better ways to go about the above.

Thanks!

I’ve been having a play around and think I’ve answered a 2/3 of my own questions.

Question #2
Using an enum array for the ammo types and the firing mode works well. The array variables can be edited without changing the blueprint logic and the in both cases, the next enum in the sequence can be stepped through (dynamically based on the values in the array) by cycling through the array indices. Useful forum post + image of my logic in case it helps anyone else:


(Same logic for the fire modes, just using a separate set of variables)

Question #3:
I was attempting to use a blueprint interface to ‘send’ the relevant ammo type from the weapon component to the projectile. I had a few issues with this:

  1. My blueprint interface setup not firing. Using an ‘enum to string’ node does work correctly with the ‘get data table row’ node, I just had mistakes in my setup.
    image

  2. I was trying to setup these parameters (via the blueprint interface) before the projectile actor had spawned. I believe this makes sense, since the actor doesn’t exist to receive this information before it is spawned. Since the projectile spawn logic is contained in the Weapon blueprint component, the solution was to create a ‘Current Ammo Type’ variable and tick ‘Expose on Spawn’ within the variable details panel. This feeds the information from the weapon blueprint to the projectile as it is spawned and has resolved my issue.
    image
    image

I’m still not 100% sure about Question #1, but I will continue to have a play around and see if I can improve my understanding. If anyone has any info on how this works it would be much appreciated, but otherwise I’m going to set this question to resolved. Hopefully the above might help someone else out