0
\$\begingroup\$

So for my game you have to hold down right mouse click to aim and then simultaneously click the left mouse click to shoot. When the gun is fired, I'd like the gunfire sound to play. Currently, I have this working, but I have a problem. When I let go of the aim button, the gunfire sound immediately stops playing (if it hasn't already played through).

I understand this is happening because of the placement of my PlayShootSound method call, but what I can't figure out is where to put it so that I don't have this problem.

Any pointers/ideas?

public class Weapon : MonoBehaviour {

 public float fireRate = 0;
 public float damage = 10;
 public LayerMask whatToHit;

 public Transform BulletTrailPrefab;
 public Transform MuzzleFlashPrefab;

 float timeToFire = 0;
 float timeToSpawnEffect = 0;
 public float effectSpawnRate = 10;
 Transform firePoint;

 public AudioClip shootSound;
 private AudioSource gunFire;

 bool isShooting = false;

 // Use this for initialization
 void Awake () {
     gunFire = GetComponent<AudioSource>();

     firePoint = transform.Find("FirePoint");
     if (firePoint == null)
     {
         Debug.LogError("No fire point...Please make an empty object named FirePoint and attach to end of gun. :)");
     }
 }
 void Update () {
     CheckIfShooting();
 }

 void CheckIfShooting()
 {
     if (Input.GetButton("Fire2")) // Holding right click
     {
         if (fireRate == 0)
         {
             print("fire rate is 0");
             if (Input.GetButtonDown("Fire1")) // Left click while holding right click
             {
                 Shoot();
                 PlayShootSound();
             }
         }
         else
         {
             if (Input.GetButton("Fire1") && Time.time > timeToFire) // For automatic guns
             {
                 timeToFire = Time.time + 1 / fireRate;
                 Shoot();
                 PlayShootSound();
             }
         }
     }
 }

 void Shoot()
 {
     Vector2 mousePosition = new Vector2(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y);
     Vector2 firePointPosition = new Vector2(firePoint.position.x, firePoint.position.y);
     RaycastHit2D hit = Physics2D.Raycast(firePointPosition, mousePosition - firePointPosition, 100f, whatToHit);


     if (Time.time >= timeToSpawnEffect)
     {
         Effect();
         timeToSpawnEffect = Time.time + 1 / effectSpawnRate;
     }
     // Debug.DrawLine(firePointPosition, (mousePosition - firePointPosition) * 100, Color.cyan);

     if (hit.collider != null)
     {
         // Debug.DrawLine(firePointPosition, hit.point, Color.red);
         Debug.Log("We hit " + hit.collider.name + " and did " + damage + " damage.");
     }
 }

 void PlayShootSound()
 {
     gunFire.PlayOneShot(shootSound, 1f);
 }

 void Effect()
 {
     Instantiate(BulletTrailPrefab, firePoint.position, firePoint.rotation); // Fire Bullet

     Transform muzzleFlashClone = Instantiate(MuzzleFlashPrefab, firePoint.position, firePoint.rotation) as Transform;
     muzzleFlashClone.parent = firePoint;
     float size = UnityEngine.Random.Range(6f, 9f); // Randomize size of muzzle flash
     muzzleFlashClone.localScale = new Vector3(size, size, size);
     Destroy(muzzleFlashClone.gameObject, 0.05f);
 }
\$\endgroup\$
0
\$\begingroup\$

In my own game I've put all Gun oriented logic inside of a Gun class (with derived classes representing different guns.)

I'd probably refactor this so you do a "gun.Shoot()" and then inside of gun.Shoot() you'd have something like:

public Shoot()
{
     // logic for firerate
     // logic for creating/firing a bullet

     this.PlayShootSound()
}

Depending if that's still buggy; you may go crazy and wrap it in a Task. Tasks are managed Threads from a Thread pool that are automatically assigned when needed so then you might do:

var task = new Task(() =>
    {
        this.PlayShootSound();
    }
task.Start();

Hopefully that's overkill and not necessary.

EDIT: I think you should try the above. It should be nigh guaranteed to work if you use a task;

\$\endgroup\$
  • \$\begingroup\$ PlayShootSound is included in the code example in the question. \$\endgroup\$ – DMGregory Jun 16 '18 at 18:05
  • \$\begingroup\$ Yes indeedy, PlayShootSound() is just below Shoot() :) \$\endgroup\$ – Jay Cuellar Jun 16 '18 at 18:50
  • \$\begingroup\$ @DMGregory (Can't figured out how to tag Jay) I meant PlayOneShot(). I'll edit the answer \$\endgroup\$ – blurry Jun 16 '18 at 23:28
  • 1
    \$\begingroup\$ PlayOneShot is part of the Unity API. You can read up on it in the Unity documentation if you're curious. \$\endgroup\$ – DMGregory Jun 16 '18 at 23:29
  • \$\begingroup\$ I'm not sure how to incorporate Task(), I tried it earlier and Unity doesn't seem recognize that method. :( \$\endgroup\$ – Jay Cuellar Jun 17 '18 at 0:17
0
\$\begingroup\$

Thank you everyone for helping, but I found the answer finally!!!

I followed this tutorial on how to create an audio manager and call sounds through it...and now my problem is fixed. :)

https://www.youtube.com/watch?v=HhFKtiRd0qI

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.