I’m currently working on a turn based RPG prototype and have run into an issue I don’t have a solution for.
One of the moves players are able to do in combat involves shooting weapons that are stored in the player’s inventory as a class reference. The issue is that these weapons have a currently loaded ammo variable that’s stored in the actor of the weapon, and every time it’s fired I want to decrease the ammo currently stored in it. (So that reloading the weapon is an action the player can take). The issue I’m having is that I require an object reference in order to rewrite the value on the weapon blueprint, but I only have a class reference in order to pull the information of the currently selected weapon from the inventory.
Is there any way to pull a specific object reference from a class reference or even just to be able to set the variable in the object to a new value? If not, does anyone have any suggestions for a possible workaround? Ultimately I just need to rewrite the current ammo stored on the individual weapon blueprint.
Presumably you must have the current ammo amount stored somewhere, like the save game, otherwise when the player switches to this weapon, you have no way of knowing what the amount is supposed to be?
Is the weapon blueprint itself the actor(blueprint) ? or is it a component or some other class attached to the weapon actor?
Basically, I want to know how your system works when player uses the weapon. Do you spawn an actor from the weapon class reference you have?
If so, you’d probably want to create a component(or interface or a combination of both) for your player where you do the logic related to ammo and reloading (and other instance based stuff) and inside the blueprint of the weapon class you get a reference of component/interface of the player using the weapon and just call their logic.
This introduces some coupling between player and weapons though.
What I would do, would be to create a class for “ammo type” which is a plain UObject, not an Actor. (UObjects can still have variables/properties, and participate in SaveGame, and such.)
I would then instantiate an instance of this class per ammo type, and put those into the player inventory.
Presumably this object has properties like “Amount” and “Name” and “Damage Type” and maybe “Icon” and “FireParticles” and “FireSound” and “ImpactDecal,” depending on specifics.
When a particular kind of ammo is loaded into the weapon, you’d simply set the “current ammo” variable of the weapon, to that object. But don’t remove the object from inventory! When firing, you subtract from available ammo in the object.
If you want to model magazine reloading, you have to also model magazines, and move ammo from the inventory to the magazine. (And then, in savegame, save each magazine with each weapon.)
This is not all that dis-similar from how you’d handle “stats” or “currency” in an inventory – I have 33 gold coins and 18 silver coins; what happens when I buy something that costs 3 gold coins? Same deal.
Finally, because this is similar to stats and resources, you may want to look at the Gameplay Ability System (GAS.) You could probably model all of this as a sequence of properties and modifiers in the GAS, which opens up certain interesting kinds of gameplay affordances. It’s probably not important enough to make the substantial move to GAS just for ammo types, but if you use GAS for other things (spells, affects, etc) then using it also for ammo types could make sense.
Thanks for the response, this is a great suggestion.
You’re right, the weapon is an actor blueprint. Currently the inventory is stored as a class reference map in the player controller which is weapons are being pulled from to populate the menu.
My understanding is that within the component I still need to set a variable reference to the actor in question, but I’m unsure what object I can cast from since the actor isn’t a character or directly possessed by the controller.
I was thinking somewhat opposite of saving a reference in component.
Basically I would create a new component called something like AmmoManager, Add a pointer property (object reference in BP) called OwnerAmmoManager of that type to the gun actor blueprint, add a setter function and whenever you spawn your gun from the class reference, immediately set the object reference to the AmmoManager of the player that spawned the gun.
Inside the component itself add public functions/custom events like Reload, GetTotalRemainingAmmoCount, GetMagazineRemainingAmmoCount, and any other needed functionality.
Then for example when player tries to shoot, inside the gun actor code use the ammo manager reference to check if there is any ammo left in the magazine, and if there is proceed with shooting. If not call reload and maybe play some reload montage.
Note that this makes the ammo logic identical for all players though. If for example you have different classes and each have their own seperate logic (A heavy gunner class for example can have an unlimited ammo skill), instead of using a component you might want to use an interface instead which lets you have custom logic for each class inheriting the interface.
If you are somewhere in between (meaning you have both generic and specific ammo behavior depending on the player) You can create both an interface and a component.
For generic behaviour just call the component functions/custom events inside your interface method implementations and when you need specific behaviour, write your custom logic instead of calling the component.