Call a script from another one.

Good afternoon everyone !

I wanted to create an event that call a script according to a music. The concept is simple. At x:xx of the music, I want to see this event.

I linked the script to the Camera because I want to display the time on the screen with GUI. At the same time, I call an AudioSource (to get the time of the music) so I also linked the audiosource to the camera.

Lastly, when the time hits a certain point, I want to play “Thunder”. It’s an anim that goes from transparant to white with sounds. I don’t think I add another audioSource to my camera, so my idea was to add the audio source to the UI layer and call both the animation and the audio when I’d like to.

Here is the code I have so far:

public class Time_Music : MonoBehaviour {

    AudioSource audio;
    int time;
    int min;
    int seconds;
    bool thunder = false;
  

    void Start () {
        audio = GetComponent<AudioSource>();
    }
   

       void Update () {

        time = 277 - (int) audio.time;
        min = time / 60;
        seconds = time - (min * 60);

        if (min == 3 && seconds == 57)
        {

           Play Thunder anim + sound
         
        }

    }

    private void OnGUI()
    {
        GUI.Label(new Rect(1500,50,1100,1100), "Halsey - Castle");
        GUI.Label(new Rect(1530, 70, 1100, 1100), min.ToString());
        GUI.Label(new Rect(1540, 70, 1100, 1100), ":");
        if (seconds >= 10)
            GUI.Label(new Rect(1545, 70, 1100, 1100), seconds.ToString());
        else
        {
            GUI.Label(new Rect(1545, 70, 1100, 1100), "0");
            GUI.Label(new Rect(1553, 70, 1100, 1100), seconds.ToString());

        }
    }
}

I sadly don’t know what do to in the “if” statement. I setted up a bool variable for the animation. I would like to say “if” conditions, then setbool → true, and that will start the script of “thunder”. Sadly, I don’t know how to make unity understand I refer to this variable if I didn’t call it.

I’ve read few things about Coroutine, but as the “if” statement is in Update, I cannot start the coroutine right away.

Finaly, I thought about creating a variable that will lead to the coroutine. However, I don’t know what behaviour should have the IENumerator function I will call for the coroutine…

I am quite lost with all the documentation I’ve read and few tutorials that I’ve seen. I think I would be able to do it if it was a collision(IENumerator OnCollisionEnter()), but as is it timers… I don’t know how to proceed.

Thank you very much for your help !

Here is the script i have for thunder:

public class Thunder : MonoBehaviour {

    Animator anim;
    bool play = false;
    AudioSource audio;
    // Use this for initialization
    void Start()
    {
        anim = GetComponent<Animator>();
        audio = GetComponent<AudioSource>();
    }


    public IEnumerator PlayThunder()
    {
        play = true;
        anim.SetBool("play",true);
        audio.Play(2);

        while (play)
            yield return null;
       
    }


    void AnimationComplete()
    {
       anim.SetBool("play",false);
        play = false;
    }

PS: I’d like to call Thunder many times. The first one will be with the music. The second one will be when the character arrives at a certain place (so collision will work well here). I’d like to make sure my thunder script works well in both situation.

LOOOOVE <3

You can allready call a script from an other one :smile:

AudioSource audio;
audio = GetComponent<AudioSource>();
audio.Play(2);

the scripts are components too, do the same with them. If you will acces from Time_Music to Thunder:

  1. You need gameobject, where the Thunder is:
    as option,
public GameObject objectWithThunder;

later you can get access on its components with GetComponent,

objectWithThunder.GetComponent <Thunder>().

and then you can see in your editor what you can do with them.

do you need this update with time ? Maybe just start delayed funktion with invoke (if you will play it once at defined time) ?
https://docs.unity3d.com/ScriptReference/MonoBehaviour.Invoke.html

can you just play thunder sound with playclip ?

And you can make Thunder as prefab. Put all audio and animation in the Start() and later Instatiate it in the scene at needed time from the other scripts (+selfdestruction if played).

I think I miss the point with objectWithThunder.GetComponent <Thunder>().

My object has audio source + anim. So if I call the object it would be:

public GameObject Thunder;
    AudioSource audio;
    Animator anim;

and then, perhaps ?

 Thunder.GetComponent<Thunder>();
        audio.GetComponent<Thunder>();
        anim.GetComponent<Thunder>();

the result would be that I can play with anim and audio without changing scripts… But it would be too simple xD

What happens once I call :

Thunder.GetComponent<Thunder>();

According to what you said, I can access to its component (AudioSource, Animator, etc…). How do I call them ?

Secondly I tried to use PlayClip but I don’t know how to call a specific AudioSource when my object has 2…

Finally, I like the prefab idea but sadly I don’t know how to use them in scripts… :frowning:

I just recently started learning C# without any computing background so everything is still confusing for me. I try to look at the doc as much as I could but I know what there is more than a hundred ways to solve a problem. Thank you for helping me !

my GameObject is named Thunder, but according to my understandting, I can call its component without using the Script I wrotte for it. Does that mean that I will have to attach Time_Music to both the Camera and Thunder ?

Moreover, if I do so, when I’ll call .GetComponent(); Does the script knows I will refer to the AudioSource from the camera and not the GameObject thunder ?

If not, does that mean I can use the components from the GameObject Thunder without attaching the script to it ?

yes, many things are simple, you are trying to do it hard :sweat_smile:

You have gameobject with name Thunder and script with name Thunder on it, I will rename Thunder object to BigThunder, so you will see the difference: And yes, you can access on other component on other object without attaching the script

//put your Thunder gameobject (BigThunder here)
public GameObject BigThunder;
//add line with reference variable for script Thunder
Thunder thunder;
Animator anim;
AudioSource audio;

void Start () {
//link all to Thunder(BigThunder) components
audio = BigThunder.GetComponent <AudioSource>();
anim = BigThunder.GetComponent <Animator>();
thunder = BigThunder.GetComponent <Thunder> ();
}

void WhatEverFunktion () {
//as example, you will change play in Thunder script. Dont forget, the play should be public in Thunder
//public bool play = false;
thunder.play = true;
//or you will change bool in Thunder(BigThunder) animator
anim.SetBool ("Play", false);
}

do you need 2 sounds at one time from one object or you are speaking about 2 audioclips for one audiosource ?
Audiosource is just player for your clips.

And for playclipatpoint you should not manually create the audiosource. You call the funktion, says what clip and where it should play and this funktion will make new object(with attached audiosource), which will play once the clip and then destroy itself.

thank you that helps a lot ! I can’t help but notice that my thunder script doesn’t work itself so I doing the Time_Music script doesn’t make sense already.

I don’t understand something. In the Unity doc, they say:

 public Start(){ 

AudioSource audio = GetComponent<AudioSource>();
audio.Play();
}

I do

AudioSource thunder_sound;
  

    // Use this for initialization
    public void Start()
    {
        thunder_sound = GetComponent<AudioSource>();
        anim = GetComponent<Animator>();
    }

    public void Update()
    {

        if (play == true)
        {
        anim.SetBool("play", true);
        thunder_sound.Play(100);
        }
    }
    }

The anim works well but the sound doesn’t come… the sounds only works when

 public void Start()
    {
        AudioSource thunder_sound = GetComponent<AudioSource>();
thunder_sounds.Play();
}

Why ?

try set boolean to false.
anim.SetBool(“play”, true);
thunder_sound.Play(100);
play = false;
I think, audiosource is trying to play every new frame. And be sure, that play will not switch to true again in next time, befor the clip was played.

when the Thunder script will be fixed, I’ll do the “thunder.play = true;”

I am only testing the Thunder script now

       play = true;
    }

    public void Update()
    {

        anim.SetBool("play", true);
        if (play == true)
        {
            thunder_sound.Play(100);
        }
        play = false;
       }

Like that it should work because play will be false for every frame but the first.

Still doesn’t work :frowning:

Got it !

okay, now that my “thunder Script” works well when I initialize play to true in the Start. I want to now initialize play from Time_Music. For that, I : initialize the variable to false in my start() of the Thunder script and then use “thunder.play = true” in my Time_Music right ?

Something like that:

void Start(){
thunderstrikeplay = true;}

void Update{
   if (min == 4 && seconds == 32 && thunderstrikeplay == true)
        {
            thunder.play = true;
            thunderstrikeplay = false;

        }
}

and

    public void Start()
    {
        thunder_sound = GetComponent<AudioSource>();
        anim = GetComponent<Animator>();
      
    }

    public void Update()
    {

        if (play == true)
        {
            ThunderStrike();
        }
 
      
    }

    public void ThunderStrike ()
    {
        anim.SetBool("play", true);
        thunder_sound.Play(100);
        play = false;
    }

It should be good, right ?

Should I yield the script Time_Music while the script Thunder is played ? To let the anim time and music to play, instead of refreshing every frame ??

It is your script :smile:
Ok, I think it is not really cpu friendly and you can do some things better. But you are doing good :roll_eyes:

You can try to call ThunderStrike () directly from the first script, thunder.ThunderStrike (); Maybe then you don’t need boolean play in update.

and if you know the time to start in first script, then you can try with delayed funktion

void Start (){
Invoke ("ThunderStrikePlay", 272);
}

void ThunderStrikePlay () {
thunder.ThunderStrike ();
}

I found the answer.

For the Thunder Script.

public static class GlobalVariables
{
    public static bool play;
}

public class Thunder : MonoBehaviour {

    Animator anim;
    AudioSource thunder_sound;

  

    // Use this for initialization
    public void Start()
    {
        thunder_sound = GetComponent<AudioSource>();
        anim = GetComponent<Animator>();
          
    }

    public void Update()
    {
        if (GlobalVariables.play == true)
        {
            anim.SetBool("play", true);

            thunder_sound.Play(100);
            GlobalVariables.play = false;
        }
 
    }

For the Time_Music Script

 if (min == 4 && seconds == 32 && thunderstrikeplay == true)
        {
            //Play variable from Thunder script
            GlobalVariables.play = true;
            //Play variable from Camera script (so the script don't load every frame in the seconds = 32)
           thunderstrikeplay = false;
        }
    }

At first I wanted to create a function (ThunderStrike()) that I will call everytime I need it… But I don’t know how to make them lol so I tried something else…

Tbh, I don’t understand why using the “public static class GlobalVariable” works as do exactly the same thing with “Thunder.play = true”…

But it works !!

Btw, thank you for teaching me about Global variables. I didn’t know they had different proprieties than the private ones. At first I was doing

public class Thunder : MonoBehaviour {

    Animator anim;
   public bool play = true;

void Start(){etc....}

but that kind of initialisation doesn’t work with public variables.

It works so well now :') I am sooo happy ! Ty so much

this is not exactly the same with static variables. You can access on global static variable from every script ( if I am not wrong, I did not using them much). I think, you can declare public static variable (play, as example) and then just use it in every script as play. And if you change it in one script, then the variable will be changed in all scripts. So static are shared variables.

Good, have fun with unity :smile: