Search Unity

Referencing a bool from a different script. [Solved]

Discussion in 'Scripting' started by Joe_27, Feb 12, 2019.

  1. Joe_27

    Joe_27

    Joined:
    Jan 12, 2019
    Posts:
    12
    I'm very new to Unity and code. I have a prefab projectile with a script attached called "Bullet". In that script there is a public bool called "stuck".

    When the projectile hits a surface stuck = true. Otherwise stuck = false.

    Script 1: The Bullet Script. This script works perfectly. I can see in the inspector on my prefab that stuck is checked or unchecked when it's on a wall, or not on a wall. I just want to use this bool information in a different script. But I can't figure out how.

    Code (CSharp):
    1.  
    2.  
    3. public class Bullet : MonoBehaviour
    4.  
    5. {
    6.  
    7. public bool stuck = false;
    8.  
    9. void Start()
    10.  
    11. {
    12.  
    13. stuck = false;
    14.  
    15. }
    16.  
    17. private void OnCollisionEnter2D(Collision2D collision)
    18.  
    19.     {
    20.  
    21.         if (collision.collider.CompareTag("Ground") || (collision.collider.CompareTag("Wall")))
    22.  
    23.         {
    24.                  
    25.             rb.velocity = new Vector2(0, 0);
    26.             rb.angularVelocity = 0;
    27.  
    28.             stuck = true;
    29. }
    30.  
    31. }
    32.  
    33.  
    Script 2: My PlayerController.

    This is where I want to know if my Prefab is stuck or not. I can't get it to trigger the Debug.Log... And it jams up my controls for some reason.

    Code (CSharp):
    1. public class PlayerController : MonoBehaviour
    2. {
    3.  
    4. public Bullet bullet;
    5.  
    6. void Start()
    7. {
    8.  
    9. bullet = GetComponent<Bullet>();
    10.  
    11. }
    12.  
    13. void Update()
    14. {
    15.  
    16. if (bullet.stuck == true)
    17. {
    18. Debug.Log("It's stuck")
    19.  
    20. {
    21.  
    22. }
    it recognizes the stuck from the other script. bullet.stuck isn't throwing any errors, but it won't actually let me know when it's stuck or not.

    Referencing other scripts works for other things I've done, but this bool is stubborn. I think it's because it's attached to a prefab and there's something strange about prefabs. But I don't know why that's a problem, and I don't know where to go from here.

    I will really appreciate if someone can point out where I've gone wrong.
     
  2. Joe_27

    Joe_27

    Joined:
    Jan 12, 2019
    Posts:
    12
    From everything I've seen online this should be working. But something isn't right and I'm too inexperienced to see what it is.

    In the second script:

    public Bullet bullet;

    void Start()
    {
    bullet = GetComponent<Bullet>();
    }

    void Update
    {
    if (bullet.stuck == true)
    { Debug.Log("stuck") }
    }

    But all I get is a "Object reference not set to an instance of an object"

    And it removes my prefab from the Bullet slot on start. I know it's not a very complicated problem and I'm missing something obvious. This exact same set up works on my other scripts. But this one is jammed. It's cost me my entire night so far and I'm pretty discouraged.
     
  3. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    In the player script when you say GetComponent it looks for the object on the same object that the script is on, you have GetComponentInParents to find components in parents, GetComponentInChildren to find components on the childs of the objects.

    I assume though that the bullet isn't attached to the player?
    If you have only one bullet you can do FindObjectOfType, or FindObjectsOfType to get an array of all the object.
    this will get all active game objects with a components called Bullet on it (of whatever you put in the <Type> ).
    *note that this function is relatively slow and should be used like you did in Start and not in Update
     
    Joe_27 likes this.
  4. Joe_27

    Joe_27

    Joined:
    Jan 12, 2019
    Posts:
    12
    Thanks for responding.

    The object is instantiated when I press a button, it flies around doing it's thing, if it hits a wall it gets stuck and it's script actives a bool (stuck = true). I can recall it when I press a button. When it's not in a wall the bool switches to false (stuck = false). I can see all of this happening on the objects inspector, so I know the bool itself is working. The information is there. I just need that information to register within my player controller script. The object is destroyed when it comes back to the player.

    Right now I only allow one to exist at a time. I have it tagged as "Projectile" and I use this tag in a MoveTowards command within my player controller.

    I'm just trying to limit the MoveTowards to only function when the object is stuck in a wall.

    I basically want "&& stuck == true" at the end of my MoveTowards command within my player controller. I don't want to MoveTowards the object unless it's stuck in a wall. Right now I can MoveTowards the Instantiated object whenever it exists.

    If you have only one bullet you can do FindObjectOfType, or FindObject[B]s[/B]OfType to get an array of all the object.
    this will get all active game objects with a components called Bullet on it (of whatever you put in the <Type> ).
    *note that this function is relatively slow and should be used like you did in Start and not in Update


    I'll mess around with FindObjectOfType in Start function when I get home.

    I appreciate the help.
     
  5. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    FindObjectsOfType should work, but could be slow. You can also just use a static List inside the Bullet class that holds all active bullets. This already supports multiple bullets. In Bullet:
    Code (csharp):
    1. public static List<Bullet> bullets = new List<Bullet>();
    2.  
    3. Start
    4. {
    5.     bullets.Add(this);
    6. }
    7.  
    8. public void Destroy()
    9. {
    10.     bullets.Remove(this);
    11.     Destroy(this);
    12. }
    Elsewhere:
    Code (csharp):
    1. foreach (Bullet bullet in Bullet.bullets)
    2. {
    3.     // Do something
    4. }
    Oh, and:
    Code (csharp):
    1. if (bullet.stuck == true)
    Is the same as:
    Code (csharp):
    1. if (bullet.stuck)
    This last way always makes more sense to me. Reads like a sentence.
     
    Joe_27 likes this.
  6. Joe_27

    Joe_27

    Joined:
    Jan 12, 2019
    Posts:
    12
    Thanks jvo3dc,

    That static List idea sounds interesting but I've never used static lists so I'm not sure how to implement that exactly. I'll trial and error my way through it later today. Hopefully it helps.

    On the surface it seems like an incredibly straight forward thing to implement.

    if (Bool from <ScriptB> is true)

    { Debug.Log("This is ScriptA, ScriptB called an told me it's true, I'll do that thing now") }

    else if (Bool from <ScriptB> is false)

    { Debug.Log("This is ScriptA, ScriptB called an told me it's now false, I can't do that thing anymore..") }

    But somehow this has me stuck more than anything else I've come across.

    Thanks for all the help so far. I'll get it eventually.
     
  7. simonlvschal

    simonlvschal

    Joined:
    Nov 17, 2015
    Posts:
    266
    never use static lists... its a bad idea. what you're trying to do is to get a component on nothing. unless Bullet exist on the object that the playercontroller also exist on.

    if Bullet does not exist on the same object as the playercontroller it wont find the object.

    what you need to do is to have a bullet object pool that allows you to enable and disable the correct bullets when required. or unstuck them etc. this is a simple script that you put on either the player or another manager.

    but since your not to experienced from what i can see lets go the simple route.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class BulletPool : MonoBehaviour
    6. {
    7.     public Transform bulletPrefab; // the prefab that we wish to use to create copies from,
    8.     //note this is not something we can use to check against since it will never be instantiated. but we will have a collection of the instantiated transforms
    9.  
    10.     public int amount; // the amount of bullets we wish to create and observe
    11.  
    12.     protected Bullet[] bullets;
    13.  
    14.     public void CreateBullets()
    15.     {
    16.         bullets = new Bullet[amount];
    17.         for (int i = 0; i < bullets.Length; i++)
    18.         {
    19.             Transform tempBullet = Instantiate(bulletPrefab);
    20.             bullets[i] = tempBullet.GetComponent<Bullet>();
    21.             bullets[i].gameObject.SetActive(false); // we have to deactivate them all.
    22.  
    23.             // In here you can set the parameters of what the bullet will do dmg,speed etc by using bullets[i]
    24.         }
    25.  
    26.     }
    27.  
    28.     public void EnableBullet() // this can be used in a contiounes fire method or a single fire method.
    29.     {
    30.         for (int i = 0; i < bullets.Length; i++)
    31.         {
    32.             if (!bullets[i].gameObject.activeInHierarchy)
    33.             {
    34.                 bullets[i].gameObject.SetActive(true);
    35.                 break; // we have to break otherwise it would enable all bullets that are not current active. this also means it just gets the first bullet that is not active
    36.             }
    37.         }
    38.     }
    39.  
    40.     public void DisableBullet(Bullet bullet) // this should be used when you want a bullet to dissapear !! Note Do not delete the bullets. just call this method. Note ! it takes in a bullet
    41.     {
    42.         bullet.gameObject.SetActive(false);
    43.     }
    44.  
    45.  
    46.     // disable a bullet could be called from the Bullet it self when it collides with a object simple said just use DisableBullet(this); note you can only use this from the bullet class it self
    47. }
    48.  
    also it should be the bullet itself that says its stuck. not the player. since the player has no access to the bullets.

    also never use GetComponent or any find methods inside update. it will degrade performence by ALOT. the same goes for FindObjectOfType etc. its always more viable to go with a collection or some sort of reference design.
     
  8. Joe_27

    Joe_27

    Joined:
    Jan 12, 2019
    Posts:
    12
    Thanks simonlvchal!

    I got it working by just reversing everything. I put a bool in my Playercontroller and set that depending on information from Bullet script, instead of the other way around.

    I just put FindObjectOfType<PlayerController>(); in the Start function of my Bullet script.

    Then I created a bool in the PlayerController and set it to true or false from the Bullet script when it collided with the wall.

    For some reason Bullet to PlayerController works perfectly, but the exact same thing from PlayerController to Bullet never worked.

    Thank you to everyone that answered my cry for help.
     
  9. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    How is that? A static item exists without an instance reference, so it will work fine without any instance attached to the same gameobject. I think it depends on your serialization/storage needs. If there are bullets in the scene by start, you want to use an object pool in a MonoBehaviour. If they are strictly generated in runtime, I'd say a static solution is simpler.

    (I do of course agree with the pool and/or the bullets handling the bullet states. Not some external player script.)
     
    SparrowGS likes this.
  10. simonlvschal

    simonlvschal

    Joined:
    Nov 17, 2015
    Posts:
    266
    no one actually talked about static methods or varibles here. its generally a bad idea to have global access to something.