0
votes

I have a big amount of prefabs. Those prefabs have several instances of the same script, which contains the following fields:

[SerializeField]
private AudioClip[] _audioClip;

[SerializeField, Range(0, 1)]
private float _volume = 1;

Since I would like to be able to control the volume of each audio clip separately, I would like to use:

[SerializeField]
private VolumedAudioClip[] _audioClips;

Where:

[Serializable]
public class VolumedAudioClip
{
    [SerializeField]
    public AudioClip _audioClip;
    [SerializeField, Range(0, 1)]
    public float _volume = 1;
}

Problem is, that if I change it now, all of the prefabs will lose the references to the audio clips already set.

I know of FormerlySerializedAs attribute, it doesn't help in my case (only if you rename a field).

My current direction is to write an editor script that will read from the old fields and put the data in the new fields.

Would be happy to hear any better suggestions...

1
That is a smart (lazy) way to do it. just add a serialized field of your custom class in the script and run for-loop to copy references of the audio clips using editor method. Once you are done just delete your old fields.This should work fine. Let me know if you need codeUmair M
This is exactly what I am doing. Problem is that the script holding those field is not of MonoBehavior type, so I have to use reflection to get all field of those typesYaniv Shaked
what type of script is it?Umair M
Oh just read in the comment after my answer this is not a MonoBehavior .. well as Umair M already asked what is it than and how did you add the other values to the array than? Only classes derived from MonoBehavior can be added as components on prefabs/GameObjectsderHugo

1 Answers

0
votes

If you have the flexibility to use a List<VolumedAudioClip> instead of the VolumedAudioClip[] I have a very simple and fast solution for you:

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

public class test : MonoBehaviour
{

    [SerializeField]
    private AudioClip[] _audioClip;

    [SerializeField, Range(0, 1)]
    private float _volume = 1;

    [Serializable]
    public class VolumedAudioClip
    {
        [SerializeField]
        public AudioClip_audioClip;
        [SerializeField, Range(0, 1)]
        public float _volume = 1;

        public VolumedAudioClip(AudioClip clip)
        {
            _audioClip = clip;
        }
    }

    [SerializeField]
    private List<VolumedAudioClip> _audioClips;

    //THIS ADDS A CONTEXT MENU BUTTON TO THE INSPECTOR!
    [ContextMenu("Copy the array")]
    private void CopyIt()
    {
        //To make sure we don't add things multiple times
        _audioClips.Clear();

        //Than just insert the items from the original array
        foreach (AudioClip clip in _audioClip)
        {
            VolumedAudioClip newClip = new VolumedAudioClip(clip);
            _audioClips.Add(newClip);
        }
    }
}

The [ContextMenu] attribute adds the CopyIt() method to the Context-Menu of the Inspector. Here is how you use it than: (I used int[] _audioClip for demonstration)

So at the beginning we have the original array of AudioClip[] _audioClip filled and the List of List<VolumedAudioClip> _audioClips empty.

The ofiginal array is filled

Now if you go to the context menu (gear icon) in the Inspector, our ContextMenu item "Copy the array" shows up. (isn't this awesom!)

The context menu method

After a simple click you see the elements of AudioClip[] _audioClip are copied to the new List List<VolumedAudioClip> _audioClips

The new List with copied content

NOTE
I wrote this really quick and it is sure not perfect so if you make already tweaks on the volumes and than use this function again, the volume tweaks will be lost since the List is filled again with the default value.

So I would recoment to use the function and than remove it from your script so you can't screw up by accident.

Hope it helps you