0
votes

I am building a 3D game, and I have some water in the scene. I have attached to it a trigger collider. When the player character's collider enters the water's trigger collider, a splash sound will play. The same happens when the character exits the water.

Now I have added another collider child of the player gameObject. As I did expect, now when the player enters the water, two different colliders hit the trigger so it produces two sounds. What I would like to do is to check to see if the collider that activated the trigger is actually the player or no, so it can play the sound only once, as it did before and as it should do.

This is what i tried to do.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Splashwater : MonoBehaviour
{
    public AudioSource audioSource;
    public AudioClip splashInWater;
    private bool isInTheWater = false;

    public GameObject player;

    private void OnTriggerEnter(Collision collision)
    {
        if (collision.gameObject == player)
        {
            audioSource.PlayOneShot(splashInWater);
        }
    }

    private void OnTriggerExit(Collision collision)
    {
        if (collision.gameObject == player)
        {
            audioSource.Stop();
            audioSource.PlayOneShot(splashInWater);
        }
    }
}

Note: I assigned to player the gameobject of the player character in the inspector.

I'm sure there is a simple way to do this. I did not yet find any solutions that could fix my problem.

Any help is highly appreciated!

3

3 Answers

2
votes

I'm not sure if I understand your problem, but it looks like you can use

public Collider playerCollider;

instead of

public GameObject player;

You can specify which collider will be "responsible" for triggering the audio.

OnTriggerEnter might be like this:

 private void OnTriggerEnter(Collider collider)
    {
        if (collider == playerCollider)
        {
            audioSource.PlayOneShot(splashInWater);
        }
    }
1
votes

Your current solution is pretty solid already.

There is a small mistake in that the methods for triggers have a different signature to the ones for collisions. They take Collider other instead of Collision collision. I guess you started prototyping with collision and forgot to change the method signatures once you switched the trigger flag on. Happens often to me too, even after a couple years of game-dev experience.

Other than that fix, I don't think I can offer any significant improvement to your implementation specifically. That is already pretty much how it should be done.

So intead, I'll offer you a bit of insight into how not to have to code the stuff from scratch every time. Let's make your system a bit more reusable, shall we? Here is how I'd do the code:

public class AudioTrigger : MonoBehaviour {
    #region Fields
    [SerializeField] private AudioSource _audioSource;
    [SerializeField] private AudioClip _audioClip;
    [SerializeField] private List<Collider> _targetColliders;
    #endregion

    #region Properties
    public AudioSource AudioSource {
        get => _audioSource;
        set => _audioSource = value;
    }

    public AudioClip AudioClip {
        get => _audioClip;
        set => _audioClip = value;
    }

    public List<Collider> TargetColliders => _targetColliders;
    #endregion

    #region Methods
    #region Instance Methods
    private void OnTriggerEnter(Collider other) {
        if (TargetColliders.Count == 0 || TargetColliders.Contains(other))
            AudioSource.PlayOneShot(AudioClip);
    }

    private void OnTriggerExit(Collider other) {
        if (TargetColliders.Count == 0 || TargetColliders.Contains(other)) {
            AudioSource.Stop();
            AudioSource.PlayOneShot(AudioClip);
        }
    }
    #endregion
    #endregion
}

There, now you can just plug that script in wherever and whenever you need a trigger to play audio, be it on any trigger event (by setting no target colliders) or on enter and exit events by specific "target" colliders.

This can be further modularized to work as a trigger for any action or set of actions, not just audio, by using UnityEvent. But I'll leave that as an exercise for you.

-1
votes

One way you can achieve this is with tags. Assign a tag to the player GameObject like so:

enter image description here

You can add your own tags by dropping the list down and selecting "Add tag", then click the small plus button to add your own tag:

enter image description here

You can then check to see if the colliding object has the "Player" tag like this:

public void OnTriggerEnter(Collider other)
{
    if (other.tag == "Player")
    {
        //do something
    }
}