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

C#: How to access a script not attached to a gameObject?

Discussion in 'Scripting' started by DarkBladeNemo, Dec 7, 2016.

  1. DarkBladeNemo

    DarkBladeNemo

    Joined:
    Aug 23, 2013
    Posts:
    116
    Hi

    So I was wondering how I can access my script from another script without it being attached to a gameObject and vice versa.

    The reason why I'm asking is because it seems to be causing some problems if I attach it to a gameObject and then making a prefab of it so that my other gameObjects can also interact with it.

    The script I want to access from other scripts:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class Experience : MonoBehaviour {
    7.  
    8.     public int playerLevel = 1;
    9.     public float expLevelModifier = 1.5f;
    10.     public float expNeeded = 100f;
    11.     public float currentExp = 0f;
    12.     //public Image level1;
    13.  
    14.     public PlayerHealth player;
    15.  
    16.  
    17.     // Use this for initialization
    18.     void Start () {
    19.        
    20.     }
    21.    
    22.     // Update is called once per frame
    23.     void Update () {
    24.         if(currentExp >= expNeeded){
    25.             currentExp = 0f;
    26.             playerLevel += 1;
    27.             expNeeded = (expNeeded * expLevelModifier);
    28.             player.maxHealth = (player.maxHealth * player.healthModifier);
    29.             Debug.Log("Level Up");
    30.         }
    31.     }
    32. }
    33.  
    I have been looking around but all the answers seem out dated and not very clear to me on how to do it.

    Thanks in advance
     
  2. Fabian-Haquin

    Fabian-Haquin

    Joined:
    Dec 3, 2012
    Posts:
    231
    You should use the keyword static then

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. public static class Experience {
    6.     public static int playerLevel = 1;
    7.     public static float expLevelModifier = 1.5f;
    8.     public static float expNeeded = 100f;
    9.     public static float currentExp = 0f;
    10.     //public static Image level1;
    11.     public static PlayerHealth player;
    12.  
    13. public static void Init(int startPlayerLevel, float modifier, float xpNeeded, float currentXP, PlayerHealth player)
    14. {
    15. Experience.playerLevel = startPlayerLevel;
    16. Experience.expLevelModifier = modifier;
    17. Experience.expNeeded = xpNeeded;
    18. Experience.currentExp = currentXP;
    19. Experience.player = player;
    20.  
    21. }
    22.  
    23.  
    24.     public static void AddExperience(float experience)
    25. {
    26.       currentExp += experience
    27.         if(currentExp >= expNeeded){
    28.             currentExp = 0f;
    29.             playerLevel += 1;
    30.             expNeeded = (expNeeded * expLevelModifier);
    31.             player.maxHealth = (player.maxHealth * player.healthModifier);
    32.             Debug.Log("Level Up");
    33.         }
    34.     }
    35. }
    36.  
    Then you call

    Code (CSharp):
    1. Experience.AddExperience(100);
    from elsewere

    A static var is shared between all instance of a script, that's why you can directly call Experience instead of an instance of it.

    Anyway you have to initialize it somewhere of you want it to have a reference of your player because you can't have this script serialized in the editor.
     
    Last edited: Dec 7, 2016
    Swdcxzaq and Jeff-Goin like this.
  3. DarkBladeNemo

    DarkBladeNemo

    Joined:
    Aug 23, 2013
    Posts:
    116
    Is it possible to use this method and still modify the values? I have a experienceGain on my enemies that adds to the currentExp when they die and also have a bar that gets increased as the currentExp goes up. So my question can I use this and still modify them from other scripts?
     
  4. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,802
    If I'm understanding this correctly, you want to be able to access the Player's Experience script from any object, but you can't drag and drop it for a reference because you can't reference with Prefab until it's created. Is that correct?

    In that case, you can have your objects get a reference to the player or Experience script when they first start.

    Assuming there's only one object with the Experience script somewhere in the scene (your player probably?) you can do something like this:
    Code (CSharp):
    1. public class Example : MonoBehaviour {
    2.  
    3.     Experience playerExperience;
    4.  
    5.     private void Awake() {
    6.         playerExperience = FindObjectOfType<Experience>();
    7.     }
    8. }
    If this example script was say, the Enemy script, then the enemy would be able to find the Experience script in the scene when it first initializes and use it throughout.

    You could alternatively get a reference to the Player object or script, and then do a GetComponent<Experience>();
     
    AndyGainey and DarkBladeNemo like this.
  5. DarkBladeNemo

    DarkBladeNemo

    Joined:
    Aug 23, 2013
    Posts:
    116
    The reason I want to access the script without attaching it to a game object is because my enemies are not in the scene at the start so the game object the experience is attached to needs to be made into a prefab. Now the issue with that is whenever I gain experience the prefab in the project tab gets updated but not the one in the scene which I don't understand why its doing that.

    So I figured why not call it directly from the project tab and just modify it from there. I hope I explained this properly.

    EDIT: Also it doesn't call the update function once the currentExp is more than expNeeded so the level up isn't happening. But because that's not happening the script is also not resetting so if you stop and play again you would insta level and the cycle starts all over.
     
  6. DarkBladeNemo

    DarkBladeNemo

    Joined:
    Aug 23, 2013
    Posts:
    116
    Thank you jeffreyschoch!! So I just applied my experience script to an empty without the prefab and callout it from my other scripts and it work perfectly. Thank you!!
     
    LiterallyJeff likes this.
  7. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,802
    Prefabs are just assets in your project files, they don't actually exist in the scene. They act as blueprints to create copies from. Instantiating a prefab makes a copy of it into the scene. Dragging your prefab into the scene in the editor is the same thing as Instantiating it at runtime, it makes a copy of it. Altering the new copy doesn't affect the prefab unless you use the Apply button in the editor.
     
  8. DarkBladeNemo

    DarkBladeNemo

    Joined:
    Aug 23, 2013
    Posts:
    116
    Exactly and that's why I was finding it so strange that it was acting that way. But using the example you gave me fixed it.
     
    LiterallyJeff likes this.
  9. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    897
    Your enemies were storing a reference to the blueprint, not the instance, so when the enemies updated the experience it was updated on the blueprint (prefab) not the instance.
     
    DarkBladeNemo likes this.
  10. DarkBladeNemo

    DarkBladeNemo

    Joined:
    Aug 23, 2013
    Posts:
    116
    Now that makes sense :/
     
  11. phocker

    phocker

    Joined:
    Sep 12, 2010
    Posts:
    57
    You could also setup an Event or Delegate system (there are many examples out there) - and then your GO could "listen" for things to react to. This is a much better solution instead of doing a full object search in your scene which may be expensive during run time.

    Here is a post on using a Type Driven event system. The one I use is based off of this. Because it is Type Driven you can pass a reference to the object that sent the event. In essence the "script" that your object is attached too.

    http://www.willrmiller.com/?p=87

    Good Luck

    Paul
     
    Fabian-Haquin likes this.
  12. Fabian-Haquin

    Fabian-Haquin

    Joined:
    Dec 3, 2012
    Posts:
    231
    Yes, static keyword is not const keyword.

    A static var is just like a regular var but it share the same value for all instances of his class.

    If in your enemies class, the health is declared as static, damaging one enemy will apply to all enemies.

    using const keyword is for var that will never change.

    Static keyword is very useful for classes that you would only instance once or generic functions that return something.

    For example when you use Vector3.Lerp() or Mathf.Sin(), Lerp is a static function of Vector3 because you can directly call Vector3 instead of declaring a Vector3 var then call the var.

    https://msdn.microsoft.com/en-us/library/98f28cdx.aspx
     
    Last edited: Dec 8, 2016