0

I'm making a new game in Unity and I'm stuck in my script. I'm really noob in C# scripting. I'm already looking for all information but no luck. The game is very simple, it is 2D game where need just click on bubbles and they are rotating when are clicked. I will describe what I exactly need to create. I need a script when all objects are clicked then scene automatically changes to the next level + I need it to have a timeline, for example, for each level have 30 seconds to click all bubbles, when the time is over the game is over and a window pops up with a message "Game Over" and you can press the Reply and Exit buttons. I really hope that someone helps me. Thanks!

P.S. This is my script now for my gameObjects:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class pop : MonoBehaviour
{
    public AudioClip sound;
    AudioSource audio;


    // Start is called before the first frame update
    void Start()
    {
        audio = GetComponent<AudioSource>();
        

    }

    // Update is called once per frame
    void Update()
    {
        
    }

    bool wasClicked = false;


    private void OnMouseDown()
    {
        if (!wasClicked)
        {
            wasClicked = true;
            transform.Rotate(0, 0, 180);
            audio.PlayOneShot(sound);
  
        }

    }


}
Toto
  • 89,455
  • 62
  • 89
  • 125
  • 1
    It seems to me relatively little as a script. In my opinion you should create these bubbles from the script (perhaps with a prefab) so that you can save a reference of them. When you click on a bubble you activate a method and destroy/disable its reference. At that point you create an update method in which you ask yourself if there are still existing bubbles (with existing references), and next to it (always in the update) you ask yourself how much is missing from the inserted timeline. – Francesco - FL Jul 29 '21 at 12:59

1 Answers1

0

You should separate these.

I would have a central manager for the scene change like e.g.

public class Manager : MonoBehaviour
{
    [SerializeField] private float timer = 30;

    private void Awake ()
    {
        // Register to an event we will add which is fired everytime 
        // a pop was clicked
        pop.onClicked += PopClicked;
    }

    private void OnDestroy ()
    {
        // Don't forget to remove the callback as soon as not needed anymore
        pop.onClicked -= PopClicked;
    }

    private void PopClicked ()
    {
        // Check if there is no Unclicked pop remaining
        if(pop.Unclicked.Count == 0)
        {
            // if so go to the next scene
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
        }
    }

    private void Update ()
    {
        // Every Frame reduce the timer by the time passed since the last frame
        timer -= Time.deltaTime;
        // Maybe also update a timer display text here

        if(timer <= 0)
        {
            // if it reaches 0 -> GameOver scene
            SceneManager.LoadScene("GameOver");
        }
    }
}

And then modify your Pop class accordingly with some additional things:

public class pop : MonoBehaviour
{
    // Stores all Unclicked instances
    // As this is static it is "shared" between all instances or better said
    // it is part of the type itself 
    private static HashSet<pop> _unclicked = new HashSet<pop>();

    // Public readonly access
    public static HashSet<pop> Unclicked => new HashSet<pop>(_unclicked);

    // Event that is invoked everytime a pop is clicked
    public static event Action onClicked;

    public AudioClip sound;
    [SerializeField] AudioSource audio;

    void Awake()
    {
        if(!audio) audio = GetComponent<AudioSource>();
        
        // Add yourself to the collection of Unclicked instances
        _uncliked.Add(this);
    }

    private void OnDestroy ()
    {
        // Don't forget to also remove in case this is destroyed 
        // e.g. due to the scene change to GameOver
        if(_unclicked.Contains(this)) _unclicked.Remove(this);
    }

    private void OnMouseDown()
    {
        // Is this still Unclicked?
        if (!_unclicked.Contains(this)) return;
        
        transform.Rotate(0, 0, 180);
        audio.PlayOneShot(sound);
 
        // Remove yourself from the Unclicked instances
        _unclicked.Remove(this); 
        // Invoke the event
        onClicked?.Invoke();
    }
}
derHugo
  • 83,094
  • 9
  • 75
  • 115
  • Thanks for the fast replay. Ok, where I need to put the Central manager script? And when I try to edit my pop script I see this errors: *The type or namespace name 'Action' could not be found (are you missing a using directive or an assembly reference?) *The name '_unclicked' does not exist in the current context – Edward Chester Jul 31 '21 at 13:16
  • Ok so `_unclicked` is clearly at the top of my `pop` class here `private static HashSet _unclicked = new HashSet();` make sure you have it and there are no typos in your code. The [`Action`](https://learn.microsoft.com/dotnet/api/system.action) and [`Action`](https://learn.microsoft.com/dotnet/api/system.action-1) are both part of `System` the most basic namespace -> make sure you have `using System;` at the top of your script. Which IDE are you using? Any serious one should automatically hint you towards this ;) – derHugo Jul 31 '21 at 13:56
  • And the manager script goes anywhere in the scene .. you could simply have an empty GameObject which does nothing except running that script – derHugo Jul 31 '21 at 13:56
  • Thanks. :) I added a using System at the top of both scripts, added the Manager script to empty gameObject but now on Manager script shows 8 Errors. *Invalid token '=' in class, struct, or interface member declaration *The name 'timer' does not exist in the current context *Cannot implicitly convert type 'void' to 'System.Action' *'pop' does not contain a definition for 'UnClicked' *The name 'timer' does not exist in the current context – Edward Chester Aug 01 '21 at 09:40
  • I'm using Visual Studio 2019 for coding – Edward Chester Aug 01 '21 at 09:44
  • Those where some typos caused by typing on the phone ^^ first it has to be `private float timer = 30;` instead of `private timer = 30;` and then it is `Unclicked` instead of `UnClicked` and `pop.onClicked += PopClicked;` instead of `pop.onClicked += PopClicked();` ;) ... and you might want to check your VS settings .. my Visual Studio 2019 automatically suggests to add `using System;` if I type `Action` ;) – derHugo Aug 01 '21 at 11:18
  • Thanks a lot, buddy! You are a life saver! :) It's working now! Only sound not working when I pushed on the bubble. No errors on scripts and sound already added in each gameObject AudioClip and pop script Audio Source too! – Edward Chester Aug 01 '21 at 16:25
  • I only see in Unity Debug Console this message: PlayOneShot was called with a null AudioClip. – Edward Chester Aug 01 '21 at 16:42
  • Can you please tell me how to make a timer in my game and when time ends it's shows in GameOver scene a Best time? Tanks a lot for help! – Edward Chester Aug 12 '21 at 16:37
  • `PlayOneShot was called with a null AudioClip` sounds like exactly that is happening ... your `AudioClip` is not referenced the moment `PlayOneShot` is called. For the timer [here](https://stackoverflow.com/questions/32306704/how-to-pass-data-between-scenes-in-unity) you can find tons of answers on how to pass data between scenes ;) a `static` might be the easiest solution for you. Additionally you will also need [Saving and Loading Data](https://stackoverflow.com/questions/40078490/saving-loading-data-in-unity) for having persistent data across multiple app sessions – derHugo Aug 13 '21 at 07:02