AudioSource error - unity3d

I am following directions out of a book to put together a simple FPS. However, I am not getting the same results as the book says I should.
The last thing I have been trying to do is add a sound to my "gun", so that this sound clip "pop.wav" plays when you fire.
Here is the working code before I took the steps to add the sound.
var projectile : Rigidbody;
var speed = 50;
function Update () {
if(Input.GetButtonDown("Fire1"))
{
var instantiatedProjectile : Rigidbody = Instantiate(projectile, transform.position +
Vector3(0,-1,0), transform.rotation);
instantiatedProjectile.velocity = transform.TransformDirection(Vector3(0,0,speed));
Physics.IgnoreCollision(instantiatedProjectile.collider, transform.root.collider);
}
}
So I did what the book said, and imported Pop.wav. Then it said to add two simple lines of code to the script.
var projectile : Rigidbody;
var speed = 50;
var pop : AudioClip;
function Update () {
if(Input.GetButtonDown("Fire1"))
{
var instantiatedProjectile : Rigidbody = Instantiate(projectile, transform.position +
Vector3(0,-1,0), transform.rotation);
instantiatedProjectile.velocity = transform.TransformDirection(Vector3(0,0,speed));
Physics.IgnoreCollision(instantiatedProjectile.collider, transform.root.collider);
audio.Play(pop);
}
}
Assets/FireProjectile.js(12,27): BCE0023: No appropriate version of 'UnityEngine.AudioSource.Play' for the argument list '(UnityEngine.AudioClip)' was found.
I would really appreciate some help on this.

I don't see you assigning the file to be played to the audio clip... something like
pop.clip = ...
A brief search on unity 3d mentions assigning the clip, and checking that it's ready to play.

Actually, you have overlooked something outside the script. You do in fact need to add an audio listener and an audio source in the scene. Then, you'll be able to hear the sound.
The reason for this is that unity allows for 3D sound, i.e. sound which has a location in 3D space, and will increase in volume if you go near it. The Audio Source is obviously where the sound is comming from, and Audio Listener is where your ears are, so to speak. Usually the audio listener is on your character. But you can rig it so that it is on any object, but then that object would have to get near the audio source, and not the character, which doesn't make any sense at all.
However, remember to only have ONE audio LISTENER at a time. Infinite audio SOURCES are allowed. :)

You need to assign your variable. It would be something like
pop.clip = (anything here)

You must use audio.PlayOneShot(pop) instead of audio.Play().
But if you want to use audio.Play(); you should know that it doesn't take AudioClip as argument.
Use following code and make sure you assign pop to Audio Clip property of Audio Source component by dragging pop sound from Project to inspector. audio.Play() uses default assigned Audio Clip in AudioSource.
var projectile : Rigidbody;
var speed = 50;
function Update () {
if(Input.GetButtonDown("Fire1"))
{
var instantiatedProjectile : Rigidbody = Instantiate(projectile, transform.position +
Vector3(0,-1,0), transform.rotation);
instantiatedProjectile.velocity = transform.TransformDirection(Vector3(0,0,speed));
Physics.IgnoreCollision(instantiatedProjectile.collider, transform.root.collider);
audio.Play();
}
}
#script RequireComponent(AudioSource)

Based on the Unity documentation (I've never used Unity so I can't be sure this is correct) I find that you probably want to do something like this.
var projectile : Rigidbody;
var speed = 50;
var pop : AudioClip;
...
if(Input.GetButtonDown("Fire1"))
{
var instantiatedProjectile : Rigidbody = Instantiate(projectile, transform.position +
Vector3(0,-1,0), transform.rotation);
instantiatedProjectile.velocity = transform.TransformDirection(Vector3(0,0,speed));
Physics.IgnoreCollision(instantiatedProjectile.collider, transform.root.collider);
audio.PlayOneShot(pop);
}
This is actually all you have to do. Assign a variable, and then tell it to play in the update function, whenever Fire1 is pressed, which is LMB by default.
PlayOneShot means the sound won't loop or anything, which I assume you want for gunshots or similar. Within the parentheses you simply name the sound you want to play.

Related

Why is it SO Hard to Just Mute a Sound in Unity?

I have spent all day looking for a solution to this problem, and I simply can't find one. Using JavaScript in Unity 3D, I have a script where I want to play a sound when the player's velocity on the X axis reaches a certain point, and if it's not at that point, then the sound will be muted. And I believe I have all the structure right, it's just the line of code that says to mute the audio that won't work. I've tried all kinds of different combinations, and I get an error for each one.
The script looks like this:
#pragma strict
var playing = false;
var audioSource = GetComponent.<AudioSource>();
function Update () {
if (transform.GetComponent.<Rigidbody>().velocity.x <= 2.5 &&
transform.GetComponent.<Rigidbody>().velocity.x >= -2.5)
{
Mute();
} else {
Unmute();
}
}
function Mute () {
audioSource.mute = true;
}
function Unmute () {
audioSource.mute = false;
Sound();
}
function Sound () {
if (transform.GetComponent.<Rigidbody>().velocity.x >= 2.5 && playing ==
false)
{
playing = true;
GetComponent.<AudioSource>().Play();
yield WaitForSeconds(2);
playing = false;
}
if (transform.GetComponent.<Rigidbody>().velocity.x <= -2.5 &&
playing == false)
{
playing = true;
GetComponent.<AudioSource>().Play();
yield WaitForSeconds(2);
playing = false;
}
}
I've gotten all kinds of different errors, but the one I seem to be getting the most says "UnityException: GetComponentFastPath is not allowed to be called from a MonoBehaviour constructor (or instance field initializer), call it in Awake or Start instead. Called from MonoBehaviour 'motioncheck' on game object 'Ball'." I'm not sure what this means, since I'm still kinda a nub at JavaScript.
I feel like it shouldn't be this hard to just mute a sound. I'm going to assume that the answer to this is really simple and that I'm just really dumb. That's what usually seems to happen, lol.
In the mean time, I'm going to continue my rampage across the internet in search for answers to this problem.
Your mute code is fine.
"UnityException: GetComponentFastPath is not allowed to be called from
a MonoBehaviour constructor (or instance field initializer), call it
in Awake or Start instead. Called from MonoBehaviour 'motioncheck' on
game object 'Ball'." I'm not sure what this means, since I'm still
kinda a nub at JavaScript.
See this:
var audioSource = GetComponent.<AudioSource>();
That's a Unity API and you have to call their functions from inside a function. The Awake or Start function is appropriate for initializing component variables.
var audioSource : AudioSource;
function Start()
{
audioSource = GetComponent.<AudioSource>();
}
Note that Unityscript/Javascript is now discontinued. They no longer update the doc on this and you cannot create new scripts from the Editor anymore. It still works as for now but the compiler will be removed soon. Please learn and start using C# before its support is totally removed.

How to destroy a game object marked "DontDestroyOnLoad" when a new scene loads?

So I created a music player to play music through all my menu and story scenes without interrupting, but then in my game scene I want to delete that music. How can destroy the playing music when my game scene loads?
Here is my music script:
#pragma strict
var offsetY : float = 40;
var sizeX : float = 100;
var sizeY : float = 40;
var musicPrefab : Transform;
function Start () {
if (!GameObject.FindGameObjectWithTag("MM")) {
var mManager = Instantiate (musicPrefab, transform.position, Quaternion.identity);
mManager.name = musicPrefab.name;
DontDestroyOnLoad (mManager);
}
}
Just call destroy on it directly:
Destroy(mManager);
DontDestroyOnLoad only protects the object from being destroyed when loading a new scene.
I created a script called Destroyer.js and attached it to the camera in the scene where I didn't want music. Then in that script I added this code, and it doesn't play anymore.
function Start() {
Destroy(gameObject.Find("_MMusic"));
}
You can destroy the object by calling Destroy(objectname) directy like mentioned above by Almo. You could place it in the same function call which is responsible for the change to the scene where you don't want the music to be playing.
I had the same issue so I tried Destroy(gameObject); as mentioned in answers above but It didn't work for me.
So I tried SceneManager.LoadScene("OtherSceneName", LoadSceneMode.Additive); and it worked for me. Read official docs here.
Maybe it's a little bit late but I use this script and it's works great:
GameObject player = GameObject.FindGameObjectWithTag("Player");
if(player)
Destroy(player);
To achieve this, simply put Destroy(gameObject) in the Update method.

Unity3D Raycasting with Oculus Rift Integration / Measuring the distance

I want to measure the distance between two points in Unity3D Game Engine using the Oculus Rift. The points are targeted by the user by looking at point A, pressing alpha1 on the keyboard and B, pressing alpha2 on the keyboard. I got this far:
#pragma strict
private var measuring = false;
private var startPoint : Vector3;
private var dist;
function Update() {
var hit : RaycastHit;
if (Input.GetKeyDown(KeyCode.Alpha1)) {
dist = 0.0f;
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), hit)) {
// if (Physics.Raycast(transform.position, transform.forward, hit, 10)) {
measuring = true;
startPoint = hit.point;
}
}
if (measuring && Input.GetKeyDown(KeyCode.Alpha2)) {
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), hit)) {
// if (Physics.Raycast(transform.position, transform.forward, hit, 10)) {
dist = Vector3.Distance(startPoint, hit.point);
}
}
}
function OnGUI() {
if (measuring) {
GUI.Label(Rect(50,50,180,50), "Distance: " + dist.ToString());
}
}
My problem is, that this code only works with the standard main camera object, but I want to use the Oculus integrated OVRCameraRig. I get the following exception message:
NullReferenceException: Object reference not set to an instance of an object
MeasureInGame.Update () (at Assets/MeasureInGame.js:11)
I found a solution on this site: https://kaharri.com/unity-gaming-shootingaiming-part3-oculus/ I created a ShotSpawner object as a child of OVRCameraRig (this should act like a gun in front of the camera) and changed the Raycast to
Physics.Raycast(transform.position, transform.forward, hit, 10)
to get the users view. But it also doesn't seem to work.
How can I get the aiming done with the Oculus a Main Camera. And is it correct that I strictly need to have a collider on my objects to be measured or is there a solution without collider?
Greetings
First of all - are you really using the mouse with Oculus? Of course you can, but the standard way is to look at the selected object (cursor is in the center of viewport). Cast the ray from the "middle" eye in the oculus integration - it's the object that is the parent to the left and right eyes. Use this ray instead of the one from Camera.main.ScreenPointToRay:
// add a reference to the middleEyeGameobject
// in your class and link it in the inspector
var ray=new Ray(middleEyeGameobject.transform.position, middleEyeGameobject.transform.forward);
Also, you don't have to specify the distance with hit raycast (remove the fourth parameter to Physics.Raycast).
And for the additional question yes, everything has to have a collider with Physics.Raycast. And yes, there are other ways to do this, but the built in ones (2) still require colliders (or similar), although they can be virtual, not attached to objects.
It's best to use colliders, perhaps on their own layer.
The NullReferenceException you are getting is because you are using Camera.main.ScreenPointToRay(Input.mousePosition) , camera.main uses the MainCamera tag which is not set for your OVRCameraRig. You can set tag of this camera as mainCamera if OVRCameraRig is supposed to be your mainCamera or otherwise you can take reference of this camera (OVRCameraRig) and use cameraRef.ScreenPointToRay(Input.mousePosition). :)

Set transform from another GameObject's script

I'm trying to make a script to set an object when is being instantiated. The problem is, I don't clearly know how to do it. I have this function..
function spawnPlayer()
{
var CameraScript = GameObject.Find(PlayerPrefab.name).GetComponent("Camera Control");
Network.Instantiate(PlayerPrefab, spawnObject.position, Quaternion.identity, 0);
}
Where PlayerPrefab is going to be the Prefab that's going to be instantiated. When this happens, I need to set the instantiated gameObject on another GameObject which is camera and has a script called "Camera Control" and inside there's a transform Target which I'm trying to set. How to do this?
The code you posted can't be right. You are using the PlayerPrefab's name to to find the Camera Control script attached to the camera? By that logic then the moment you instantiate PlayerPrefab, on the second line, you will have a second camera.
I think what you want to do is this: Instantiate the player prefab and make the camera point to the player.
So I am assuming the CameraControl script is created. You need the following before we start to code.
Attach CameraControl script to the camera in the scene.
Make sure the Player script is attached to the Player Prefab.
Have a third script that will instantiate the PlayerPrefab. I will call it Instantiator. Attach it to an empty GameObject in the scene, think of it as the world GameObject. We will call it World.
Make sure the Instantiator script is attached to the World GameObject and that it is pointing to the PlayerPrefab.
Code: Instantiator
The Instantiator script will spawn and create things we will use in the scene.
#pragma strict
var PlayerPrefab : GameObject;
function Start ()
{
// You can add position and rotation to the function call if you like.
var p = Instantiate(PlayerPrefab) as GameObject;
// Find the camera script and point to Player's transform.
Camera.main.GetComponent("CameraControl").SendMessage("setTarget", p.transform);
}
Notice I used the fact that the MainCamera in the scene is marked by Unity for you so it is easy to find.
Code: CameraControl
The CameraControl will have the logic to follow the Player as you see fit. Notice that target will point to what the camera will focus on. Of course following the Player around you will have to write.
var target : Transform;
function setTarget(t : Transform)
{
target = t;
}
I just taught myself a bit of JavaScript. I had never used it before.
I found my solution.
What I was meaning on my question was to set my camera's script the transform of the instantiated object.
I did not have to make many empty objects with scripts value of each object; it took me hours to find it because I did not know how unity handles the scripts objects calls.
This is how I made it:
var PlayerPrefab : GameObject;
var spawnObject : Transform;
private var MainCamera : GameObject;
function spawnPlayer()
{
var player = Instantiate(PlayerPrefab, spawnObject.position, Quaternion.identity);
MainCamera = GameObject.Find("MainCamera");
player.name = "Ball";
if(MainCamera)
{
MainCamera.GetComponent.<CameraControl>().target = player.transform;
Debug.Log("Succeed.");
}
}
Like this, my camera will have the transform properties of the new instantiated object automatically.

Unity3D OffNavMesh jump issue

I have set up Unity navigation meshes (four planes), navigation agent (sphere) and set up automatic and manual off mesh links. It should now jump between meshes. It does jump between meshes, but it does that in straight lines.
In other words, when agent comes to an edge, instead of actually jumping up (like off mesh link is drawn) it just moves straight in line but a bit faster. I tried moving one plane higher than others, but sphere still was jumping in straight line.
Is it supposed to be like this? Is it possible to set up navigation to jump by some curve? Or should I try to implement that myself?
I came by this question, and had to dig through the Unity sample. I just hope to make it easier for people by extracting the important bits.
To apply your own animation/transition across a navmesh link, you need to tell Unity that you will handle all offmesh link traversal, then add code that regularly checks to see if the agent is on an offmesh link. Finally, when the transition is complete, you need to tell Unity you've moved the agent, and resume normal navmesh behaviour.
The way you handle link logic is up to you. You can just go in a straight line, have a spinning wormhole, whatever. For jump, unity traverses the link using animation progress as the lerp argument, this works pretty nicely. (if you're doing looping or more complex animations, this doesn't work so well)
The important unity bits are:
_navAgent.autoTraverseOffMeshLink = false; //in Start()
_navAgent.currentOffMeshLinkData; //the link data - this contains start and end points, etc
_navAgent.CompleteOffMeshLink(); //Tell unity we have traversed the link (do this when you've moved the transform to the end point)
_navAgent.Resume(); //Resume normal navmesh behaviour
Now a simple jump sample...
using UnityEngine;
[RequireComponent(typeof(NavMeshAgent))]
public class NavMeshAnimator : MonoBehaviour
{
private NavMeshAgent _navAgent;
private bool _traversingLink;
private OffMeshLinkData _currLink;
void Start()
{
// Cache the nav agent and tell unity we will handle link traversal
_navAgent = GetComponent<NavMeshAgent>();
_navAgent.autoTraverseOffMeshLink = false;
}
void Update()
{
//don't do anything if the navagent is disabled
if (!_navAgent.enabled) return;
if (_navAgent.isOnOffMeshLink)
{
if (!_traversingLink)
{
//This is done only once. The animation's progress will determine link traversal.
animation.CrossFade("Jump", 0.1f, PlayMode.StopAll);
//cache current link
_currLink = _navAgent.currentOffMeshLinkData;
//start traversing
_traversingLink = true;
}
//lerp from link start to link end in time to animation
var tlerp = animation["Jump"].normalizedTime;
//straight line from startlink to endlink
var newPos = Vector3.Lerp(_currLink.startPos, _currLink.endPos, tlerp);
//add the 'hop'
newPos.y += 2f * Mathf.Sin(Mathf.PI * tlerp);
//Update transform position
transform.position = newPos;
// when the animation is stopped, we've reached the other side. Don't use looping animations with this control setup
if (!animation.isPlaying)
{
//make sure the player is right on the end link
transform.position = _currLink.endPos;
//internal logic reset
_traversingLink = false;
//Tell unity we have traversed the link
_navAgent.CompleteOffMeshLink();
//Resume normal navmesh behaviour
_navAgent.Resume();
}
}
else
{
//...update walk/idle animations appropriately ...etc
Its recommended to solve your problems via animation. Just create a Jump animation for your object, and play it at the correct time.
The position is relative, so if you increase the Y-position in your animation it will look like the object is jumping.
This is also how the Unity sample is working, with the soldiers running around.
Not sure what version of unity you are using but you could also try this, I know it works just fine in 4:
string linkType = GetComponent<NavMeshAgent>().currentOffMeshLinkData.linkType.ToString();
if(linkType == "LinkTypeJumpAcross"){
Debug.Log ("Yeah im in the jump already ;)");
}
also just some extra bumf for you, its best to use a proxy and follow the a navAgent game object:
Something like:
AIMan = this.transform.position;
AI_Proxy.transform.position = AIMan;
And also be sure to use:
AI_Proxy.animation["ProxyJump"].blendMode = AnimationBlendMode.Additive;
If you are using the in built unity animation!
K, that's my good deed for this week.
Fix position in update()
if (agent.isOnOffMeshLink)
{
transform.position = new Vector3(transform.position.x, 0f, transform.position.z);
}