I am trying to convert some js code to C# and ran into some difficulties. I am pretty new at this, so this is probably an easy couple answers.
I have a music scrip that I have setup to play music and sounds. In my js script I was able to setup the audio source and audio tracks via the inspector. As I have converted (or trying to) it to C#, I am having issues with Object definition/declaring.
I originally had this:
public static AudioClip[ ] myMusic;
public static AudioSource myMusicSource;
I am able to access this via code such as :
static public IEnumerable SwitchMusic(int hit)
{
myMusicSource.clip = myMusic[hit];
myMusicSource.Play();
…
However, I can’t setup the sources and files via the inspector. I figured this is because of the static declaration, so I set about changing that. Problem is that I now have lots of errors, which I can’t figure out… and the easy part for you guys.
When I set the variable definition to:
public AudioClip[ ] myMusic = new AudioClip[5];
public AudioSource myMusicSource = new AudioSource();
I get a object reference is required for a non-static field on the statements that reference the variable:
myMusicSource.clip = myMusic[hit];
myMusicSource.Play();
How do I fix this part?
Also, How do I get the Audiosource and AudioClip to show up in Inspector so I don’t have to hard code these?
I would probably use a singleton for this situation… Something like the following;
using UnityEngine;
using System.Collections;
public class AudioThingy : MonoBehaviour
{
static AudioThingy _instance;
public AudioClip[] myMusic;
public AudioSource myMusicSource;
public static AudioThingy Instance
{
get
{
return _instance;
}
}
void Start()
{
_instance = new AudioThingy();
}
public void SwitchMusic(int hit)
{
myMusicSource.clip = myMusic[hit];
myMusicSource.Play();
}
}
Then when you want to play a clip, you would use AudioThingy.Instance.SwitchMusic( 0 );
Ok… close… got everything to compile and able to inspect it…
I get this warning when running the program now, and my audio routines don’t get executed.
You are trying to create a MonoBehaviour using the ‘new’ keyword. This is not allowed. MonoBehaviours can only be added using AddComponent(). Alternatively, your script can inherit from ScriptableObject or no base class at all
Any thoughts?
Also, do I need a : DontDestroyOnLoad(this);
in the start function to keep this visible?
I finally got this to work.
I had to change this from a MonoBehavior to get rid of the warning message. I also had timing issues in when this was called as other scripts attached to the game object seemed to be calling it before it was created. I put the following code in to check that.
public static SoundEvent Instance
{
get
{
if (_instance == null)
{
_instance = new SoundEvent();
return _instance;
}
else
{
return _instance;
}
}
}
void Awake()
{
if (_instance != null)
{
_instance = new SoundEvent();
}
Edit---------------------
ok, well I thought this would work. When I call my sound event routines:
SoundEvent.Instance.SwitchMusic(0);
Nothing happens… It doesn’t even go into the script… just seems to skip over it.
Sorry about the script before, still kinda new to Unity and forgot that you can’t instantiate MonoBehaviour objects…
I modified the script a little, should actually work this time…
Someone with a bit more Unity experience may be able to do this a better way, but basically you create a Unity GameObject and add the AudioInitializer script to it. This script has public variables for the AudioSource and the AudioClips, this way you can assign them through the inspector.
The AudioSystem class, which is a singleton, gets automatically created the first time you use AudioSystem.instance. This class just holds a reference to the AudioClips, and because it’s a singleton you can use it from anywhere in your code.
using UnityEngine;
using System.Collections;
public class AudioInitializer : MonoBehaviour
{
public AudioClip[] myMusic;
public AudioSource myMusicSource;
void Awake()
{
DontDestroyOnLoad( this );
AudioSystem.Instance.myMusic = myMusic;
AudioSystem.Instance.myMusicSource = myMusicSource;
AudioSystem.Instance.SwitchMusic( 0 );
}
}
public class AudioSystem
{
static AudioSystem _instance;
public AudioClip[] myMusic;
public AudioSource myMusicSource;
public static AudioSystem Instance
{
get
{
if( _instance == null )
{
_instance = new AudioSystem();
}
return _instance;
}
}
void Start()
{
_instance = new AudioSystem();
}
public void SwitchMusic( int hit )
{
myMusicSource.clip = myMusic[hit];
myMusicSource.Play();
}
}
I had actually solved this problem, but not the way I wanted. I created a component based singleton, but with that method, I could not use the inspector to setup my music source and clips. I had to create them programmatically because I created a new game object in the instance.
I just tried your method because it seems much cleaner. It still doesn’t work. When I get into the Switchmusic routine, it errors out with “object reference not set to an instance of the object”. It looks like you can’t assign the sources and clips like that… I really want to use your method, as I hate having to go back into the code to add music/sound events.
Ok… Almost got… I forgot to rename the script to the name of the new class you defined. The Awake call was not happening.
The only problem I have now is that it looks like the class gets destroyed when I leave the scene. Since this is not a monobehavior class, I can’t call DontDestroyonLoad. Is there something similar I can call?
Since AudioSystem is not derived from MonoBehehaviour, the Start method will not be called automatically (ie, it’s an ordinary method that just happens to be called “Start”). However, in C# you can use a static initialiser to… guess what… initialise static variables:-
public class AudioSystem {
static AudioSystem() {
// Initialisation code
}
}