diff --git a/Assets/Fungus/Narrative/Scripts/SayDialog.cs b/Assets/Fungus/Narrative/Scripts/SayDialog.cs index 15b05381..3b338f6f 100644 --- a/Assets/Fungus/Narrative/Scripts/SayDialog.cs +++ b/Assets/Fungus/Narrative/Scripts/SayDialog.cs @@ -187,6 +187,7 @@ namespace Fungus { nameText.text = ""; } + speakingCharacter = null; } else { diff --git a/Assets/Fungus/UI/Editor/WriterAudioEditor.cs b/Assets/Fungus/UI/Editor/WriterAudioEditor.cs new file mode 100644 index 00000000..559cf586 --- /dev/null +++ b/Assets/Fungus/UI/Editor/WriterAudioEditor.cs @@ -0,0 +1,61 @@ +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using Rotorz.ReorderableList; + +namespace Fungus +{ + + [CustomEditor (typeof(WriterAudio))] + public class WriterAudioEditor : Editor + { + protected SerializedProperty volumeProp; + protected SerializedProperty loopProp; + protected SerializedProperty audioSourceProp; + protected SerializedProperty audioModeProp; + protected SerializedProperty beepSoundsProp; + protected SerializedProperty soundEffectProp; + protected SerializedProperty beepDelayProp; + protected SerializedProperty randomizeDelayProp; + + protected virtual void OnEnable() + { + volumeProp = serializedObject.FindProperty("volume"); + loopProp = serializedObject.FindProperty("loop"); + audioSourceProp = serializedObject.FindProperty("audioSource"); + audioModeProp = serializedObject.FindProperty("audioMode"); + beepSoundsProp = serializedObject.FindProperty("beepSounds"); + soundEffectProp = serializedObject.FindProperty("soundEffect"); + beepDelayProp = serializedObject.FindProperty("beepDelay"); + randomizeDelayProp = serializedObject.FindProperty("randomizeDelay"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(volumeProp); + EditorGUILayout.PropertyField(loopProp); + EditorGUILayout.PropertyField(audioSourceProp); + + EditorGUILayout.PropertyField(audioModeProp); + if ((WriterAudio.AudioMode)audioModeProp.enumValueIndex == WriterAudio.AudioMode.Beeps) + { + ReorderableListGUI.Title(new GUIContent("Beep Sounds", "A list of beep sounds to play at random")); + ReorderableListGUI.ListField(beepSoundsProp); + + EditorGUILayout.PropertyField(beepDelayProp); + EditorGUILayout.PropertyField(randomizeDelayProp); + } + else + { + EditorGUILayout.PropertyField(soundEffectProp); + } + + serializedObject.ApplyModifiedProperties(); + } + } + +} \ No newline at end of file diff --git a/Assets/Fungus/UI/Editor/WriterAudioEditor.cs.meta b/Assets/Fungus/UI/Editor/WriterAudioEditor.cs.meta new file mode 100644 index 00000000..bbbfed9f --- /dev/null +++ b/Assets/Fungus/UI/Editor/WriterAudioEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f07068d2254394c5d9367a7b738d8c86 +timeCreated: 1440497180 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Fungus/UI/Scripts/Writer.cs b/Assets/Fungus/UI/Scripts/Writer.cs index c9a8e9ee..fe10cd10 100644 --- a/Assets/Fungus/UI/Scripts/Writer.cs +++ b/Assets/Fungus/UI/Scripts/Writer.cs @@ -25,8 +25,8 @@ namespace Fungus // Called when the Writer has finshed writing text void OnEnd(); - // Called every time the Writer writes a character - void OnCharacter(); + // Called every time the Writer writes a new character glyph + void OnGlyph(); } public class Writer : MonoBehaviour, IDialogInputListener @@ -469,6 +469,8 @@ namespace Fungus PartitionString(writeWholeWords, param, i, out left, out right); text = ConcatenateString(startText, openText, closeText, left, right); + NotifyGlyph(); + // No delay if user has clicked if (inputFlag) { @@ -670,11 +672,11 @@ namespace Fungus } } - protected virtual void NotifyCharacter() + protected virtual void NotifyGlyph() { foreach (IWriterListener writerListener in writerListeners) { - writerListener.OnCharacter(); + writerListener.OnGlyph(); } } diff --git a/Assets/Fungus/UI/Scripts/WriterAudio.cs b/Assets/Fungus/UI/Scripts/WriterAudio.cs index 27ae834c..21248748 100644 --- a/Assets/Fungus/UI/Scripts/WriterAudio.cs +++ b/Assets/Fungus/UI/Scripts/WriterAudio.cs @@ -9,8 +9,15 @@ namespace Fungus */ public class WriterAudio : MonoBehaviour, IWriterListener { + [Tooltip("Volume level of writing sound effects")] + [Range(0,1)] + public float volume = 1f; + + [Tooltip("Loop the audio when in Sound Effect mode. Has no effect in Beeps mode.")] + public bool loop = true; + // If none is specifed then we use any AudioSource on the gameobject, and if that doesn't exist we create one. - [Tooltip("AudioSource to use for playing sound effects.")] + [Tooltip("AudioSource to use for playing sound effects. If none is selected then one will be created.")] public AudioSource audioSource; public enum AudioMode @@ -22,20 +29,21 @@ namespace Fungus [Tooltip("Type of sound effect to play when writing text")] public AudioMode audioMode = AudioMode.Beeps; - [Tooltip("List of beeps to randomly select when playing beep sound effects")] - public List beeps = new List(); + [Tooltip("List of beeps to randomly select when playing beep sound effects. Will play maximum of one beep per character, with only one beep playing at a time.")] + public List beepSounds = new List(); [Tooltip("Long playing sound effect to play when writing text")] public AudioClip soundEffect; - [Tooltip("Loop the sound effect")] - public bool loop = true; + protected float targetVolume = 0f; - [Tooltip("Volume level of writing sound effects")] - [Range(0,1)] - public float volume = 1f; + // When true, a beep will be played on every written character glyph + protected bool playBeeps; - protected float targetVolume = 0f; + public virtual void SetAudioMode(AudioMode mode) + { + audioMode = mode; + } protected virtual void Awake() { @@ -60,21 +68,31 @@ namespace Fungus return; } + audioSource.volume = 0f; + targetVolume = 1f; + if (audioClip != null) { + // Voice over clip provided audioSource.clip = audioClip; + audioSource.loop = loop; + audioSource.Play(); } - else + else if (audioMode == AudioMode.SoundEffect && + soundEffect != null) { + // Use sound effects defined in WriterAudio audioSource.clip = soundEffect; + audioSource.loop = loop; + audioSource.Play(); + } + else if (audioMode == AudioMode.Beeps) + { + // Use beeps defined in WriterAudio + audioSource.clip = null; + audioSource.loop = false; + playBeeps = true; } - - audioSource.loop = loop; - - audioSource.volume = 0f; - targetVolume = 1f; - - audioSource.Play(); } public virtual void Pause() @@ -99,6 +117,7 @@ namespace Fungus // looping and let the audio stop automatically at the end of the clip targetVolume = 0f; audioSource.loop = false; + playBeeps = false; } public virtual void Resume() @@ -137,11 +156,20 @@ namespace Fungus public virtual void OnEnd() { - Stop (); + Stop(); } - public virtual void OnCharacter() + public virtual void OnGlyph() { + if (playBeeps && beepSounds.Count > 0) + { + if (!audioSource.isPlaying) + { + audioSource.clip = beepSounds[Random.Range(0, beepSounds.Count - 1)]; + audioSource.loop = false; + audioSource.Play(); + } + } } } diff --git a/Assets/Tests/Narrative/NarrativeTests.unity b/Assets/Tests/Narrative/NarrativeTests.unity index 3678d540..ba1c4ce1 100644 --- a/Assets/Tests/Narrative/NarrativeTests.unity +++ b/Assets/Tests/Narrative/NarrativeTests.unity @@ -1057,6 +1057,7 @@ GameObject: - 114: {fileID: 594837302} - 114: {fileID: 594837303} - 114: {fileID: 594837304} + - 114: {fileID: 594837305} m_Layer: 0 m_Name: TestAssertions m_TagString: Untagged @@ -1181,6 +1182,27 @@ MonoBehaviour: checkMethods: 1 m_ActionBase: {fileID: 1613545005} checksPerformed: 0 +--- !u!114 &594837305 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 594837298} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8bafa54482a87ac4cbd7ff1bfd1ac93a, type: 3} + m_Name: + m_EditorClassIdentifier: + checkAfterTime: 12.5 + repeatCheckTime: 0 + repeatEveryTime: 1 + checkAfterFrames: 1 + repeatCheckFrame: 1 + repeatEveryFrame: 1 + hasFailed: 0 + checkMethods: 1 + m_ActionBase: {fileID: 1216870120} + checksPerformed: 0 --- !u!1 &658513471 GameObject: m_ObjectHideFlags: 0 @@ -1295,6 +1317,10 @@ GameObject: - 114: {fileID: 736071361} - 114: {fileID: 736071364} - 114: {fileID: 736071363} + - 114: {fileID: 736071366} + - 114: {fileID: 736071365} + - 114: {fileID: 736071368} + - 114: {fileID: 736071367} m_Layer: 0 m_Name: Flowchart m_TagString: Untagged @@ -1370,6 +1396,8 @@ MonoBehaviour: - {fileID: 736071347} - {fileID: 736071352} - {fileID: 736071360} + - {fileID: 736071366} + - {fileID: 736071365} --- !u!114 &736071350 MonoBehaviour: m_ObjectHideFlags: 0 @@ -1386,7 +1414,7 @@ MonoBehaviour: scrollPos: {x: 0, y: 0} variablesScrollPos: {x: 0, y: 0} variablesExpanded: 1 - blockViewHeight: 280 + blockViewHeight: 513 zoom: 1 scrollViewRect: serializedVersion: 2 @@ -1395,7 +1423,8 @@ MonoBehaviour: width: 1121 height: 870 selectedBlock: {fileID: 736071355} - selectedCommands: [] + selectedCommands: + - {fileID: 736071368} variables: [] description: stepPause: 0 @@ -1512,6 +1541,8 @@ MonoBehaviour: - {fileID: 736071361} - {fileID: 736071364} - {fileID: 736071363} + - {fileID: 736071368} + - {fileID: 736071367} --- !u!114 &736071356 MonoBehaviour: m_ObjectHideFlags: 0 @@ -1690,6 +1721,117 @@ MonoBehaviour: errorMessage: indentLevel: 0 duration: 2 +--- !u!114 &736071365 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 736071346} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} + m_Name: + m_EditorClassIdentifier: + itemId: 15 + errorMessage: + indentLevel: 0 + storyText: Write some audio with beep sounds + description: + character: {fileID: 0} + portrait: {fileID: 0} + voiceOverClip: {fileID: 0} + showAlways: 1 + showCount: 1 + extendPrevious: 0 + fadeOut: 1 + waitForClick: 1 + setSayDialog: {fileID: 0} +--- !u!114 &736071366 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 736071346} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 688e35811870d403f9e2b1ab2a699d98, type: 3} + m_Name: + m_EditorClassIdentifier: + itemId: 14 + errorMessage: + indentLevel: 0 + targetObject: {fileID: 1714427702} + targetComponentAssemblyName: Fungus.WriterAudio, Assembly-CSharp, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + targetComponentFullname: UnityEngine.Component[] + targetComponentText: WriterAudio + targetMethod: SetAudioMode + targetMethodText: 'SetAudioMode (AudioMode): Void' + methodParameters: + - objValue: + typeAssemblyname: Fungus.WriterAudio+AudioMode, Assembly-CSharp, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + typeFullname: Fungus.WriterAudio+AudioMode + intValue: 0 + boolValue: 0 + floatValue: 0 + stringValue: + colorValue: {r: 0, g: 0, b: 0, a: 0} + gameObjectValue: {fileID: 0} + materialValue: {fileID: 0} + objectValue: {fileID: 0} + spriteValue: {fileID: 0} + textureValue: {fileID: 0} + vector2Value: {x: 0, y: 0} + vector3Value: {x: 0, y: 0, z: 0} + variableKey: + saveReturnValue: 0 + returnValueVariableKey: + returnValueType: System.Void + showInherited: 0 + callMode: 0 +--- !u!114 &736071367 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 736071346} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 688e35811870d403f9e2b1ab2a699d98, type: 3} + m_Name: + m_EditorClassIdentifier: + itemId: 17 + errorMessage: + indentLevel: 0 + targetObject: {fileID: 1714427702} + targetComponentAssemblyName: Fungus.DialogInput, Assembly-CSharp, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + targetComponentFullname: UnityEngine.Component[] + targetComponentText: DialogInput + targetMethod: SetNextLineFlag + targetMethodText: 'SetNextLineFlag (): Void' + methodParameters: [] + saveReturnValue: 0 + returnValueVariableKey: + returnValueType: System.Void + showInherited: 0 + callMode: 0 +--- !u!114 &736071368 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 736071346} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3315ad2ebb85443909a1203d56d9344e, type: 3} + m_Name: + m_EditorClassIdentifier: + itemId: 16 + errorMessage: + indentLevel: 0 + duration: 2 --- !u!1 &891159641 GameObject: m_ObjectHideFlags: 0 @@ -3023,6 +3165,23 @@ MonoBehaviour: otherPropertyPath: constantValueGeneric: 4 compareType: 0 +--- !u!114 &1216870120 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2586c8e41f35d2f4fadde53020bf4207, type: 3} + m_Name: + m_EditorClassIdentifier: + go: {fileID: 1714427702} + thisPropertyPath: AudioSource.isPlaying + compareToType: 1 + other: {fileID: 0} + otherPropertyPath: + constantValueGeneric: 0 --- !u!114 &1300618896 MonoBehaviour: m_ObjectHideFlags: 0 @@ -3586,12 +3745,14 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: c4782cf42f2644447b9631f6e522160b, type: 3} m_Name: m_EditorClassIdentifier: + volume: .538999975 + loop: 1 audioSource: {fileID: 0} audioMode: 1 - beeps: [] + beepSounds: + - {fileID: 8300000, guid: 0cec78902391f4944881c028a5bd61e2, type: 3} + - {fileID: 8300000, guid: e63f93fa5d357441485c639326e9e8f7, type: 3} soundEffect: {fileID: 8300000, guid: 98d045067b3b7428c842dab1285b43a1, type: 3} - loop: 1 - volume: 1 --- !u!114 &1714427707 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Assets/Tests/TestAssets/Audio/Beep1.wav b/Assets/Tests/TestAssets/Audio/Beep1.wav new file mode 100644 index 00000000..a1ee7527 Binary files /dev/null and b/Assets/Tests/TestAssets/Audio/Beep1.wav differ diff --git a/Assets/Tests/TestAssets/Audio/Beep1.wav.meta b/Assets/Tests/TestAssets/Audio/Beep1.wav.meta new file mode 100644 index 00000000..d35662f5 --- /dev/null +++ b/Assets/Tests/TestAssets/Audio/Beep1.wav.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: 0cec78902391f4944881c028a5bd61e2 +timeCreated: 1440502847 +licenseType: Free +AudioImporter: + serializedVersion: 6 + defaultSettings: + loadType: 1 + sampleRateSetting: 0 + sampleRateOverride: 0 + compressionFormat: 0 + quality: .5 + conversionMode: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + preloadAudioData: 1 + loadInBackground: 0 + 3D: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/TestAssets/Audio/Beep2.wav b/Assets/Tests/TestAssets/Audio/Beep2.wav new file mode 100644 index 00000000..63293edf Binary files /dev/null and b/Assets/Tests/TestAssets/Audio/Beep2.wav differ diff --git a/Assets/Tests/TestAssets/Audio/Beep2.wav.meta b/Assets/Tests/TestAssets/Audio/Beep2.wav.meta new file mode 100644 index 00000000..92a8a716 --- /dev/null +++ b/Assets/Tests/TestAssets/Audio/Beep2.wav.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: e63f93fa5d357441485c639326e9e8f7 +timeCreated: 1440502847 +licenseType: Free +AudioImporter: + serializedVersion: 6 + defaultSettings: + loadType: 1 + sampleRateSetting: 0 + sampleRateOverride: 0 + compressionFormat: 0 + quality: .5 + conversionMode: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + preloadAudioData: 1 + loadInBackground: 0 + 3D: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/TestAssets/Audio/Beep3.wav b/Assets/Tests/TestAssets/Audio/Beep3.wav new file mode 100644 index 00000000..fe6e9a49 Binary files /dev/null and b/Assets/Tests/TestAssets/Audio/Beep3.wav differ diff --git a/Assets/Tests/TestAssets/Audio/Beep3.wav.meta b/Assets/Tests/TestAssets/Audio/Beep3.wav.meta new file mode 100644 index 00000000..14cb4a29 --- /dev/null +++ b/Assets/Tests/TestAssets/Audio/Beep3.wav.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: c40373edf37cb4a3f8b7b1103d03b1bb +timeCreated: 1440502847 +licenseType: Free +AudioImporter: + serializedVersion: 6 + defaultSettings: + loadType: 1 + sampleRateSetting: 0 + sampleRateOverride: 0 + compressionFormat: 0 + quality: .5 + conversionMode: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + preloadAudioData: 1 + loadInBackground: 0 + 3D: 0 + userData: + assetBundleName: + assetBundleVariant: