1

Issue

I'm trying to make a bubble/balloon popper style game and have a Spawner script (Spawner.cs) which holds a pool of objects (bubbles), this Spawner script then selects, at random, one of the objects that's in the pool.

From here another script (Bubble.cs), which is attached to all of the bubbles in the pool, is supposed to check the Spawner script to see which bubble from the pool is currently selected as the safeBubble. If this bubble matches the current safeBubble then the bubble should change it's tag to "Safe", if it doesn't match the safeBubble then it's tag should be "Bad".

It seems that the Bubble.cs does check and set initially (when I first hit play) but only then, they don't de-set/ re-check after that first safeBubble is chosen, like it should.

The idea being that the safeBubble changes at random intervals and thus the tags on the active/spawned bubbles should change to reflect whether they are "Safe" or "Bad".


Code & What I've tried

Here are my scripts, the only script not provided is the GM.cs but that's just the score manager.

Bubble.cs

  public class Bubble : MonoBehaviour{

  public Spawner spawner;

  public float popPoint = 10f;
  public float spinSpeed;
    public float riseSpeed;

  public AudioSource popAudio;

  public bool safe;

    void Start(){
      transform.name = transform.name.Replace("(Clone)","").Trim();
      riseSpeed= Random.Range(0.05f, 0.1f);
      spinSpeed= Random.Range(0.1f, 0.5f);

      if (this.gameObject == spawner.safeBubble) {
        this.tag ="Safe";
      } else{
        this.tag ="Bad";
      }
    }

    void Update(){
      if ( this.gameObject == spawner.safeBubble ){
        this.tag ="Safe";
      } else {
        this.tag ="Bad"; 
      }

      transform.Translate (Vector3.up * riseSpeed, Space.World);
        transform.Rotate (Vector3.right * 2* Time.deltaTime);
        transform.Rotate (Vector3.up * spinSpeed* Time.deltaTime);

        if(gameObject.transform.position.y >= popPoint ){
            gameObject.SetActive(false);
        }
    }

}

Spawner.cs

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

public class Spawner : MonoBehaviour{
  public int index;
  public int randomIndex;

  public List<GameObject>[] pool;
  public GameObject[] bubbles;

  public GameObject greenBubble;
  public GameObject orangeBubble;
  public GameObject pinkBubble;
  public GameObject purpleBubble;
  public GameObject redBubble;
  public GameObject blueBubble;

  public GameObject safeBubble;

  public float timeBetweenSpawns;
  public float speed = 1.0f;

  public float swapTime;
  public Transform spawnLoc;

  public Vector3 Position1;
  public Vector3 Position2;

  public Image BubbleToPopImg;
    public Sprite green;
    public Sprite orange;
    public Sprite pink;
    public Sprite purple;
    public Sprite red;
    public Sprite blue;

  public bool willGrow = true;

  void Awake(){
        bubbles = new GameObject[6];
        bubbles [0] = greenBubble;
        bubbles [1] = orangeBubble;
        bubbles [2] = pinkBubble;
        bubbles [3] = purpleBubble;
        bubbles [4] = redBubble;
        bubbles [5] = blueBubble;



        safeBubble = bubbles[Random.Range(0, 5)];

        swapTime = Random.Range (2f,3f);
        // Randomiser ();

        timeBetweenSpawns = Random.Range (0.6f,1.2f);

        InvokeRepeating ("Spawn", 1f, timeBetweenSpawns);

        pool = new List<GameObject>[bubbles.Length];
        for (int i = 0; i < bubbles.Length; i++){
            pool[i] = new List<GameObject>();
        }
    // Debug.Log("Safe Bubble is " + safeBubble);

    }


  public GameObject GetPooledObject(){

        randomIndex = Random.Range(0, pool.Length);

        for (int i = 0; i < pool[randomIndex].Count; i++){
            GameObject go = pool[randomIndex][i];
            if (!go.activeInHierarchy){
                return go;
            }
        }

        if (willGrow){
            GameObject obj = (GameObject)Instantiate(bubbles[randomIndex]);
            pool[randomIndex].Add(obj);
            return obj;
        }
        return null;
    }


  public void Spawn(){
        GameObject bubbles = GetPooledObject ();
        if(bubbles != null){
            bubbles.transform.position = spawnLoc.transform.position;
            bubbles.transform.rotation = spawnLoc.transform.rotation;
            bubbles.SetActive(true);
        }

    }


  void Update(){
        transform.position = Vector3.Lerp (Position1, Position2, Mathf.PingPong(Time.time*speed, 1.0f));
    timeBetweenSpawns -= Time.deltaTime;
    swapTime -= Time.deltaTime;

        if(timeBetweenSpawns<=0){
            timeBetweenSpawns = Random.Range (0.6f,1.1f);
        }

        if(swapTime <= 0){
            Randomiser ();
            swapTime = Random.Range (3f,6f);
        }


     switch(index){
        case 5: BubbleToPopImg.sprite = blue; break;
        case 4: BubbleToPopImg.sprite = red; break;
        case 3: BubbleToPopImg.sprite = purple; break;
        case 2: BubbleToPopImg.sprite = pink; break;
        case 1: BubbleToPopImg.sprite = orange; break;
        case 0: BubbleToPopImg.sprite = green; break;
      }

    }

  public void Randomiser(){
        index = randomIndex;
        safeBubble = bubbles[index];
    // Debug.Log("Safe Bubble is " + safeBubble);
    }

}

Popper.cs

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

public class Popper : MonoBehaviour{

    public GM gm;

    void Update(){
      if (Input.GetMouseButtonDown(0)) {
        Shoot();
      }
    }

    void Shoot(){
      RaycastHit hit;
      Ray ray = GetComponent<Camera>().ScreenPointToRay(Input.mousePosition);
      if (Physics.Raycast(ray, out hit)) {

        if(hit.collider.tag == "Bad"){
            Debug.Log("Ouch");
        }
        
        if(hit.collider.tag == "Safe"){
            Debug.Log("Nice");
        }
        
      }
      
    }
    
}

I though that a simple if statement to set and check the tag in both the Start and Update functions of the Bubble.cs would work but it doesn't and I'm just not managing to figure it out. I've also tried using a switch, but it has the same result.


Any Help is greatly appreciated.

Thanks in advance.

Twisted
  • 59
  • 7

2 Answers2

2

In

this.gameObject == spawner.safeBubble

you check if an existing object is equal to your Prefab.

This will of course Never be true!


Instead simply set the tag on the prefab as soon as you selected it

 // Note that here was another mistake: The maxValue is EXCLUSIVE
 // so Random.Range(0,5) returns the values 0 to 4!
 // rather simply use the length of the array
 safeBubble = bubbles[Random.Range(0, bubbles.Length)];
 foreach(var bubble in bubbles)
 {
     bubble.tag = bubble == safeBubble ? "Safe" : "Bad";
 }

This way everytime you Instantiate according prefabs the tag is already set correctly and there is no need to do this later from the bubble itself.

derHugo
  • 83,094
  • 9
  • 75
  • 115
  • This did the trick. I totally didn't realise my mistake and have added .ToString() to both the `this.gameObject` and to the `spawner.safeBubble` so it now reads `this.gameObject.ToString() == spawner.safeBubble.ToString()` and used the snippet you provided. Thank you for the assistance – Twisted Jul 31 '21 at 15:27
  • `gameObject.ToString()` basically equals `gameObject.name` .. it won't work since objects created via `Instantiate` always get the postfix `(Clone)` added to their name – derHugo Jul 31 '21 at 15:41
  • It's working fine and dandy, I have a snippet that removes the clone postfix but I'll change it to .name as it's less verbose. Thanks again. – Twisted Jul 31 '21 at 18:43
2

You can add a function(public) in bubble.cs that switches the variable safe of your bubble script and then call it from spawner.cs after assigning the safebubble(you will also have to call it before assigning the next time).

So, add this in bubble.cs

public void changestate()
{
safe = !safe ;
if (safe) this.Tag = "Safe";
else this.Tag = "Bad";
}

Note: I recommend changing 'this' to 'gameObject' in the above script.

Now, in Spawner.cs, after assigning the safebubble, you can do this..

safebubble.GetComponent<Bubble>().changestate();

And you should do the same thing before changing the safebubble to switch it back to bad.

In my opinion, using code like this which does not use the update function is good for performance.

I hope understood it and found it helpful.

Extra: If you are confused with the first code, you can do this..

public void makesafe() {this.Tag = "Safe";}
public void makebad() {this.Tag = "Bad";}

And Then you can use them in spawner like this..

safebubble = bubbles[Random.Range(0, 5)];
safebubble.GetComponent<Bubble>().makesafe();

And the randomizer function should be like this..

public void Randomizer()
{
    if (safebubble != null) safebubble.GetComponent<Bubble>().makebad();
    index = randomindex;
    safebubble = bubbles[randomindex];
    safebubble.GetComponent<Bubble>().makesafe();

}

Sorry for the bad explanation.