Search Unity

Creating Random Begining Character Stats

Discussion in 'Scripting' started by Huwey, Apr 12, 2019.

  1. Huwey

    Huwey

    Joined:
    Mar 17, 2019
    Posts:
    15
    Ok so I am following a tutorial on youtube for making an rpg. In the video they have created script that gives static creation stats, what I'm wanting to do when the character creation process is started I'm wanting the few stats that they will have be randomized between set numbers. Here is what I have right now for the character stats:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class BaseWarriorClass : BaseCharacterClass
    6.  
    7. {
    8.     public BaseWarriorClass()
    9.     {
    10.         CharacterClassName = "Warrior";
    11.         CharacterClassDescription = "A sword wielding hero!";
    12.         Strength = 10;
    13.         Damage = 8;
    14.         Stamina = 5;
    15.         Intelligence = 3;
    16.     }
    17. }
    18.  
    As you can see right now the given stats have defined values but I want it to be where the strength could be anything between let's say 7 and 10. So I tried doing this
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class BaseWarriorClass : BaseCharacterClass
    6.  
    7. {
    8.     public BaseWarriorClass()
    9.     {
    10.         CharacterClassName = "Warrior";
    11.         CharacterClassDescription = "A sword wielding hero!";
    12.         Strength = Random.Range(7,11);
    13.         Damage = 8;
    14.         Stamina = 5;
    15.         Intelligence = 3;
    16.     }
    17. }
    And get the following error in unity:
    UnityException: RandomRangeInt is not allowed to be called from a MonoBehaviour constructor (or instance field initializer), call it in Awake or Start instead. Called from MonoBehaviour 'TestGUI' on game object 'Main Camera'.
    See "Script Serialization" page in the Unity Manual for further details.
    UnityEngine.Random.Range (System.Int32 min, System.Int32 max) (at C:/buildslave/unity/build/Runtime/Export/Random.bindings.cs:48)
    BaseWarriorClass..ctor () (at Assets/Scripts/Character Class/BaseWarriorClass.cs:12)
    TestGUI..ctor () (at Assets/Scripts/TestGUI.cs:8)

    With me being new to all this I'm not sure what I need to do to achieve what I'm wanting and do not understand the error. If there is more information needed let me know and I'll do what I can to give what is needed.

    Thanks in advance for the help.
     
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    4,696
  3. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,286
    Your BaseWarriorClass inherits BaseCharacterClass. BaseCharacterClass probably iherits MonoBehaviour because all unity scripts inherits MonoBehaviour. Therefore, your BaseWarriorClass is MonoBehaviour. You invoked Random.Range method from the BaseWarriorClass constructor. The error message says you must invoke it from the Start or Awake methods instead of constructor, like this:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. public class BaseWarriorClass : BaseCharacterClass
    5. {
    6.     public BaseWarriorClass()
    7.     {
    8.         CharacterClassName = "Warrior";
    9.         CharacterClassDescription = "A sword wielding hero!";
    10.         Damage = 8;
    11.         Stamina = 5;
    12.         Intelligence = 3;
    13.     }
    14.    
    15.     public void Awake() {
    16.         Strength = Random.Range(7,11);
    17.     }
    18. }
     
  4. Huwey

    Huwey

    Joined:
    Mar 17, 2019
    Posts:
    15
    Ok so I tried this with my stats and it's giving back all 0's.
    Capture.PNG
    Here is what I have now:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class BaseWarriorClass : BaseCharacterClass
    6.  
    7. {
    8.     public BaseWarriorClass()
    9.     {
    10.         CharacterClassName = "Warrior";
    11.         CharacterClassDescription = "A sword wielding hero!";
    12.         //Strength = 10;
    13.         //Damage = 8;
    14.         //Stamina = 5;
    15.         //Intelligence = 3;
    16.     }
    17.  
    18.     public void Awake()
    19.     {
    20.         Strength = Random.Range(7, 11);
    21.         Damage = Random.Range(6, 10);
    22.         Stamina = Random.Range(4, 8);
    23.         Intelligence = Random.Range(0, 5);
    24.     }
    25. }
    Here is the BaseCharacterClass that the BaseWarriorClass is inheriting from:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class BaseCharacterClass {
    6.  
    7.     private string characterClassName;
    8.     private string characterClassDescription;
    9.  
    10.     //stats
    11.     private int stamina;
    12.     private int damage;
    13.     private int strength;
    14.     private int intelligence;
    15.  
    16.     public string CharacterClassName { get; set; }
    17.     public string CharacterClassDescription { get; set; }
    18.     public int Stamina { get; set; }
    19.     public int Damage { get; set; }
    20.     public int Strength { get; set; }
    21.     public int Intelligence { get; set; }
    22. }
     
  5. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,286
    Your properties are not connected to the class fields.

    Wrong:

    Code (CSharp):
    1. public class BaseCharacterClass {
    2.     private int stamina;
    3.     public int Stamina { get; set; }
    4. }
    This code defines two places to store 2 values not related each to other: manually declared stamina field and autogenerated backing field for Stamina property. Changing one of them won;t affect another.

    Right:

    Code (CSharp):
    1. public class BaseCharacterClass {
    2.     private int stamina;
    3.     public int Stamina {
    4.         get { return stamina; }
    5.        set { stamina = value; }
    6.     }
    7. }
    In this code there is one value - stamina, wich can be accesed (read & write) through Stamina property.
     
  6. jasrei

    jasrei

    Joined:
    Apr 19, 2018
    Posts:
    13
    The BaseCharacterClass is also not a MonoBehaviour, which means Awake() will never be called. In this case, I would actually not use the Unity Random class. There is no obvious reason for your class to be a MonoBehaviour, so use built in C# Random class instead as Brathnann suggests.

    Code (CSharp):
    1. Random rand = new Random();
    2. var stat = rand.Next(7,11);
     
  7. Huwey

    Huwey

    Joined:
    Mar 17, 2019
    Posts:
    15
    Ok I will try these changes when I get home thanks. I will update with results then
     
  8. Huwey

    Huwey

    Joined:
    Mar 17, 2019
    Posts:
    15
    Ok, so I believe I have updated/adjusted as suggested. If not I do apologize I am clearly very new to unity and C#.

    Here is the new scripts:
    Code (CSharp):
    1. public class BaseCharacterClass {
    2.  
    3.     private string characterClassName;
    4.     private string characterClassDescription;
    5.  
    6.     //stats
    7.     private int stamina;
    8.     private int damage;
    9.     private int strength;
    10.     private int intelligence;
    11.  
    12.     public string CharacterClassName { get; set; }
    13.     public string CharacterClassDescription { get; set; }
    14.     public int Stamina
    15.     {
    16.         get { return stamina; }
    17.         set { stamina = value; }
    18.     }
    19.     public int Damage
    20.     {
    21.         get { return damage; }
    22.         set { damage = value; }
    23.     }
    24.     public int Strength
    25.     {
    26.         get { return strength; }
    27.         set { strength = value; }
    28.     }
    29.     public int Intelligence
    30.     {
    31.         get { return intelligence; }
    32.         set { intelligence = value; }
    33.     }
    34. }
    35.  
    And:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class BaseWarriorClass : BaseCharacterClass
    4.  
    5. {
    6.     public BaseWarriorClass()
    7.     {
    8.         CharacterClassName = "Warrior";
    9.         CharacterClassDescription = "A sword wielding hero!";
    10.         Random rand = new Random();
    11.         var Strength = rand.Next(7, 11);
    12.         Random rand1 = new Random();
    13.         var Damage = rand.Next(6, 10);
    14.         Random rand2 = new Random();
    15.         var Stamina = rand.Next(4, 8);
    16.         Random rand3 = new Random();
    17.         var Intelligence = rand.Next(0, 5);
    18.     }
    19. }
    20.  
    I am now getting the following:
    Error CS1061 'Random' does not contain a definition for 'Next' and no accessible extension method 'Next' accepting a first argument of type 'Random' could be found (are you missing a using directive or an assembly reference?)

    Not sure if it makes a difference but I'm using Visual Studio Ver. 15.9.11 and Unity 2018.3.12f1
     
  9. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    4,696
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class BaseWarriorClass : BaseCharacterClass
    4.  
    5. {
    6.     public BaseWarriorClass()
    7.     {
    8.         CharacterClassName = "Warrior";
    9.         CharacterClassDescription = "A sword wielding hero!";
    10.         var rand = new System.Random(); //Or System.Random rand = new System.Random();
    11.         var Strength = rand.Next(7, 11);
    12.         var Damage = rand.Next(6, 10);
    13.         var Stamina = rand.Next(4, 8);
    14.         var Intelligence = rand.Next(0, 5);
    15.     }
    16. }
    17.  
     
  10. Huwey

    Huwey

    Joined:
    Mar 17, 2019
    Posts:
    15
    Ok, I see. I'll try that tomorrow. Thanks again. Sorry for such noobie questions and mess ups on implementation of answers.
     
  11. Huwey

    Huwey

    Joined:
    Mar 17, 2019
    Posts:
    15
    I had to make a slight change to what your suggested code was to get it to work.
    But it is now working for me. Thank you for your assistance!

    Code (CSharp):
    1. public BaseWarriorClass()
    2.     {
    3.         CharacterClassName = "Warrior";
    4.         CharacterClassDescription = "A sword wielding hero!";
    5.         var rand = new System.Random();
    6.         Strength = rand.Next(7, 11);
    7.         Damage = rand.Next(6, 10);
    8.         Stamina = rand.Next(4, 8);
    9.         Intelligence = rand.Next(0, 5);
    10.     }
    However I did notice that I couldn't have the same range for the same stat on multiple classes because they would show the same results.



    So that is what I'm going to work on next. I'm assuming if I was to change the names slightly to represent each class then it would allow the generation of different numbers instead of just "Strength" maybe change it to "WarStrength" for my warrior and maybe "WmStrength" for my white mage ect.

    EDIT: So, that didn't work. Even tried changing the var name and that didn't work either.
     
    Last edited: Apr 13, 2019