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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

How could I code an attribute system?

Discussion in 'Scripting' started by Steelshot, May 17, 2016.

  1. Steelshot

    Steelshot

    Joined:
    Feb 24, 2015
    Posts:
    102
    Hi, my name is John.

    I'm creating a game to when you have to keep track of 6 patients. You hAve to maintain their health, hydration, and sanity levels. How do I make a attribute system that will change the values of the levels at a certain time?

    I am a "noob" at programming but a good designer. (Ps. If you want to help collab with me, let me know!)
     
  2. kru

    kru

    Joined:
    Jan 19, 2013
    Posts:
    452
    There are a number of ways to handle this. You could have a central component which has one variable for each important value. This is a useful way to go if you are certain that any object which has one value will also have the others. In other words, its rigid and simple.

    A more unity-like way would be to create a component for each value, and add those components to any object which needs them.
    Code (csharp):
    1. public class Health : MonoBehaviour { }
    2. public class Hydration : MonoBehaviour { }
    3. ...
    4.  
    5. // then you can manipulate an object's health by
    6. var objectsHealth = someObject.GetComponent<Health>();
    7. objectsHealth.Value = 5;
     
  3. Steelshot

    Steelshot

    Joined:
    Feb 24, 2015
    Posts:
    102
    Ah okay, thanks for the explanation!
    So, if I add the two <> to the sides of the componets would that add it in?
     
  4. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    <T> is the notation for a "generic" class/function/whatever, T being the "type" (aka "class").

    Not sure what you mean by "add it in" though :confused:
     
  5. Steelshot

    Steelshot

    Joined:
    Feb 24, 2015
    Posts:
    102
    Thanks for clarifying that for me haha

    Say that I don't have the component, how would I add it automatically with out going to the component selctions?
     
  6. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Keep it simple. All the patients have the same property, one MonoBehaviour should do the job. Then you can simulate the patient evolution by using the update function. Also you can implement the player action through other function, for instance:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Patient : MonoBehaviour
    4. {
    5.     public float health;
    6.     public float hydratation;
    7.     public float sanity;
    8.  
    9.     public float hydratationDecreaseRate;
    10.  
    11.     // Update is called once per frame
    12.     void Update ()
    13.     {
    14.         // Simulate here.
    15.         hydratation -= hydratationDecreaseRate * Time.deltaTime;
    16.  
    17.         // update other parameters here.
    18.  
    19.     }
    20.  
    21.     public void Drink(float hydratationIncrease)
    22.     {
    23.         hydratation += hydratationIncrease;
    24.     }
    25.  
    26. }
    27.  
     
    Last edited: May 18, 2016
  7. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,184
    I would encourage you to take the component-based approach. Usually, stat attributes have some logic of their own, like notify somebody that the stat changed, which they all share, so it makes sense to put them in their own classes and share a base class. Here's an incomplete example:

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3.  
    4. public class HealthAttribute : BaseAttribute
    5. {
    6.     public bool isAlive
    7.     {
    8.         get { return base.value > 0; }
    9.     }
    10.  
    11.     public void Damage(int value)
    12.     {
    13.         base.value -= value;
    14.         if(base.value < 0)
    15.             Debug.Log("I'm dead. Now what?");
    16.     }
    17. }
    18.  
    19. public abstract class BaseAttribute : MonoBehaviour
    20. {
    21.     public event Action<float> ValueChanged;
    22.  
    23.     public int defaultValue = 1;
    24.  
    25.     public int value
    26.     {
    27.         get {return value;}
    28.         set
    29.         {
    30.             if(value != _value)
    31.             {
    32.                 _value = value;
    33.                 if(ValueChanged != null)
    34.                     ValueChanged.Invoke(_value);
    35.             }
    36.         }
    37.     }
    38.  
    39.     [SerializeField]
    40.     int _value;
    41.  
    42.     protected virtual void Start()
    43.     {
    44.         value = defaultValue;
    45.     }
    46. }
    47.  
    Make sure that the .cs file name is the same as the class you want to attach to a GameObject and that that class is first in the file (usually you separate your classes into different files anyway).

    The BaseAttribute is abstract, because it's not a real thing yet, it only contains logic which is shared by all attributes, such as firing an event when the value changes or checking that nothing falls below zero, whatever you need. The concrete attributes then add specific methods or variables to the base class or reinterpret the base data to make it more readable. You could just use access the base class and modify the "value" property, but maybe it is more readable to have a "Damage" method that makes is very clear what's happening, also usually specific things add up and you end up with different behaviour for your stats anyway.

    Best tip ever: if you can, use int instead of float. If you need smaller increments, then just make the max health value be 1000 instead of 100 for example. If you start with floats, you might run into some problems when trying to compare two values if they are the same, as you will experience, they might not be although you think they are close enough. Google "float precision vs int" for more info on that.
     
  8. Steelshot

    Steelshot

    Joined:
    Feb 24, 2015
    Posts:
    102
    Thanks for the example!

    If I were to call the value into a text box, would I do

    using UnityEngine.UI
    public text HydrationLevels;
    public int value;

    void Start (){

    value = 0+1;

    }

    void Update () {

    HydrationLevels.text = "Hydration Levels: " += value;

    }

    Would that add the value number to the text?