Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Spell buffs, temporal skill boost, temporal character states, etc. How to?

Discussion in 'Scripting' started by raycosantana, Apr 7, 2014.

  1. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    I just finished my database system to hold all the items and spells of my game, but now Im having problems conceiving how to make items that give the player temporal boost or spells, or even how to give the player or enemies temporal states (such as poison, on flames etc...)

    My item setup is really basic, there is a basic "Item" class with an abstract void and the different classes for the different types of items that override that abstract void with their own void. Same with spells.

    My question is more from a conceptual stand point, I mean I don't need help with the code it self but more on which approach would be more optimal to this kind of features.

    For example, lets say I have a spell that increases the attack stat by 10 for 10 seconds and lets say the attack calculation is:

    Attack*4-E.Defense*2

    Do you rise the attack stat like this:

    Attack= Attack+10;

    Attack*4-E.Defense*2

    Or you would rather add a new variable so the attack calculation is now:

    Boost = 10;

    attack*4+Boost-E.Defense*2

    or how would you do this kind of stuff?
     
  2. _met44

    _met44

    Joined:
    Jun 1, 2013
    Posts:
    633
    My point of view on this topic is that in the end it really depends what your needs are.

    I would probably keep references to all effects in dictionnaries of lists for fast access to all effect of a type and calculate when appropriate, but then again if you don't ever cumulate any effect that isn't of any use and if you have 1 million mobs with active effects on each, calculating each frame could even turn out to be painfull whereas having the sum ready would be effective.

    Also, if you plan on having effects affecting other effects, this conception might be of some help as well...
     
  3. Glader

    Glader

    Joined:
    Aug 19, 2013
    Posts:
    449
    I would recommend you calculate all boosts separately from the base attack. When you go to serialize, or save, the data do you really want to worry about if the current stats are boosted? I would say keep real values separate from temporary values for this reason, and others, however you'll end up with the same result either way.

    I would take the hit of the increased memory allocation and computation, which should be negligible, for the decoupling of boosts and real values. This however seems like a subjective design decision that doesn't have a TRUE black and white answer.
     
    Last edited: Apr 8, 2014
  4. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    I would put those values (AttackBonus, DefenseBonus, FireDamage) into properties and let them query any effects/influences when needed. The effects itself are in a list on the player/enemy and checked every update if they still apply or need to be removed (time over). When a boosted value is required (the property is called) the list is iterated and all effects of that specific type are summed up and returned by the property.
    So in general you put an effect in the list, the player class checks itself if it still applies and the calculation queries the summed value when needed. simple and extendable. Your items/spells just need to modify the list (fe when an item is unequiped the bonus is removed, antidot removes poison etc). All you need is a class for handling all the functionality (timed, unlimited, enum for the effect, value for the effect, possibly a list of those itself) and a method which queries all objects in the list and asks them if they have an effect on attack, defense, damage to player over time etc. .

    Edit:
    this way you can also handle permanent class bonuses.
     
  5. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    Thanks all, I got a few ideas!.

    If anyone more want to add anything more please do, Im always open for more points of view on this matter.

    Kind regards!
     
    Last edited: Apr 9, 2014
  6. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    In doing this you also want to keep an order of events.

    Attack = base * percentage + 5 + 3 - 2;

    !=

    Attack = (base + 5 + 3 - 2) * percentage;
     
  7. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    Yes I understand.

    The idea I had following the example I said in the opening post goes something like this:

    There is a TempVariable for the Attack, at the start the TempVariable is equal to the Attack stat

    TempVariable = Attack;

    Then when the Boost is applied +10 is added to the TempVariable

    TempVariable += 10;

    Then it counts 10 seconds and subtracts the extra 10 points and the boost is over.

    TempVariable -= 10;

    I don't know exactly how I'm going to add the boots to the characters, I like the idea @exiguous said about the lists but I don't know if is possible to Auto-eliminate stuff from the lists (boots eliminating themselves from the list when the boost is over) so I don't know...
     
  8. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    A cool way to do this, is to add "modifiers" or component scripts to your character. You do this by using Polymorphism and a base class.

    Here is an example:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class Modifier : MonoBehaviour {
    6.     public float timeRemaining = 10;
    7.     public string modifierText = "Generic Modifier";
    8.     public int order = 0;
    9.    
    10.     // Update is called once per frame
    11.     void Update () {
    12.         DoTimer ();
    13.     }
    14.  
    15.     public Character GetCharacter(){
    16.         return transform.root.gameObject.GetComponent<Character>();
    17.     }
    18.  
    19.     public Character GetTarget(){
    20.         Character chr = transform.root.gameObject.GetComponent<Character>();
    21.         if(!chr) return null;
    22.         return chr.target;
    23.     }
    24.  
    25.     public virtual void DoTimer(){
    26.         if (timeRemaining != Mathf.Infinity) {
    27.             timeRemaining -= Time.deltaTime;
    28.         }
    29.        
    30.         if (timeRemaining <= 0) Destroy (this);
    31.     }
    32.  
    33.     public virtual float ModifyDamage(float value){ return value; }
    34.     public virtual float ModifyAccuracy(float value){ return value; }
    35.     public virtual float ModifyAvoidance(float value){ return value; }
    36.     public virtual float ModifyHealing(float value){ return value; }
    37.     public virtual float ModifyDamageResistance(float value){ return value; }
    38.  
    39.  
    40.     // these are here for after effects, like heal on damage.
    41.     public virtual void FinalDamage(float value){}
    42.     public virtual void FinalHeal(float value){}
    43. }
    44.  
    using this as a base class, you crate things like this:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class Blessed : Modifier {
    6.     public float timeRemaining = Mathf.Infinity;
    7.     public string modifierText = "Blessed, damage +1, healing + 1";
    8.    
    9.     public override float ModifyDamage(float value) {
    10.         return value + 1;
    11.     }
    12.    
    13.     public override void FinalDamage(float value){
    14.         Character chr = GetCharacter ();
    15.         if (!chr) return;
    16.         chr.ApplyHealing (ModifyHealing (1));
    17.     }
    18. }
    19.  

    Now, all you have to do is to run a loop on all the modifiers and call specific things. like

    value = mod.ModifyDamage(value);

    This changes the value. Using the order, you simply count to the max order number and modify them in order.

    I did probably about 20 scripts just to make sure things worked out ok. I did things like food buffs, debuffs, cursed items debuff throwing modifiers (like acidic, gives an acid debuff) I did protectors, like AidProtection which stops damage. (the acid debuff looks for the AcidProtection and stops it from being attached or stops the damage if it is attached. The timer part works just fine because I am subclassing it,all I have to do is to rewrite the time remaining part. I use Mathf.Infinity to make permenant modifiers, like a Acidic sword is permenant, but a SpellBlessed sword would not be permenant.

    I can check the character for all modifiers and apply them to the damage, healing and other things. it is very expandable IMO.

    I created the Character base class, which is what the Blessed item does. and apply healing every hit. I also created a Weapon base class, with default attack and hit stuff.

    Since this is an entire system and involves way too many scripts, I am not going to share it all here.
     
  9. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    I see, I get the concept its a great system, I may copy the idea of using components instead of lists, thanks!.

    The problem I have is when I first started working on this game I wanted to do an action adventure but soon I changed my mind (because Im an idiot :D ) I started adding RPG elements to it but by then I realized the player character class and enemy character class where very different, so now to do something like this I will have to rewrite both classes to inherit from the same character base class (like any normal RPG) so both player and enemies can use the same states and boosts. I guess I will have to anyways or it wont be a proper RPG :rolleyes:
     
    Last edited: Apr 10, 2014
  10. Tzan

    Tzan

    Joined:
    Apr 5, 2009
    Posts:
    733
    You may also want to review the Decorator Pattern.

    http://en.wikipedia.org/wiki/Decorator_pattern
    Take a look at the Java code coffee example, after reading the base text.
    I know some guys who were using this for RPG effects.

    Lots of other examples out there.
     
  11. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    After checking over that... it is exactly the same as I had discussed.
     
  12. Tzan

    Tzan

    Joined:
    Apr 5, 2009
    Posts:
    733
    Its not exactly the same.

    In your version
    With a decorator, each decoration wraps all the previous decorations and the original object.
    In the coffee example the last value of "c" is the Sprinkles.

    Then you get a value.
    Code (csharp):
    1. public double getCost() {
    2.     return super.getCost() + 0.7;
    3. }
    4.  
    It reaches down into the previous decoration to get that cost, then all the decorations before that, etc.. and then adds the last cost. It doesnt use a loop to get the value.

    I'm not saying either one is better. But they are different.
     
    Last edited: Apr 16, 2014
    DotusX likes this.