I am creating a weapons system in my game whereby the player character and enemies can pick up weapons of different types. I am using inheritance to define this structure, a basic diagram is shown below.
For each gameobject I create, I also want to create a script associated with it. I.e a handgun gameobject would also have its own script, same with machinegun and shotgun. Each of these scripts would inherit from the weapon abstract class, which in turn inherits from monobehaviour. These classes would define each of the weapons, what projectiles the gun fires, how fast, what spread etc.
Given a player character or enemy that is currently holding a weapon, which could potentially be any weapon, I want to be able to access the weapon script to call the fire method. The fire method would be defined in the Weapon abstract class as an abstract method. My question is given that I know the character is holding a Weapon, and that weapon is stored in a variable, how best do I call the fire method?
The below examples will show code within a script of a gameobject that is firing the weapon.
My current thoughts are as follows.
Simply use sendMessage
This is by far the simplest option, and makes use of inheritance as I know the weapon must have a method called Fire, but I get the impression that this is both not very performant and bad practice.
Use GetComponent.
I have one big issue with this method. As far as I’m aware i need to explicitly state the type of component I need to get, and if I only know the type of component is Shotgun when it could in theory be any other weapon during runtime. I am under the impression that if I were to use code similar to this:
Even if it did return the shotgun script, I would not be able to invoke the Fire method as it is abstract!
Use events
This is the option I know the least about! Though I would be happy to research it more to see whether it is viable. I essentially know it is a possibility but don’t want to look too much into it now if it isn’t seen as a good option.
Any help in deciding what method is best to use here would be greatly appreciated. I fully accept I could be completely barking up the wrong tree, so any other suggestions are welcome. If I have left anything out/ just haven’t explained myself very well please feel free to ask questions!
You’re correct that option 1 is simple but problematic. It’s prone to typos (which would generate runtime errors rather than compile-time errors), not very performant (though on this scale the difference would be infinitesimal), and has a risk of both false positives and negatives. Plus, you wouldn’t be able to send it parameters (which doesn’t matter much here but for other things it might).
Regarding option 2:
This is not true (well, except for the incorrect GetComponent syntax), and having code like this is the reason abstract methods exist in the first place. First, if Shotgun inherits from Weapon, then GetComponent() would indeed give you your Shotgun - it counts all inherited types when getting the component. Second, if Weapon has an abstract Fire() method and Shotgun overrides it, you would be able to call Shotgun.Fire as you’d expect.
Option 2 is a good choice.
Option 3 is more complex, but still pretty good, and a little more versatile than option 2. Weapons can be coded to decide for themselves whether they want to fire, it’s easier to support firing multiple weapons at once (a la bullet hell shooters), etc. But for this, it’s probably overkill unless you specifically want to learn how events work for the sake of the learning experience (because events are incredibly useful for a lot of situations).
Another option would be interfaces (just to toss that out there), which would give you a way to access the script and know that it has a certain method if it implements the interface. But, @StarManta provided great info on your three other options and which would be best for your current setup.
Huh, I was so completely under the impression that it would be harder than that that I didn’t catch that basic syntax error and assumed the error was referencing Weapons fire method being abstract! I’ve just tried it now and it works a charm. There’s quite a few other places where I could refactor my code to use this method! It’s good to know that it is considered good practice too.
I certainly want to learn events at some point, just right now I’m already learning so much about Unity that I’m just taking it one step at a time! Once I feel like I understand the fundamentals + move away from just prototyping this idea I will take a much greater look at events.