Search Unity

Calling upon a variable from one script to another

Discussion in 'Scripting' started by Kinxy, Nov 20, 2014.

  1. Kinxy

    Kinxy

    Joined:
    May 5, 2014
    Posts:
    22
    I want to create a whole class of spells for a card game. I want to store a huge bank of spells in one script, and call upon them throughout the game. In this instance I want to create a spell book, where I can create/browse my decks

    this is the start of the bank of spells script.
    using UnityEngine;
    using System.Collections;

    public class SBSpells : MonoBehaviour {

    public class spell {
    public int mana;
    public string typeClass;
    public bool unlocked;

    public spell(int mana, string typeClass, bool unlocked) {
    }

    public spell Dragon1 = new spell(2, "DragonTamer", true);
    public spell Dragon2 = new spell(3, "DragonTamer", true);

    void Start () {
    }

    void Update () {
    }
    }
    }

    I want to in another script create tabs/box/buttons within the screen of the different cards which you can click, to start building a deck all within the GUI. But I don't know how to call upon the variables. I have tried researching stuff but it is hard to understand as there seem to be no clear answer. So looking for some help/advice for my problem.
     
  2. RSG

    RSG

    Joined:
    Feb 20, 2013
    Posts:
    93
    You could place your spells in a public list so that other scripts can access them.
     
  3. Kinxy

    Kinxy

    Joined:
    May 5, 2014
    Posts:
    22
    Ah is a list better then classes? I was having a lot of debate with my friends with which is better. We are still new to c#. So would a list make it easier? and if so how would I write it to access a variable from the list?
     
  4. Fluzing

    Fluzing

    Joined:
    Apr 5, 2013
    Posts:
    815
    A list in the inspector is easy to access and manage. If you want to access the list, create a reference to the object holdign the list using GetComponent.
     
  5. Kinxy

    Kinxy

    Joined:
    May 5, 2014
    Posts:
    22
    But that is the problem, this bank of cards is just a virtual storage which allows us to access the information throughout the game. It isn't attached to any game objects. It just exists and things exists from its information
     
  6. RSG

    RSG

    Joined:
    Feb 20, 2013
    Posts:
    93
    There are many ways of doing this, each with pros and cons. One option would be to use a static class to store all of your spells, for example:

    Code (CSharp):
    1. public static class SpellBook
    2. {
    3.     public static List<Spell> Spells = new List<Spell>();
    4. }
    5.  
    You could also use a dictionary to access a spell by name instead:

    Code (CSharp):
    1. public static class SpellBook
    2. {
    3.     public static Dictionary<string, Spell> Spells = new Dictionary<string, Spell>();
    4. }
    Then you could access a spell from anywhere by doing:

    Code (CSharp):
    1. var spell = SpellBook.Spells["spell name"];
    2. spell.Cast(target, otheroptions)
    Yet another option would be to use a dedicated game object to store your spells and access them with static properties:

    Code (CSharp):
    1. public class SpellBook : Monobehaviour
    2. {
    3.     public static Dictionary<string, Spell> Spells = new Dictionary<string, Spell>();
    4. }
     
  7. Kinxy

    Kinxy

    Joined:
    May 5, 2014
    Posts:
    22
    Hm. Okay these were some ideas we were knocking around before. The problem we have we just don't know which would be the best in our scenario? I think I want to avoid using a game object. But does it even matter if you use one? I am unsure if I am being honest. Any tips?
     
  8. MattB79

    MattB79

    Joined:
    Sep 12, 2014
    Posts:
    20
    I made a empty game object and called it GameController and put my start up scripts and things I need to reference like spells .. and just use find object and get component
     
  9. Kinxy

    Kinxy

    Joined:
    May 5, 2014
    Posts:
    22
    Do I only need to do this once? and then just hide it in every scene?
     
  10. MattB79

    MattB79

    Joined:
    Sep 12, 2014
    Posts:
    20
    you can make a GameObject go to multiple scene's with DontDestroyOnLoad(myGameObject); ... It wont show up in the editor on other scenes but using find object in code will find it then.

    So yes you would only need to do it once
     
  11. Kinxy

    Kinxy

    Joined:
    May 5, 2014
    Posts:
    22
    Ah okay. And would that probably be the cleanest way to do it?
    Also I'm getting an error message. Unsure why, any help would be great. Confused what the problem is:


    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;

    public class SBSpells : MonoBehaviour {


    public class Spell {
    public int mana;
    public string typeClass;
    public bool unlocked;
    }

    public Spell(int mana, string typeClass, bool unlocked) {
    }
    public Spell Dragon1 = new Spell (2, "DragonTamer", true);
    public Spell Dragon2 = new Spell (3, "DragonTamer", true);



    public static class Spellbook {
    public static List<Spell> Spells = new List<Spell> ();
    Spells.Add (Spell(Dragon1));
    Spells.Add (Spell(Dragon2));
    }
     
  12. MattB79

    MattB79

    Joined:
    Sep 12, 2014
    Posts:
    20
    Spells.Add (Spell(Dragon1)); would just be Spells.Add (Dragon1); I think

    Also personally I don't like to use static if I don't have to.
    I would make the Gameobject you have spells on have its own tag and use
    http://docs.unity3d.com/ScriptReference/GameObject.Find.html
    and
    http://docs.unity3d.com/ScriptReference/GameObject.GetComponent.html

    Im not sure why static is bad ... I just remember my programming 101 class that's what the professor said..
    That was a while back in c++. Maybe things Changed idk
     
  13. MattB79

    MattB79

    Joined:
    Sep 12, 2014
    Posts:
    20
    Also you can Serializable the spell if your design allows then just have a public List<Spell> = new List<Spell>(); on the game object... and when you click that game object in the editor you can add spells right in the inspector instead of in code.. sometimes it makes it a bit easier to look back and modify a spell

    Something I use for commands in my game
    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3.  
    4. [Serializable]
    5. public class Command
    6. {
    7.     public int ID;
    8.     public string name;
    9.     public Sprite Icon;
    10.     public GameObject prefab;
    11.     public ActiveCommandCard activeCommand;
    12. }
    then on the game object I have a script that is
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Commands :MonoBehaviour
    5. {
    6.     public List<Command> = new List<Command>();
    7. }
    then I can add / modify all my commands right in the inspector
     
  14. Kinxy

    Kinxy

    Joined:
    May 5, 2014
    Posts:
    22
    Thank you so much for all the help. I'm going to give both options a spin and just see what happens. I need to learn lots, so thank you for all the help. I may be back with more questions, but hopefully not for a while!
     
  15. MattB79

    MattB79

    Joined:
    Sep 12, 2014
    Posts:
    20
    No problem :) If you do use Serializable Remember to have using System;
    I have to run to work now. ttyl
     
  16. Kinxy

    Kinxy

    Joined:
    May 5, 2014
    Posts:
    22
    When I type in the GameObject script it tell me I have an unexpected symbol '=' in class, struct, or interface member declaration. And I have no idea why that would be happening. :| I copied your code word for word.
     
  17. MattB79

    MattB79

    Joined:
    Sep 12, 2014
    Posts:
    20
    oh wow ... sorry copy paste fail
    public List<Command> commands = new List<Command>();
     
  18. Kinxy

    Kinxy

    Joined:
    May 5, 2014
    Posts:
    22
    Yeah I thought that was the problem. But I get an error after that. This is my adapted code.

    using UnityEngine;
    using System;


    public class Spell {
    public int ID;
    public string name;
    public Sprite Icon;
    public GameObject prefab;

    }


    then the gameobject script:

    using UnityEngine;
    using System.Collections;

    public class SpellList :MonoBehaviour
    {
    public List<Spell> SpellList = new List<Spell>();

    }


    and my error is = error CS0542: 'SpellList.SpellList': member names cannot be the same as their enclosing type

    edit: just fixed it but now I have "The tpy eor namescape name 'List'1' could not be found. are you missing a using directive or an assembly reference? FIXED. but I had to use System.Collections.Generic; but I am not getting anything in the editor like you mentioned.
     
    Last edited: Nov 23, 2014
  19. Kinxy

    Kinxy

    Joined:
    May 5, 2014
    Posts:
    22
     
  20. MattB79

    MattB79

    Joined:
    Sep 12, 2014
    Posts:
    20
    did you serialize the Spell class? then add the class with the list to a game object.

    it should show something like element size ... you put a number like 5 and it will have spots for 5 spells
     
  21. MattB79

    MattB79

    Joined:
    Sep 12, 2014
    Posts:
    20
    Another example of my weapons Class.

    This time I made sure all the code copy pasted correctly...

    I use my own custom name space CronoSoft for this... you can call the name space anything you want for yours.

    Code (CSharp):
    1. using System;
    2. namespace CronoSoft
    3. {
    4.     [Serializable()]
    5.     public class Weapon
    6.     {
    7.         public string Name;
    8.         public double BaseDamage;
    9.         public float Range;
    10.         public float AttackSpeed;
    11.         public double CritChance;
    12.         public double CritDamage;
    13.         public WeaponType Type;
    14.     }
    15. }
    Code (CSharp):
    1. using CronoSoft;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Weapons : MonoBehaviour
    6. {
    7.     public List<Weapon> weapons = new List<Weapon>();
    8.  
    9.     public Weapon getWeapon(string name)
    10.     {
    11.         foreach (Weapon w in this.weapons)
    12.         {
    13.             if (w.Name == name)
    14.             {
    15.                 return w;
    16.             }
    17.         }
    18.         return null;
    19.     }
    20. }
     
  22. MattB79

    MattB79

    Joined:
    Sep 12, 2014
    Posts:
    20
    For your spell it could be
    Code (CSharp):
    1. using System;
    2.  
    3. [Serializable()]
    4. public class Spell
    5. {
    6.     public int mana;
    7.     public string typeClass;
    8.     public bool unlocked;
    9. }
    and

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. public class Spells : MonoBehaviour
    5. {
    6.     public List<Spell> spells = new List<Spell>();
    7. }
     
  23. Kinxy

    Kinxy

    Joined:
    May 5, 2014
    Posts:
    22
    Thank you a lot for all your help. This is a great system. So I assume if I want to access my huge bank of spells would I use Find.GameObject.Getcomponent() ?

    Also if I wanted to add a special trait to the spell/ability which not all of the spells have, how would I add that to only a handful or maybe just one spell?
     
    Last edited: Nov 26, 2014
  24. MattB79

    MattB79

    Joined:
    Sep 12, 2014
    Posts:
    20
    yes get the game object the class is on and get Getcomponent() That would get the list of spells so you would need a way to get the spell you want.. add a index to the spell .. so you can search the list to find the spell with that number .. or use spell names and do that same looking to match a string.

    you could make a new class inheriting the spell class and add to it... you would need a separate list for those spells though

    http://msdn.microsoft.com/en-us/library/vstudio/ms173149(v=vs.100).aspx


    edit: if you look at mine I use
    public string Name;

    then a getWeapon method searching the list for the weapon with that name,, I'm sure there are better ways but im not sure how in c# ... in java I used HashMaps
     
  25. MattB79

    MattB79

    Joined:
    Sep 12, 2014
    Posts:
    20
    I forgot GameObject also uses Name as a string variable So you might want to be more clear naming it.. Like SpellName... I got mixed up once when the name didn't match what I thought it would.
     
  26. Fluzing

    Fluzing

    Joined:
    Apr 5, 2013
    Posts:
    815
    If you are accessing the spells a lot, it is better to store a reference to the script instead of using GetComponent everytime:

    Code (csharp):
    1.  
    2.  
    3. SomeScript script;
    4.  
    5. function Start()
    6. {
    7.       script = GameObject.Find("SomeObject").GetComponent<SomeScript>();
    8. }
    9.  
     
  27. Kinxy

    Kinxy

    Joined:
    May 5, 2014
    Posts:
    22
    So using this script I gain access to the bank of spells. But if I only want to access a specific bit of information, for example total number of spells. Which is size. How would I be able to access this through the secondary script, like how could I in another script access the variables.

    http://puu.sh/d6Go2/5686d91572.png
     
  28. MattB79

    MattB79

    Joined:
    Sep 12, 2014
    Posts:
    20
    You could make a public static class ... well function to get the list. I normally don't like doing statics .. there's limitations
    like each spell in the list is global so if you change anything during run time it will effect all object using that spell

    This code wont work just an example.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. public class SpellsList
    5. {
    6.     private static List<Spell> spells = new List<Spell>();
    7.  
    8.     public SpellsList()
    9.     {
    10.         SpellListScript script = GameObject.Find("SpellListGameObject").GetComponent("YourSpellListScript");
    11.  
    12.         spells = script.spells;
    13.     }
    14.  
    15.     public static List<Spell> getSpells()
    16.     {
    17.         return spells;
    18.     }
    19. }
    Then other scripts could access your spell list by just doing

    Code (CSharp):
    1. SpellsList.getSpells();
    So you would need to get component just one time and put the list into a static variable

    You would also want to edit the script execution order to avoid nullpointer... the static script must happen after the Spells script and before any script that uses the spells


    msdn link to static classes
    http://msdn.microsoft.com/en-us/library/98f28cdx.aspx