Hey, working through my first implementation of multiplayer. I can’t seem to get audio sources to play. When the playing uses a gun, I use a command to fire a bullet and create a PlayOneShot audio source on the server. I see the bullets, but I don’t hear the audio. What am I missing? Do I need to somehow sync the audio source to each client manually?
I think the best implementation of sound would be to send the client an Rpc call and in the function play the sound.
Hmm, is there an easy way to deal with distance for volume that way?
Well, I’m guessing it’s the player that shoots a bullet, and each client has the camera following their own player. Then you can just attach an audiosource on each player and play it whenever that player is shooting. Then have the audiolistener only on the clients player. Be sure to enable 3D sounds which will automatically handle distance with audiosources and listeners.
Well, I can certainly give that a shot. Know of any reason why it wouldn’t be playing from the server though? I’ll need to have this option for explosions of targets and other sound effects.
Are you using the Commands and RpcClient attributes?
Here’s the rundown:
Receive input to shoot.
Run a [Command] function.
In the [Command] function, instantiate and spawn the bullet object. Also call a [RpcClient] function that will play the audio on the players AudioSource.
public AudioClip fireBulletSound;
[Command]
public void Cmd_SpawnBullet()
{
GameObject bullet = Instantiate(bulletPrefab, player.transform.position, player.transform.rotation);
NetworkServer.Spawn(bullet);
Rpc_PlaySound(fireBulletSound);
}
[RpcClient]
public void Rpc_PlaySound(AudioClip sound)
{
AudioSource audioSource = GetComponent<AudioSource>();
audioSource.PlayOneShot(sound, 1f);
}
Note that I just wrote this here, not tested. But it should work fine, looking away from syntax errors.
Ok, I’ll give that a shot - I haven’t used any RPCs yet. For an asteroid explosion, I would have a similar Rpc call method on the asteroid that is called by the server when it determines the asteroid needs to explodes, and the Rpc would play audio using an audio source on the asteroid, and this would happen on the client? From http://docs.unity3d.com/Manual/UNetActions.html it sounds like all objects can have Rpc methods.
Yeah, all objects that are NetworkBehaviours if I remember correctly. But that’s exactly what you’d need to do.
Ok, here’s what I have:
public override void Operate(List<KeyCode> allKeys, List<KeyCode> allKeyDowns, List<KeyCode> allKeyUps)
{
if (allKeys.Contains(KeyCode.Space))
{
if (cooldown <= 0)
{
if (Input.GetKey("space"))
{
// Reset gun cooldown.
cooldown = 1;
Rpc_ShotSound();
}
}
// Create a bullet
Vector3 bulletStartPosition = new Vector3(this.transform.position.x, this.transform.position.y, this.transform.position.z + 2);
GameObject bulletClone = Instantiate(Gun.BulletPrefab, bulletStartPosition, transform.rotation) as GameObject;
// Accellerate the bullet
Vector3 newVector = this.transform.forward * Gun.BULLET_SPEED + this.transform.parent.transform.parent.transform.GetComponent<Rigidbody>().velocity;
bulletClone.GetComponent<Rigidbody>().AddForce(newVector, ForceMode.VelocityChange);
// Spawn the bullet
Destroy(bulletClone, 2f);
NetworkServer.Spawn(bulletClone);
}
}
[ClientRpc]
public void Rpc_ShotSound()
{
// Create firing sound.
float vol = Random.Range(volLowRange, volHighRange);
aSource.PlayOneShot(aClipShoot, vol);
}
Operate() is called by a Cmd method inside the player script. I hit a breakpoint at Rpc_ShotSound(); so I can see I’m getting there. I never reach a breakpoint inside Rpc_ShotSound() though.
Hmm, that seems a bit weird. I just installed UnityVS myself, so I don’t know much about the breakpoints. But it might be interfering with networking? Try maybe using Debug.Log instead, as it won’t stop the code. I would just guess that pausing the game with networking kinda messes up the timing.
Also a bit unrelated, but if I understand this correctly, this code will only run on the host, since you’re checking if the user has pressed a key, but Operate is only run on the host. That might not want to be your intention.
I had the same behaviour with/without the breakpoints.
Actually, I’m capturing all the various inputs at the player and passing them through to the server via a Cmd :). Operate is called by a Cmd on the player. Since my player can control various vehicles, I needed to move most of the control complexity to the server.
Well, if the input works, no problem.
As for the actual problem, the only reason I could see it not executing the Rpc function would be if you’re not calling it from the host. But since you’re only calling Operate() from a Cmd, I don’t see how it would be possible. Just to be sure, try putting the breakpoint in an if (isServer) state once you’ve reached the point where you want to run the Rpc function? It should go to the breakpoint, but I’m running out of ideas.
Based on a few comments in (UNet - ClientRpc not executing on Host - Unity Engine - Unity Discussions) I’m wondering if how I’m setting up this script is a problem. The Gun gameobject and script are around at launch, but I spawn the controller later. Also, my Operate() method in GunController is called inside my player script’s Cmd and passed all the inputs. isServer is true when I come through Operate. Details below.
Here’s the game objects inside the scene before I start the game (so they’re there at game launch, and I assume I don’t need to worry about doing a NetworkServer.Spawn):
And here’s my Gun script and GunController scripts:
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
using System.Collections.Generic;
public class Gun : Equipment
{
public GameObject BulletPrefab;
public float RateOfFirePerSecond = 2f;
public const int BULLET_SPEED = 15;
// Use this for setting up references
public void Awake()
{
// Add Controller
Controller = gameObject.AddComponent<GunController>();
}
}
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
using System.Collections.Generic;
public class GunController : EquipmentController
{
private float cooldown = 0;
private Gun Gun;
public AudioClip aClipShoot;
private AudioSource aSource;
private float volLowRange = .75f;
private float volHighRange = 1.25f;
void Start()
{
aSource = GetComponent<AudioSource>();
this.Gun = this.gameObject.GetComponent<Gun>();
}
// TODO: Make sure this only runs on the server.
[Server]
void Update()
{
if (cooldown > 0)
{
cooldown -= this.Gun.RateOfFirePerSecond * Time.deltaTime;
}
}
public override void Operate(List<KeyCode> allKeys, List<KeyCode> allKeyDowns, List<KeyCode> allKeyUps)
{
if (allKeys.Contains(KeyCode.Space))
{
if (cooldown <= 0)
{
if (Input.GetKey("space"))
{
// Reset gun cooldown.
cooldown = 1;
if (isServer)
{
Debug.LogWarning("IsServer");
}
Rpc_ShotSound();
}
}
// Create a bullet
Vector3 bulletStartPosition = new Vector3(this.transform.position.x, this.transform.position.y, this.transform.position.z + 2);
GameObject bulletClone = Instantiate(Gun.BulletPrefab, bulletStartPosition, transform.rotation) as GameObject;
// Accellerate the bullet
Vector3 newVector = this.transform.forward * Gun.BULLET_SPEED + this.transform.parent.transform.parent.transform.GetComponent<Rigidbody>().velocity;
bulletClone.GetComponent<Rigidbody>().AddForce(newVector, ForceMode.VelocityChange);
// Spawn the bullet
Destroy(bulletClone, 2f);
NetworkServer.Spawn(bulletClone);
}
}
[ClientRpc]
void Rpc_ShotSound()
{
Debug.LogWarning("RPC return");
// Create firing sound.
float vol = Random.Range(volLowRange, volHighRange);
aSource.PlayOneShot(aClipShoot, vol);
}
}
is GunController a NetworkBehaviour?
Hey, I think you are overthinking the bullet part.
Just add an audio source to your bullet prefab and set it to play your sound on start up.
When the bullet is spawned on the clients (remote and local) it will play the sound.