Okay, I need some solid OOP advice. Here’s the setup: I have a player object with code that handles things like movement, pathfinding logic, etc. Now I need to assign each player a large table of variables and settings. Namely, each player has about 40 different weapon actions he can perform, and each weapon has 6-8 variables associated with it. My question is, which data-structure is most appropriate. Note, I don’t want to create a class for each weapon because weapons are never instantiated in my game.
Here are the specifics: Each player has 40 different weapons that need to be pulled by name. For example:
Weapon #1: Pistol
Weapon #2: Shotgun
Weapon #3: Rifle
Weapon #4: Bow
Weapon #5: RocketLauncher
Each weapon then has the same set of variables assigned to it. For example:
Pistol.HasBeenUnlocked (true/false)
Pistol.Priority (1-40)
Pistol.AmmoQuantityMax (0-10)
Pistol.AmmoQuantityCurrent (0-10)
Pistol.UIButtonState ("Hidden", "Selected", "Deselected", "CoolOff")
Pistol.CoolOffTimerMax (0.0-5.0)
Pistol.CoolOffOn (true/false)
Now I want some sort of data-structure that organizes all these variables and makes them easy to access. For example, I want to be able to loop through all 40 weapons and generate buttons for them based on whether they were unlocked by a particular player. Here’s what I want to do:
for (int i = 0; i < Player.Weapons.NumberOfWeaponsTotal(); i++) {
if (Player.Weapons.Weapon[i].UIButtonState == "Hidden"){
// don't create a UI button to fire weapon
}
else {
// create a UI button to fire weapon
}
}
Variable names across the different weapons will be the same. So Weapons.Pistol.UIButtonState will exist, as will Weapons.Rifle.UIButtonState.
So what’s the best way to organize this? A 2D array isn’t pretty. A structure doesn’t seem robust enough. A class sees strange. I’ve never used classes for this sort of thing. I want to make sure this is somehow linked to the player, so when he’s destroyed, so is this “object”.
Define a struct or a class type that contains all the properties that all the different weapons have. Create an array[40] of this weapon type and store it as a property on the player type. Define an enum of ints to use as named indices into the weapons array. Pistol = 0, Shotgun = 1, etc. Use these enum names to index into the weapons array in your code.
On the rare occasion when you do need to look up a weapon by string name, you can just scan through the weapons array until you find the weapon whose name matches what you’re looking for. Capture the index of that weapon and throw away the string name, so that all further operations are by indexed array. The cost of a linear scan through 40 items will not be noticeable.
If you really do absolutely have to avoid scanning the list for a matching name, you could construct a Dictionary to provide fast lookup by name. You’ll want the dictionary entries to return the weapons of a particular player, so you’ll need a different dictionary instance for each player, and store it in a field of the player object. If the simple scan is sufficient (it almost certainly is), don’t bother with the dictionary approach.
Regardless of whether you define the weapon type as a struct or a class, it is a structured type and you are creating instances of this type every time you use it. 40 instances per player. The main difference between class and struct is where/how the memory is allocated and whether assignment copies the values or not. If you are careful to never assign a weapon from the array into a local weapon variable, and you don’t use the dictionary thing above or do anything else that needs to share references to the same weapon data, then struct should be fine. If in doubt, use class.
You don’t need to worry about the weapons getting disposed of when the player goes away – as long as the weapons array is the only thing that keeps a long term reference to the weapons, then they will all be disposed when the player is disposed. Proper encapsulation and minimizing cross-references between different objects will help here.
If you are certain that your selection of weapons will always have the same variables and the same actions (methods), then you can get by with a single weapon type for all the weapons, and that type can be a struct or a class.
If you start getting into special cases where this action behaves differently for that weapon, or this weapon has additional data that none of the other weapons need, then you should look at defining a base weapon class and descendents of that for specialization as needed.