Hey guys, the titles says it all, im trying to add an audio clip whenever my character picks up some coins. ive added the audio component to the coins and tried added the code to the character controller. but im having a hard time getting it to work properly... Code (CSharp): public class Playercontroller : MonoBehaviour { public float speed; public Text CoinCounter; public AudioClip Pickup; void OnTriggerEnter (Collider other) { if (other.gameObject.CompareTag ("Coin")) other.gameObject.SetActive (false); count = count + 1; SetCoinCounter (); AudioSource.PlayClipAtPoint (Coin, transform.position); } I came to use this code by searching the unity forums for similar situations as mine, and this one seems the closest even though im pretty sure the original post was in JS and im using C#. lemme know what you guys think!! Thanks! P.S. Whats the command to search unity for a command? i remember high lighting the word. pressing a button and clicking the word and it brings me to the related commands, but i cant remember which button commands it was....
You are playing an AudioClip called Coin but you didn't show where it was declared. Did you mean to play the AudioClip Pickup? P.S. Try: ctrl + '
Switched in to "Pickup" and got this error message when i pick up the coins. everything seems to be functioning other than the sound, in my event system in my hierarchy it says "one shot audio" with every coin i pick up, but doesnt play the sound UnassignedReferenceException: The variable Pickup of Playercontroller has not been assigned. You probably need to assign the Pickup variable of the Playercontroller script in the inspector. UnityEngine.AudioSource.PlayClipAtPoint (UnityEngine.AudioClip clip, Vector3 position, Single volume) (at C:/buildslave/unity/build/artifacts/generated/common/modules/AudioBindings.gen.cs:683) UnityEngine.AudioSource.PlayClipAtPoint (UnityEngine.AudioClip clip, Vector3 position) (at C:/buildslave/unity/build/artifacts/generated/common/modules/AudioBindings.gen.cs:672) Playercontroller.OnTriggerEnter (UnityEngine.Collider other) (at Assets/Scripts/Playercontroller.cs:47) P.S. thats it! EDIT: I really thought I figured it out. I added the sound to the playercontroller in the inspector just like the error message called for, but it still doesnt play the sound. As I got to think about it, I had the realization that my code made the variable of the sound public (which is why its in the inspector) and so every time it comes into contact with a pick up item, it'll play the sound... well thats not what I want. What I want is for the character to call on the OTHER object to play the sound, not rely on its own scripting for it. So basically, I need the character to be able to call on the other object so that it can play different sounds when it comes into contact with different objects in the game.
I guess, you want to access the coin, so every coin needs an audio source where the sound is in. I would prefer a global manager for this coin sound, but if you want to be it 3D and depending on the position of the coin, add a audiosource to the coin prefab and use something like this: Code (CSharp): void OnTriggerEnter (Collider other) { if (other.gameObject.CompareTag ("Coin")) AudioSource otherAudio = other.gameObject.GetComponent<AudioSource>(); otherAudio.PlayOneShot ("YourSound"); other.gameObject.SetActive (false); count = count + 1; SetCoinCounter (); AudioSource.PlayClipAtPoint (Coin, transform.position); }
ewww... I think it would be far more modular to have the coin handle it's side of things, and the player handle it's side of things rather than trying to get the player object do the coins job for it... Code (csharp): // add to coin or anything you want to pickup public void class Collectable : Monobehaviour { public AudioClip pickupSound; public AudioSource audio; public Start() { audio = GetComponent<AudioSource>(); } public void Collected() { audio.PlayClipAtPoint(pickupSound, transform.position); // do animation, whatever } } Code (csharp): void OnTriggerEnter(Collider other) { Collectable oc = other.transform.GetComponent<Collectable>(); if(oc) { oc.Collected(); // do what the player needs to do when they pick something up... } }
Both of those methods make sense to me, but could you walk me through yours? im having a hard time understanding...
as LeftyRighty said, you need to add the first script and the audiosource to your coin and the second script to your player. that's it. Your player handles, if he collected a collectable, and if he did he calls the "Collected" function on the coin.
do i need both audioclip pickup and audiosource audio? it seems to just give me two fields to put the soundclip in on the coin
I'm not sure, what you are asking You need an audiosource component on your coin and you need to put in the clip in the inspector on the audioclip. that should do it
audiosource is the "thing" that plays the sound (the cd player), audioclip is the sound to be played (the track on the cd). The Collectable Start() function will handle the audiosource so long as there is an audiosource component on the same object, you just need to populate the audioclip "slot" in the inspector. (I tend to make everything public so you can see if there are any nulls, you could make the audiosource variable private and the code would still work, and the slot would disappear from the inspector). As for understanding what's going on; the player runs into another gameobject with a trigger collider and a "Collectable" component on it. In that trigger collision it picks up a reference to the collectable class, and tells it "you've been collected" via the "Collected()" function. The player object doesn't need to know anything about the coin, doesn't care if it makes a sound or not, it just carries on doing whatever the player class does. When the "Collectable" component attached to the coin gets told "you've been collected" (i.e. Collected() is called) it uses the attached Audiosource to play the audioclip you've assigned it.
i punched it all into my code with "Public void Collectable" and im calling on "Collectable oc" but it says Collectable does not exist... part of my confusion is im not sure if collectable is the actual code, or just you substitute for that i should be putting in there lol what exactly does "Collectable oc" mean? this is my playercontroller script Code (CSharp): void OnTriggerEnter (Collider other) { Collected oc = other.transform.GetComponent<pickup>(); if (oc) { oc.Collected (); ; if (other.gameObject.CompareTag ("Coin")) other.gameObject.SetActive (false); count = count + 1; SetCoinCounter (); } } This is my Coins script Code (CSharp): public void Collected () { AudioSource.PlayClipAtPoint (pickup, transform.position); }
Collectable above is the entire code to create the "Collectable" component, it's its own script doesn't get put "into" any other scripts. Once you have a c# script called "Collectable" with that code in it saved you should be able to reference it as a type in you're player class script (or anywhere else). If you want it to do more you just add the code in where line 16 has the comment. Collectable oc ... a variable called oc ("o"ther "c"ollectable) of type Collectable.
Right now my coins have a rotator script on them that makes them spin, so if i replace collectable with rotator it should work? IT WORKED! thanks so much for the help!
gameobjects can have as many components attached to them as needed. You can just add collectable as a new component and keep rotator. So long as the two scripts are attempting to manipulate the transform's properties at the same time (i.e. one script turns the gameobject one way and the other script turns it counterwise). Breaking behaviour down into their own little scripts makes the code more reusable.
@LeftyRighty Do you think you could help me make my coins reappear after a set time now? ive been searching the site trying to find a way but i cant seem to find it. I want them to reappear after a Set amount of time of being set to false, but im not sure which keywords to use in my loop.
I think, you need to use SetActive(false); to disable the object, but you need some kind of manager on another active gameobject to SetActive(true); the coin again, as, as far as I know, the script won't execute anymore if your coin is disabled.
there are a few ways of doing this... really depends on what you want to do with the coins. If you want the UI to show something about "coins collected / total coins" you'll probably want to go down the route of a manager script to centralise all that information in one place to make the UI side easier. If you really don't care about the coins beyond them "doing their own thing" I'd probably go down the route of having an empty GameObject as a parent of the coin which can then use SetActive(false) and the parent can use Invoke() to set the child as true again after a while. Code (csharp): using UnityEngine; using System.Collections; public class TriggerChildDisable : MonoBehaviour { public Transform child; // drag the coin child into this slot public float reactivationDelay; public void OnTriggerEnter(Collider other) { Debug.Log(transform.name + " trigger collision with " + other.transform.name); child.gameObject.SetActive(false); Invoke("ReactivateChild", reactivationDelay); } public void ReactivateChild() { child.gameObject.SetActive(true); } } parent (an empty gameobject) needs a rigidbody (without gravity ), the child (which is your existing coin) needs to have the trigger collider (if it currently has a rigidbody remove it).
@LeftyRighty right now my HUD does say the total number of coins collected in the bottom left corner, im using it as just a tracker for how many coins you've collected in general (eventually i want this game to turn into like an RPG type thing where you can buy items, but thats a long was away) so with that in mind, would i want to go with the less UI intensive option? I added the code you provided but its saying: Assets/Scripts/Coincontroller.cs(9,14): error CS1519: Unexpected symbol `public' in class, struct, or interface member declaration Code (CSharp): public Transform child; public float reactivationDelay public void OnTriggerEnter(Collider other) { Debug.Log (Transform.name + "Trigger collision with " + other.transform.name); child.GameObject.setactive (false); Invoke ("ReavticvateChild", reactivationDelay); } public void ReactivateChild () { child.gameObject.SetActive (true); }
every F***ing time. i thought i went line for line trying to find it now its saying Assets/Scripts/Coincontroller.cs(11,38): error CS0120: An object reference is required to access non-static member `UnityEngine.Object.name' from looking online i guess i have to change the way i word something... This is probably 90% of the struggle have.. i know exactly what it is i WANT it to do, and i roughly now HOW to do it, i just dont know what WORDS to use...
You can use InvokeRepeating to spawn GameObjects (like a coin) repeatedly. You store the object that is returned by Instantiate in a List. You then set a max count and when the List contains too many items you don't spawn a object (just so that the level doesn't get spammed): Code (csharp): public class CoinController : MonoBehavior { // set in Inspector public float delay; public float rate; public float minRadius; public float maxRadius; public int maxCoins; public GameObject coinPrefab; public List<GameObject> coinsInScene; void Start () { InvokeRepeating ( "spawnCoin", delay, rate ) } public void spawnCoin () { if ( coinsInScene.Count > maxCoins ) return; GameObject newCoin = Instantiate ( coinPrefab, getRandomPosInRadius(), Random.rotation ); // adding the new Coin to the List coinsInScene.Add ( newCoin ); // if a Coin gets picked up, destroy it in the List // tracking Coins and destroying them // is beyond this code, however } public Vector3 getRandomPosInRadius ( ) { float rRadius = Random.Range ( minRadius, maxRadius ); return Random.insideUnitCircle * rRadius; } } Obviously, this is not a long-term solution. Long-term you want to use some kind of event system and an object pooling solution a la PoolManager. One thing in your code: Code (csharp): child.GameObject.setactive (false); should propably be Code (csharp): child.gameObject.SetActive( false ); Btw, your posts are harder to understand without punctuation. One last thing ... You are asking some very basic questions here. Study the Unity Learn section and read code from Unity example projects that are available for free on the Unity Asset store. Starting with Unity you will have to read, read, read.