Weapon enchantments - designing the code architecture?
I've been thinking for a couple of days now about how to implement weapon enchantments through Unity.
For example:
Iron Sword (10 damage on hit, 1 attack per second)
Swift Iron Sword (10 damage on hit, 2 attacks per second)
Iron Sword of Fire (20 damage on hit, 1 attacks per second, target burns for 5 seconds)
Swift Iron Sword of Fire (20 damage on hit, 2 attacks per second, target burns for 5 seconds)
I would like to be able to achieve this without having a unique prefab for every single possible combination, primarily as doing so is both time consuming and could eat up a lot of space.
The way I would do this in a "regular" Object Oriented architecture would be decorators. (Read: The way I WOULD do it, not the way I HAVE done it, this could still be entirely wrong!) ie, Weapon sword = new SwiftEnchant( new FireEnchant( new IronMaterial( new Sword() ) ) );
However, I can't see how a decorator model could exist within the component based architecture of Unity.
Can anyone help me out by pointing me in the right direction here? It would be much appreciated.
Answer by OncaLupe · Nov 14, 2015 at 08:07 PM
The way I would do this, is to have a base item (in this case Iron Sword) that has variables inside for the different possible enhancements.
For a simple setup, you could have booleans for each of the types to set if the weapon has it, and a companion variable to set how much it affects the weapon. Like a bool 'hasSpeedEnhance' and a float saying how much faster (or slower for penalties) it swings.
You could also use class inheritance and interfaces to allow for more flexibility, where the base weapon doesn't need a variable for each type. On attack it could call a method in the derived class that gives it a chance to modify the stats of that attack.
Your suggestion of a derived class hierarchy is similar to the decorator method, and pretty desirable for what I want. What I can't get my head around, is how do I derive from two, three, four base classes?
Having a list of enchantments like your simple setup sound like how I'd plan on passing the data in a communication context - ie the server will pass a JSON serialized inventory object to the client, telling him he has a (type=Sword; damage=10; speed=0.5; enchantments=[swift, fire])
However, with each weapon type having its own unique behavior (sword, bow, boomerang) I'd rather not have each and every single weapon type script manage a list of enchantments and how they affect it. $$anonymous$$ostly because it's error prone and fiddly with X unique weapon types and Y potential enchantments, and I'd like to keep refactoring to a $$anonymous$$imum if I was to add different enchantment behaviors.
I'd rather go with a pattern somewhat similar to a decorator where I just "fire and forget" the enchantments as wrappers around the weapon and each other. To keep enchantment code encapsulated within its own scope, so the code for "Iron Sword" has no mention of the enchantments.
So when I call int x = weapon.damageTarget(foo); I don't need to worry about getting my +20% poison damage, or applying a 5 second burning status effect, two very different potential enchantments, I just know it will work because they got wrapped up in there.
What I was thinking of, is you'd have one base enhancement class that all enhancements would derive from. I'd define the core methods needed like OnSetup(), OnAttack(), and OnHit(). The specific enhancements would then derive from that and perform their jobs in those overrides.
The base item doesn't need to know any specifics. When the weapon is first made, it would make new instances of the proper enhancement, then just call the proper method(s) when needed.
For instance, a Swift Iron Sword of Fire would create a new EnhancementSwift and EnhancementFire, and store the refs in a list. Each enhancement would have a reference back to the base weapon. Then it could call OnSetup for each, which could modify base stats like speed. Fire enhancement would add it's fire damage over time when it's OnHit(target) is called.
This was just my rough idea off the top of my head. There are many different ways of doing this, and it'd take some time to iron out exactly how it'd work, but I think the basic idea is possible.
Answer by Whitecold · Nov 14, 2015 at 07:57 PM
You can define yourself some enhancement class that holds the information (attacks per sec/ dmg multiplier/etc.) and then put all modifiers on a weapon in a list. Using Linq or just iterating you can then easily get the total effect of all enhancements on a weapon.