Chris Gregan
9 years ago
46 changed files with 8390 additions and 2821 deletions
Binary file not shown.
@ -0,0 +1,22 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 14a396b1562834718b2d52b9c4639264 |
||||
timeCreated: 1440511211 |
||||
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: |
Binary file not shown.
@ -0,0 +1,22 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 774486030b696474e8b3cf7f178123da |
||||
timeCreated: 1440509679 |
||||
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: |
Binary file not shown.
@ -0,0 +1,22 @@
|
||||
fileFormatVersion: 2 |
||||
guid: c53b7c20372e444c6bd7f2ac0729bbe2 |
||||
timeCreated: 1440509678 |
||||
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: |
@ -0,0 +1,49 @@
|
||||
using UnityEditor; |
||||
using UnityEngine; |
||||
using System.Collections; |
||||
using Rotorz.ReorderableList; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
|
||||
[CustomEditor (typeof(DialogInput))] |
||||
public class DialogInputEditor : Editor |
||||
{ |
||||
protected SerializedProperty clickModeProp; |
||||
protected SerializedProperty nextClickDelayProp; |
||||
protected SerializedProperty keyPressModeProp; |
||||
protected SerializedProperty shiftKeyEnabledProp; |
||||
protected SerializedProperty keyListProp; |
||||
|
||||
protected virtual void OnEnable() |
||||
{ |
||||
clickModeProp = serializedObject.FindProperty ("clickMode"); |
||||
nextClickDelayProp = serializedObject.FindProperty ("nextClickDelay"); |
||||
keyPressModeProp = serializedObject.FindProperty ("keyPressMode"); |
||||
shiftKeyEnabledProp = serializedObject.FindProperty ("shiftKeyEnabled"); |
||||
keyListProp = serializedObject.FindProperty ("keyList"); |
||||
} |
||||
|
||||
public override void OnInspectorGUI() |
||||
{ |
||||
serializedObject.Update(); |
||||
|
||||
DialogInput t = target as DialogInput; |
||||
|
||||
EditorGUILayout.PropertyField(clickModeProp); |
||||
EditorGUILayout.PropertyField(nextClickDelayProp); |
||||
|
||||
EditorGUILayout.PropertyField(keyPressModeProp); |
||||
if (t.keyPressMode == DialogInput.KeyPressMode.KeyPressed) |
||||
{ |
||||
EditorGUILayout.PropertyField(shiftKeyEnabledProp); |
||||
ReorderableListGUI.Title(new GUIContent("Key List", "Keycodes to check for user input")); |
||||
ReorderableListGUI.ListField(keyListProp); |
||||
} |
||||
|
||||
serializedObject.ApplyModifiedProperties(); |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,8 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 674037e0ad6e34e149f9bbab6940e155 |
||||
guid: 2a336080b178f4c239754dd614d6d6b4 |
||||
timeCreated: 1440156410 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -1,625 +0,0 @@
|
||||
using UnityEngine; |
||||
using UnityEngine.UI; |
||||
using UnityEngine.Events; |
||||
using System; |
||||
using System.Collections; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
|
||||
public class Dialog : MonoBehaviour |
||||
{ |
||||
public static Character speakingCharacter; |
||||
public static string prevStoryText; |
||||
|
||||
public float writingSpeed = 60; |
||||
public AudioClip writingSound; |
||||
[Range(0,1)] |
||||
public float writingVolume = 1f; |
||||
public bool loopWritingSound = true; |
||||
public bool beepPerCharacter = false; |
||||
public float slowBeepsAt = 10f; |
||||
public float fastBeepsAt = 30f; |
||||
public float punctuationPause = 0.25f; |
||||
public bool alwaysFadeDialog = false; |
||||
public float fadeDuration = 1f; |
||||
public LeanTweenType fadeEaseType; |
||||
public bool alwaysMoveDialog = false; |
||||
public Vector2 startPosition; |
||||
protected Vector2 endPosition; |
||||
public float moveSpeed = 1000f; |
||||
public LeanTweenType moveEaseType; |
||||
|
||||
[Tooltip("Click anywhere on screen to continue when set to true, or only on dialog when false.")] |
||||
public bool clickAnywhere = true; |
||||
|
||||
public Canvas dialogCanvas; |
||||
public Text nameText; |
||||
public Text storyText; |
||||
public Image characterImage; |
||||
public AudioClip characterTypingSound; |
||||
|
||||
protected float currentSpeed; |
||||
protected float currentPunctuationPause; |
||||
protected bool boldActive; |
||||
protected bool italicActive; |
||||
protected bool colorActive; |
||||
protected string colorText; |
||||
protected float clickCooldownTimer; |
||||
|
||||
protected bool wasPointerClicked; |
||||
|
||||
public DialogAudio audioController = new DialogAudio(); |
||||
|
||||
protected virtual void LateUpdate() |
||||
{ |
||||
wasPointerClicked = false; |
||||
|
||||
if (clickCooldownTimer > 0f) |
||||
{ |
||||
clickCooldownTimer -= Time.deltaTime; |
||||
clickCooldownTimer = Mathf.Max(0, clickCooldownTimer); |
||||
} |
||||
|
||||
if (clickCooldownTimer == 0f && |
||||
clickAnywhere && |
||||
Input.GetMouseButtonDown(0)) |
||||
{ |
||||
wasPointerClicked = true; |
||||
clickCooldownTimer = 0.2f; |
||||
} |
||||
} |
||||
|
||||
public virtual void ShowDialog(bool visible) |
||||
{ |
||||
if (dialogCanvas != null) |
||||
{ |
||||
LeanTween.cancel(dialogCanvas.gameObject); |
||||
CanvasGroup canvasGroup = dialogCanvas.GetComponent<CanvasGroup>(); |
||||
if (canvasGroup != null) |
||||
{ |
||||
canvasGroup.alpha = 1; |
||||
} |
||||
dialogCanvas.gameObject.SetActive(visible); |
||||
} |
||||
if (visible) |
||||
{ |
||||
// A new dialog is often shown as the result of a mouse click, so we need |
||||
// to make sure the previous click doesn't register on the new dialogue |
||||
wasPointerClicked = false; |
||||
clickCooldownTimer = 0.2f; |
||||
} |
||||
} |
||||
|
||||
public virtual void FadeInDialog() |
||||
{ |
||||
LeanTween.cancel(dialogCanvas.gameObject); |
||||
CanvasGroup canvasGroup = dialogCanvas.GetComponent<CanvasGroup>(); |
||||
if (canvasGroup != null) |
||||
{ |
||||
canvasGroup.alpha = 0; |
||||
} |
||||
dialogCanvas.gameObject.SetActive(true); |
||||
if (fadeDuration == 0) fadeDuration = float.Epsilon; |
||||
LeanTween.value(dialogCanvas.gameObject,0,1,fadeDuration).setEase(fadeEaseType).setOnUpdate( |
||||
(float fadeAmount)=>{ |
||||
if (canvasGroup != null) |
||||
{ |
||||
canvasGroup.alpha = fadeAmount; |
||||
} |
||||
} |
||||
).setOnComplete( |
||||
()=>{ |
||||
if (canvasGroup != null) |
||||
{ |
||||
canvasGroup.alpha = 1; |
||||
} |
||||
} |
||||
); |
||||
} |
||||
|
||||
public virtual void MoveInDialog() |
||||
{ |
||||
endPosition = this.transform.position; |
||||
float moveDuration = (Vector3.Distance(startPosition,this.transform.position)/moveSpeed); |
||||
if (moveSpeed == 0) moveDuration = float.Epsilon; |
||||
LeanTween.value(this.gameObject,(Vector2)startPosition,(Vector2)endPosition,moveDuration).setEase(moveEaseType).setOnUpdate( |
||||
(Vector3 updatePosition)=>{ |
||||
this.transform.position = updatePosition; |
||||
} |
||||
).setOnComplete( |
||||
()=>{ |
||||
this.transform.position = endPosition; |
||||
} |
||||
); |
||||
} |
||||
|
||||
public virtual void FadeOutDialog() |
||||
{ |
||||
CanvasGroup canvasGroup = dialogCanvas.GetComponent<CanvasGroup>(); |
||||
LeanTween.cancel(dialogCanvas.gameObject); |
||||
if (fadeDuration == 0) fadeDuration = float.Epsilon; |
||||
LeanTween.value(dialogCanvas.gameObject,1,0,fadeDuration).setEase(fadeEaseType).setOnUpdate( |
||||
(float fadeAmount)=>{ |
||||
if (canvasGroup != null) |
||||
{ |
||||
canvasGroup.alpha = fadeAmount; |
||||
} |
||||
} |
||||
).setOnComplete( |
||||
()=>{ |
||||
dialogCanvas.gameObject.SetActive(false); |
||||
if (canvasGroup != null) |
||||
{ |
||||
canvasGroup.alpha = 1; |
||||
} |
||||
} |
||||
); |
||||
} |
||||
|
||||
public virtual void MoveOutDialog() |
||||
{ |
||||
endPosition = this.transform.position; |
||||
float moveDuration = (Vector3.Distance(startPosition,this.transform.position)/moveSpeed); |
||||
if (moveSpeed == 0) moveDuration = float.Epsilon; |
||||
LeanTween.value(this.gameObject,(Vector2)endPosition,(Vector2)startPosition,moveDuration).setEase(moveEaseType).setOnUpdate( |
||||
(Vector3 updatePosition)=>{ |
||||
this.transform.position = updatePosition; |
||||
} |
||||
).setOnComplete( |
||||
()=>{ |
||||
this.transform.position = endPosition; |
||||
} |
||||
); |
||||
} |
||||
|
||||
public virtual void SetCharacter(Character character, Flowchart flowchart = null) |
||||
{ |
||||
if (character == null) |
||||
{ |
||||
if (characterImage != null) |
||||
characterImage.gameObject.SetActive(false); |
||||
if (nameText != null) |
||||
nameText.text = ""; |
||||
characterTypingSound = null; |
||||
} |
||||
else |
||||
{ |
||||
Character prevSpeakingCharacter = speakingCharacter; |
||||
speakingCharacter = character; |
||||
|
||||
// Dim portraits of non-speaking characters |
||||
foreach (Stage s in Stage.activeStages) |
||||
{ |
||||
if (s.dimPortraits) |
||||
{ |
||||
foreach (Character c in s.charactersOnStage) |
||||
{ |
||||
if (prevSpeakingCharacter != speakingCharacter) |
||||
{ |
||||
if (c != speakingCharacter) |
||||
{ |
||||
Portrait.SetDimmed(c, s, true); |
||||
} |
||||
else |
||||
{ |
||||
Portrait.SetDimmed(c, s, false); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
string characterName = character.nameText; |
||||
|
||||
if (characterName == "") |
||||
{ |
||||
// Use game object name as default |
||||
characterName = character.name; |
||||
} |
||||
|
||||
if (flowchart != null) |
||||
{ |
||||
characterName = flowchart.SubstituteVariables(characterName); |
||||
} |
||||
|
||||
characterTypingSound = character.soundEffect; |
||||
|
||||
SetCharacterName(characterName, character.nameColor); |
||||
} |
||||
} |
||||
|
||||
public virtual void SetCharacterImage(Sprite image) |
||||
{ |
||||
if (characterImage != null) |
||||
{ |
||||
if (image != null) |
||||
{ |
||||
characterImage.sprite = image; |
||||
characterImage.gameObject.SetActive(true); |
||||
} |
||||
else |
||||
{ |
||||
characterImage.gameObject.SetActive(false); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public virtual void SetCharacterName(string name, Color color) |
||||
{ |
||||
if (nameText != null) |
||||
{ |
||||
nameText.text = name; |
||||
nameText.color = color; |
||||
} |
||||
} |
||||
|
||||
protected virtual IEnumerator WriteText(string text, AudioClip voiceOverClip, Action onWritingComplete, Action onExitTag) |
||||
{ |
||||
storyText.text = ""; |
||||
|
||||
// Parse the story text & tag markup to produce a list of tokens for processing |
||||
DialogParser parser = new DialogParser(); |
||||
parser.Tokenize(text); |
||||
|
||||
if (parser.tokens.Count == 0) |
||||
{ |
||||
if (onWritingComplete != null) |
||||
{ |
||||
onWritingComplete(); |
||||
} |
||||
yield break; |
||||
} |
||||
|
||||
DialogText dialogText = new DialogText(); |
||||
dialogText.parentDialog = this; |
||||
dialogText.writingSpeed = writingSpeed; |
||||
dialogText.punctuationPause = punctuationPause; |
||||
dialogText.beepPerCharacter = beepPerCharacter; |
||||
dialogText.slowBeepsAt = slowBeepsAt; |
||||
dialogText.fastBeepsAt = fastBeepsAt; |
||||
|
||||
audioController.audioSource = GetComponent<AudioSource>(); |
||||
audioController.volume = writingVolume; |
||||
audioController.loop = loopWritingSound; |
||||
if (voiceOverClip != null) |
||||
{ |
||||
audioController.audioClip = voiceOverClip; |
||||
} |
||||
else if (characterTypingSound != null) |
||||
{ |
||||
audioController.audioClip = characterTypingSound; |
||||
} |
||||
else if (writingSound != null) |
||||
{ |
||||
audioController.audioClip = writingSound; |
||||
} |
||||
audioController.Play(); |
||||
|
||||
foreach (Token token in parser.tokens) |
||||
{ |
||||
switch (token.type) |
||||
{ |
||||
case TokenType.Words: |
||||
dialogText.Append(token.param); |
||||
break; |
||||
|
||||
case TokenType.BoldStart: |
||||
dialogText.boldActive = true; |
||||
break; |
||||
|
||||
case TokenType.BoldEnd: |
||||
dialogText.boldActive = false; |
||||
break; |
||||
|
||||
case TokenType.ItalicStart: |
||||
dialogText.italicActive = true; |
||||
break; |
||||
|
||||
case TokenType.ItalicEnd: |
||||
dialogText.italicActive = false; |
||||
break; |
||||
|
||||
case TokenType.ColorStart: |
||||
dialogText.colorActive = true; |
||||
dialogText.colorText = token.param; |
||||
break; |
||||
|
||||
case TokenType.ColorEnd: |
||||
dialogText.colorActive = false; |
||||
break; |
||||
|
||||
case TokenType.Wait: |
||||
float duration = 1f; |
||||
if (!Single.TryParse(token.param, out duration)) |
||||
{ |
||||
duration = 1f; |
||||
} |
||||
yield return StartCoroutine(WaitForSecondsOrInput(duration)); |
||||
break; |
||||
|
||||
case TokenType.WaitForInputNoClear: |
||||
OnWaitForInputTag(true); |
||||
yield return StartCoroutine(WaitForInput(null)); |
||||
OnWaitForInputTag(false); |
||||
break; |
||||
|
||||
case TokenType.WaitForInputAndClear: |
||||
OnWaitForInputTag(true); |
||||
yield return StartCoroutine(WaitForInput(null)); |
||||
OnWaitForInputTag(false); |
||||
currentSpeed = writingSpeed; |
||||
dialogText.Clear(); |
||||
audioController.Stop(); |
||||
break; |
||||
|
||||
case TokenType.WaitOnPunctuationStart: |
||||
float newPunctuationPause = 0f; |
||||
if (!Single.TryParse(token.param, out newPunctuationPause)) |
||||
{ |
||||
newPunctuationPause = 0f; |
||||
} |
||||
dialogText.punctuationPause = newPunctuationPause; |
||||
break; |
||||
case TokenType.WaitOnPunctuationEnd: |
||||
dialogText.punctuationPause = punctuationPause; |
||||
break; |
||||
|
||||
case TokenType.Clear: |
||||
dialogText.Clear(); |
||||
break; |
||||
|
||||
case TokenType.SpeedStart: |
||||
float newSpeed = 0; |
||||
if (!Single.TryParse(token.param, out newSpeed)) |
||||
{ |
||||
newSpeed = 0f; |
||||
} |
||||
dialogText.writingSpeed = newSpeed; |
||||
break; |
||||
|
||||
case TokenType.SpeedEnd: |
||||
dialogText.writingSpeed = writingSpeed; |
||||
break; |
||||
|
||||
case TokenType.Exit: |
||||
if (onExitTag != null) |
||||
{ |
||||
prevStoryText = storyText.text; |
||||
audioController.Stop(); |
||||
onExitTag(); |
||||
} |
||||
yield break; |
||||
|
||||
case TokenType.Message: |
||||
Flowchart.BroadcastFungusMessage(token.param); |
||||
break; |
||||
case TokenType.VerticalPunch: |
||||
float vPunchIntensity = 0; |
||||
if (!Single.TryParse(token.param, out vPunchIntensity)) |
||||
{ |
||||
vPunchIntensity = 0f; |
||||
} |
||||
VerticalPunch(vPunchIntensity); |
||||
break; |
||||
case TokenType.HorizontalPunch: |
||||
float hPunchIntensity = 0; |
||||
if (!Single.TryParse(token.param, out hPunchIntensity)) |
||||
{ |
||||
hPunchIntensity = 0f; |
||||
} |
||||
HorizontalPunch(hPunchIntensity); |
||||
break; |
||||
case TokenType.Shake: |
||||
float shakeIntensity = 0; |
||||
if (!Single.TryParse(token.param, out shakeIntensity)) |
||||
{ |
||||
shakeIntensity = 0f; |
||||
} |
||||
Shake(shakeIntensity); |
||||
break; |
||||
case TokenType.Shiver: |
||||
float shiverIntensity = 0; |
||||
if (!Single.TryParse(token.param, out shiverIntensity)) |
||||
{ |
||||
shiverIntensity = 0f; |
||||
} |
||||
Shiver(shiverIntensity); |
||||
break; |
||||
case TokenType.Flash: |
||||
float flashDuration = 0; |
||||
if (!Single.TryParse(token.param, out flashDuration)) |
||||
{ |
||||
flashDuration = 0f; |
||||
} |
||||
Flash(flashDuration); |
||||
break; |
||||
case TokenType.Audio: |
||||
{ |
||||
AudioSource audioSource = FindAudio(token.param); |
||||
if (audioSource != null) |
||||
{ |
||||
audioSource.PlayOneShot(audioSource.clip); |
||||
} |
||||
} |
||||
break; |
||||
case TokenType.AudioLoop: |
||||
{ |
||||
AudioSource audioSource = FindAudio(token.param); |
||||
if (audioSource != null) |
||||
{ |
||||
audioSource.Play(); |
||||
audioSource.loop = true; |
||||
} |
||||
} |
||||
break; |
||||
case TokenType.AudioPause: |
||||
{ |
||||
AudioSource audioSource = FindAudio(token.param); |
||||
if (audioSource != null) |
||||
{ |
||||
audioSource.Pause (); |
||||
} |
||||
} |
||||
break; |
||||
case TokenType.AudioStop: |
||||
{ |
||||
AudioSource audioSource = FindAudio(token.param); |
||||
if (audioSource != null) |
||||
{ |
||||
audioSource.Pause (); |
||||
} |
||||
} |
||||
break; |
||||
} |
||||
|
||||
// Update text writing |
||||
while (!dialogText.UpdateGlyphs(wasPointerClicked)) |
||||
{ |
||||
storyText.text = dialogText.GetDialogText(); |
||||
yield return null; |
||||
} |
||||
storyText.text = dialogText.GetDialogText(); |
||||
wasPointerClicked = false; |
||||
|
||||
// Now process next token |
||||
} |
||||
|
||||
prevStoryText = storyText.text; |
||||
|
||||
audioController.Stop(); |
||||
|
||||
if (onWritingComplete != null) |
||||
{ |
||||
onWritingComplete(); |
||||
} |
||||
|
||||
yield break; |
||||
} |
||||
|
||||
protected virtual AudioSource FindAudio(string audioObjectName) |
||||
{ |
||||
GameObject go = GameObject.Find(audioObjectName); |
||||
if (go == null) |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
return go.GetComponent<AudioSource>(); |
||||
} |
||||
|
||||
protected virtual void VerticalPunch(float intensity) |
||||
{ |
||||
iTween.ShakePosition(this.gameObject, new Vector3(0f, intensity, 0f), 0.5f); |
||||
} |
||||
|
||||
protected virtual void HorizontalPunch(float intensity) |
||||
{ |
||||
iTween.ShakePosition(this.gameObject, new Vector3(intensity, 0f, 0f), 0.5f); |
||||
} |
||||
|
||||
protected virtual void Shake(float intensity) |
||||
{ |
||||
iTween.ShakePosition(this.gameObject, new Vector3(intensity, intensity, 0f), 0.5f); |
||||
} |
||||
|
||||
protected virtual void Shiver(float intensity) |
||||
{ |
||||
iTween.ShakePosition(this.gameObject, new Vector3(intensity, intensity, 0f), 1f); |
||||
} |
||||
|
||||
protected virtual void Flash(float duration) |
||||
{ |
||||
CameraController cameraController = CameraController.GetInstance(); |
||||
cameraController.screenFadeTexture = CameraController.CreateColorTexture(new Color(1f,1f,1f,1f), 32, 32); |
||||
cameraController.Fade(1f, duration, delegate { |
||||
cameraController.screenFadeTexture = CameraController.CreateColorTexture(new Color(1f,1f,1f,1f), 32, 32); |
||||
cameraController.Fade(0f, duration, null); |
||||
}); |
||||
} |
||||
|
||||
public virtual void Clear() |
||||
{ |
||||
ClearStoryText(); |
||||
|
||||
// Reset control variables |
||||
currentSpeed = 60; |
||||
currentPunctuationPause = 0.25f; |
||||
boldActive = false; |
||||
italicActive = false; |
||||
colorActive = false; |
||||
colorText = ""; |
||||
|
||||
// Kill any active write coroutine |
||||
StopAllCoroutines(); |
||||
} |
||||
|
||||
protected virtual void ClearStoryText() |
||||
{ |
||||
if (storyText != null) |
||||
{ |
||||
storyText.text = ""; |
||||
} |
||||
} |
||||
|
||||
protected virtual IEnumerator WaitForInput(Action onInput) |
||||
{ |
||||
while (!wasPointerClicked) |
||||
{ |
||||
yield return null; |
||||
} |
||||
wasPointerClicked = false; |
||||
|
||||
if (onInput != null) |
||||
{ |
||||
// Stop all tweening portraits |
||||
foreach( Character c in Character.activeCharacters ) |
||||
{ |
||||
if (c.state.portraitImage != null) |
||||
{ |
||||
if (LeanTween.isTweening(c.state.portraitImage.gameObject)) |
||||
{ |
||||
LeanTween.cancel(c.state.portraitImage.gameObject, true); |
||||
|
||||
Portrait.SetRectTransform(c.state.portraitImage.rectTransform, c.state.position); |
||||
if (c.state.dimmed == true) |
||||
{ |
||||
c.state.portraitImage.color = new Color(0.5f,0.5f,0.5f,1f); |
||||
} |
||||
else |
||||
{ |
||||
c.state.portraitImage.color = Color.white; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
onInput(); |
||||
} |
||||
} |
||||
|
||||
protected virtual IEnumerator WaitForSecondsOrInput(float duration) |
||||
{ |
||||
float timer = duration; |
||||
while (timer > 0 && !wasPointerClicked) |
||||
{ |
||||
timer -= Time.deltaTime; |
||||
yield return null; |
||||
} |
||||
|
||||
wasPointerClicked = false; |
||||
} |
||||
|
||||
protected virtual void OnWaitForInputTag(bool waiting) |
||||
{} |
||||
|
||||
public virtual void OnPointerClick() |
||||
{ |
||||
if (clickCooldownTimer == 0f) |
||||
{ |
||||
wasPointerClicked = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,84 +0,0 @@
|
||||
using UnityEngine; |
||||
using System.Collections; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
|
||||
/* |
||||
* Helper class to manage play, pause & stop operations on voiceover and writing sound effects |
||||
*/ |
||||
public class DialogAudio |
||||
{ |
||||
public AudioSource audioSource; |
||||
public AudioClip audioClip; |
||||
public float volume; |
||||
public bool loop; |
||||
|
||||
public virtual void Play() |
||||
{ |
||||
if (audioSource == null || |
||||
audioClip == null) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
audioSource.clip = audioClip; |
||||
audioSource.loop = loop; |
||||
|
||||
// Fade in the audio at start |
||||
LeanTween.value(audioSource.gameObject, 0f, volume, 0.1f).setOnUpdate( (value) => { |
||||
audioSource.volume = value; |
||||
}); |
||||
|
||||
audioSource.Play(); |
||||
} |
||||
|
||||
public virtual void Pause() |
||||
{ |
||||
if (audioSource == null) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
// Fade out the audio |
||||
// There's an audible click if you call audioSource.Pause() so instead just |
||||
// drop the volume to 0. |
||||
LeanTween.value(audioSource.gameObject, volume, 0f, 0.1f).setOnUpdate( (value) => { |
||||
audioSource.volume = value; |
||||
}); |
||||
} |
||||
|
||||
public virtual void Stop() |
||||
{ |
||||
if (audioSource == null) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
// Fade out the audio |
||||
LeanTween.value(audioSource.gameObject, audioSource.volume, 0f, 0.1f).setOnUpdate( (value) => { |
||||
audioSource.volume = value; |
||||
}).setOnComplete( () => { |
||||
// There's an audible click if you call audioSource.Stop() so instead we just switch off |
||||
// looping and let the audio stop automatically at the end of the clip |
||||
audioSource.loop = false; |
||||
}); |
||||
} |
||||
|
||||
public virtual void Resume() |
||||
{ |
||||
if (audioSource == null) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
audioSource.volume = volume; |
||||
if (!audioSource.isPlaying) |
||||
{ |
||||
audioSource.loop = loop; |
||||
audioSource.Play(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,168 @@
|
||||
using UnityEngine; |
||||
using UnityEngine.EventSystems; |
||||
using System.Collections; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
public interface IDialogInputListener |
||||
{ |
||||
void OnNextLineEvent(); |
||||
} |
||||
|
||||
public class DialogInput : MonoBehaviour |
||||
{ |
||||
public enum ClickMode |
||||
{ |
||||
Disabled, // Clicking disabled |
||||
ClickAnywhere, // Click anywhere on screen to advance |
||||
ClickOnDialog, // Click anywhere on Say Dialog to advance |
||||
ClickOnButton // Click on continue button to advance |
||||
} |
||||
|
||||
public enum KeyPressMode |
||||
{ |
||||
Disabled, // Key pressing disabled |
||||
AnyKey, // Press any key to continue |
||||
KeyPressed // Press one of specified keys to advance |
||||
} |
||||
|
||||
[Tooltip("Click to advance story")] |
||||
public ClickMode clickMode; |
||||
|
||||
[Tooltip("Press a key to advance story")] |
||||
public KeyPressMode keyPressMode; |
||||
|
||||
[Tooltip("Hold down shift while pressing a key to advance though story instantly")] |
||||
public bool shiftKeyEnabled = true; |
||||
|
||||
[Tooltip("Delay between consecutive clicks. Useful to prevent accidentally clicking through story.")] |
||||
public float nextClickDelay = 0f; |
||||
|
||||
[Tooltip("Keycodes to check for key presses")] |
||||
public KeyCode[] keyList; |
||||
|
||||
protected bool dialogClickedFlag; |
||||
|
||||
protected bool nextLineInputFlag; |
||||
|
||||
protected float ignoreClickTimer; |
||||
|
||||
/** |
||||
* Trigger next line input event from script. |
||||
*/ |
||||
public void SetNextLineFlag() |
||||
{ |
||||
nextLineInputFlag = true; |
||||
} |
||||
|
||||
/** |
||||
* Set the dialog clicked flag (usually from an Event Trigger component in the dialog UI) |
||||
*/ |
||||
public void SetDialogClickedFlag() |
||||
{ |
||||
// Ignore repeat clicks for a short time to prevent accidentally clicking through the character dialogue |
||||
if (ignoreClickTimer > 0f) |
||||
{ |
||||
return; |
||||
} |
||||
ignoreClickTimer = nextClickDelay; |
||||
|
||||
// Only applies in Click On Dialog mode |
||||
if (clickMode == ClickMode.ClickOnDialog) |
||||
{ |
||||
dialogClickedFlag = true; |
||||
} |
||||
} |
||||
|
||||
public void SetButtonClickedFlag() |
||||
{ |
||||
// Only applies if clicking is not disabled |
||||
if (clickMode != ClickMode.Disabled) |
||||
{ |
||||
SetNextLineFlag(); |
||||
} |
||||
} |
||||
|
||||
protected virtual void Update() |
||||
{ |
||||
switch (keyPressMode) |
||||
{ |
||||
case KeyPressMode.Disabled: |
||||
break; |
||||
case KeyPressMode.AnyKey: |
||||
if (Input.anyKeyDown) |
||||
{ |
||||
SetNextLineFlag(); |
||||
} |
||||
break; |
||||
case KeyPressMode.KeyPressed: |
||||
foreach (KeyCode keyCode in keyList) |
||||
{ |
||||
if (shiftKeyEnabled && |
||||
(Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))) |
||||
{ |
||||
if (Input.GetKey(keyCode)) |
||||
{ |
||||
SetNextLineFlag(); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
if (Input.GetKeyDown(keyCode)) |
||||
{ |
||||
SetNextLineFlag(); |
||||
} |
||||
} |
||||
} |
||||
break; |
||||
} |
||||
|
||||
switch (clickMode) |
||||
{ |
||||
case ClickMode.Disabled: |
||||
break; |
||||
case ClickMode.ClickAnywhere: |
||||
if (Input.GetMouseButtonDown(0)) |
||||
{ |
||||
SetNextLineFlag(); |
||||
} |
||||
break; |
||||
case ClickMode.ClickOnDialog: |
||||
if (dialogClickedFlag) |
||||
{ |
||||
SetNextLineFlag(); |
||||
dialogClickedFlag = false; |
||||
} |
||||
break; |
||||
} |
||||
|
||||
if (ignoreClickTimer > 0f) |
||||
{ |
||||
ignoreClickTimer = Mathf.Max (ignoreClickTimer - Time.deltaTime, 0f); |
||||
} |
||||
|
||||
// Ignore input events if a Menu is being displayed |
||||
if (MenuDialog.activeMenuDialog != null) |
||||
{ |
||||
if (MenuDialog.activeMenuDialog.gameObject.activeSelf) |
||||
{ |
||||
dialogClickedFlag = false; |
||||
nextLineInputFlag = false; |
||||
} |
||||
} |
||||
|
||||
// Tell any listeners to move to the next line |
||||
if (nextLineInputFlag) |
||||
{ |
||||
IDialogInputListener[] inputListeners = gameObject.GetComponentsInChildren<IDialogInputListener>(); |
||||
foreach (IDialogInputListener inputListener in inputListeners) |
||||
{ |
||||
inputListener.OnNextLineEvent(); |
||||
} |
||||
nextLineInputFlag = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
@ -1,8 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: b7e8f397d6557484f91f9992f702cff5 |
||||
guid: 43b85556abd314f3f870c18c013fdcef |
||||
timeCreated: 1439996546 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -1,250 +0,0 @@
|
||||
using UnityEngine; |
||||
using System.Collections; |
||||
using System.Collections.Generic; |
||||
using System.Text.RegularExpressions; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
public enum TokenType |
||||
{ |
||||
Words, // A string of words |
||||
BoldStart, // b |
||||
BoldEnd, // /b |
||||
ItalicStart, // i |
||||
ItalicEnd, // /i |
||||
ColorStart, // color=red |
||||
ColorEnd, // /color |
||||
Wait, // w, w=0.5 |
||||
WaitForInputNoClear, // wi |
||||
WaitForInputAndClear, // wc |
||||
WaitOnPunctuationStart, // wp, wp=0.5 |
||||
WaitOnPunctuationEnd, // /wp |
||||
Clear, // c |
||||
SpeedStart, // s, s=60 |
||||
SpeedEnd, // /s |
||||
Exit, // x |
||||
Message, // m=MessageName |
||||
VerticalPunch, // {vpunch=0.5} |
||||
HorizontalPunch, // {hpunch=0.5} |
||||
Shake, // {shake=0.5} |
||||
Shiver, // {shiver=0.5} |
||||
Flash, // {flash=0.5} |
||||
Audio, // {audio=Sound} |
||||
AudioLoop, // {audioloop=Sound} |
||||
AudioPause, // {audiopause=Sound} |
||||
AudioStop // {audiostop=Sound} |
||||
} |
||||
|
||||
public class Token |
||||
{ |
||||
public TokenType type = TokenType.Words; |
||||
public string param = ""; |
||||
} |
||||
|
||||
public class DialogParser |
||||
{ |
||||
public List<Token> tokens = new List<Token>(); |
||||
|
||||
public virtual void Tokenize(string storyText) |
||||
{ |
||||
tokens.Clear(); |
||||
|
||||
string pattern = @"\{.*?\}"; |
||||
Regex myRegex = new Regex(pattern); |
||||
|
||||
Match m = myRegex.Match(storyText); // m is the first match |
||||
|
||||
int position = 0; |
||||
while (m.Success) |
||||
{ |
||||
// Get bit leading up to tag |
||||
string preText = storyText.Substring(position, m.Index - position); |
||||
string tagText = m.Value; |
||||
|
||||
AddWordsToken(tokens, preText); |
||||
AddTagToken(tokens, tagText); |
||||
|
||||
position = m.Index + tagText.Length; |
||||
m = m.NextMatch(); |
||||
} |
||||
|
||||
if (position < storyText.Length) |
||||
{ |
||||
string postText = storyText.Substring(position, storyText.Length - position); |
||||
if (postText.Length > 0) |
||||
{ |
||||
AddWordsToken(tokens, postText); |
||||
} |
||||
} |
||||
|
||||
// Remove all leading whitespace & newlines after a {c} or {wc} tag |
||||
// These characters are usually added for legibility when editing, but are not |
||||
// desireable when viewing the text in game. |
||||
bool trimLeading = false; |
||||
foreach (Token token in tokens) |
||||
{ |
||||
if (trimLeading && |
||||
token.type == TokenType.Words) |
||||
{ |
||||
token.param.TrimStart(' ', '\t', '\r', '\n'); |
||||
} |
||||
|
||||
if (token.type == TokenType.Clear || |
||||
token.type == TokenType.WaitForInputAndClear) |
||||
{ |
||||
trimLeading = true; |
||||
} |
||||
else |
||||
{ |
||||
trimLeading = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected static void AddWordsToken(List<Token> tokenList, string words) |
||||
{ |
||||
Token token = new Token(); |
||||
token.type = TokenType.Words; |
||||
token.param = words; |
||||
tokenList.Add(token); |
||||
} |
||||
|
||||
protected virtual void AddTagToken(List<Token> tokenList, string tagText) |
||||
{ |
||||
if (tagText.Length < 3 || |
||||
tagText.Substring(0,1) != "{" || |
||||
tagText.Substring(tagText.Length - 1,1) != "}") |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
string tag = tagText.Substring(1, tagText.Length - 2); |
||||
|
||||
TokenType type = TokenType.Words; |
||||
string paramText = ""; |
||||
|
||||
if (tag == "b") |
||||
{ |
||||
type = TokenType.BoldStart; |
||||
} |
||||
else if (tag == "/b") |
||||
{ |
||||
type = TokenType.BoldEnd; |
||||
} |
||||
else if (tag == "i") |
||||
{ |
||||
type = TokenType.ItalicStart; |
||||
} |
||||
else if (tag == "/i") |
||||
{ |
||||
type = TokenType.ItalicEnd; |
||||
} |
||||
else if (tag.StartsWith("color=")) |
||||
{ |
||||
type = TokenType.ColorStart; |
||||
paramText = tag.Substring(6, tag.Length - 6); |
||||
} |
||||
else if (tag == "/color") |
||||
{ |
||||
type = TokenType.ColorEnd; |
||||
} |
||||
else if (tag == "wi") |
||||
{ |
||||
type = TokenType.WaitForInputNoClear; |
||||
} |
||||
if (tag == "wc") |
||||
{ |
||||
type = TokenType.WaitForInputAndClear; |
||||
} |
||||
else if (tag.StartsWith("wp=")) |
||||
{ |
||||
type = TokenType.WaitOnPunctuationStart; |
||||
paramText = tag.Substring(3, tag.Length - 3); |
||||
} |
||||
else if (tag == "wp") |
||||
{ |
||||
type = TokenType.WaitOnPunctuationStart; |
||||
} |
||||
else if (tag == "/wp") |
||||
{ |
||||
type = TokenType.WaitOnPunctuationEnd; |
||||
} |
||||
else if (tag.StartsWith("w=")) |
||||
{ |
||||
type = TokenType.Wait; |
||||
paramText = tag.Substring(2, tag.Length - 2); |
||||
} |
||||
else if (tag == "w") |
||||
{ |
||||
type = TokenType.Wait; |
||||
} |
||||
else if (tag == "c") |
||||
{ |
||||
type = TokenType.Clear; |
||||
} |
||||
else if (tag.StartsWith("s=")) |
||||
{ |
||||
type = TokenType.SpeedStart; |
||||
paramText = tag.Substring(2, tag.Length - 2); |
||||
} |
||||
else if (tag == "s") |
||||
{ |
||||
type = TokenType.SpeedStart; |
||||
} |
||||
else if (tag == "/s") |
||||
{ |
||||
type = TokenType.SpeedEnd; |
||||
} |
||||
else if (tag == "x") |
||||
{ |
||||
type = TokenType.Exit; |
||||
} |
||||
else if (tag.StartsWith("m=")) |
||||
{ |
||||
type = TokenType.Message; |
||||
paramText = tag.Substring(2, tag.Length - 2); |
||||
} |
||||
else if (tag.StartsWith("vpunch=")) |
||||
{ |
||||
type = TokenType.VerticalPunch; |
||||
paramText = tag.Substring(7, tag.Length - 7); |
||||
} |
||||
else if (tag.StartsWith("hpunch=")) |
||||
{ |
||||
type = TokenType.HorizontalPunch; |
||||
paramText = tag.Substring(7, tag.Length - 7); |
||||
} |
||||
else if (tag.StartsWith("shake=")) |
||||
{ |
||||
type = TokenType.Shake; |
||||
paramText = tag.Substring(6, tag.Length - 6); |
||||
} |
||||
else if (tag.StartsWith("shiver=")) |
||||
{ |
||||
type = TokenType.Shiver; |
||||
paramText = tag.Substring(7, tag.Length - 7); |
||||
} |
||||
else if (tag.StartsWith("flash=")) |
||||
{ |
||||
type = TokenType.Flash; |
||||
paramText = tag.Substring(6, tag.Length - 6); |
||||
} |
||||
else if (tag.StartsWith("audio=")) |
||||
{ |
||||
type = TokenType.Audio; |
||||
paramText = tag.Substring(6, tag.Length - 6); |
||||
} |
||||
else if (tag.StartsWith("audioloop=")) |
||||
{ |
||||
type = TokenType.AudioLoop; |
||||
paramText = tag.Substring(10, tag.Length - 10); |
||||
} |
||||
Token token = new Token(); |
||||
token.type = type; |
||||
token.param = paramText.Trim(); |
||||
|
||||
tokenList.Add(token); |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,222 +0,0 @@
|
||||
using UnityEngine; |
||||
using System.Collections; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
public class Glyph |
||||
{ |
||||
public float hideTimer; |
||||
public string character; |
||||
public bool boldActive; |
||||
public bool italicActive; |
||||
public bool colorActive; |
||||
public string colorText; |
||||
public bool hasPunctuationPause; |
||||
} |
||||
|
||||
public class DialogText |
||||
{ |
||||
protected List<Glyph> glyphs = new List<Glyph>(); |
||||
protected bool oneBeep = false; |
||||
|
||||
public bool boldActive { get; set; } |
||||
public bool italicActive { get; set; } |
||||
public bool colorActive { get; set; } |
||||
public string colorText { get; set; } |
||||
public float writingSpeed { get; set; } |
||||
public float punctuationPause { get; set; } |
||||
public float slowBeepsAt { get; set; } |
||||
public float fastBeepsAt { get; set; } |
||||
public bool beepPerCharacter { get; set; } |
||||
public Dialog parentDialog { get; set; } |
||||
|
||||
public virtual void Clear() |
||||
{ |
||||
glyphs.Clear(); |
||||
} |
||||
|
||||
public virtual void Append(string words) |
||||
{ |
||||
if (beepPerCharacter && (writingSpeed <= slowBeepsAt || writingSpeed >= fastBeepsAt)) // beeps match character speed at these speeds |
||||
{ |
||||
oneBeep = true; |
||||
} |
||||
else |
||||
{ |
||||
oneBeep = false; |
||||
} |
||||
|
||||
float hideTimer = 0f; |
||||
if (writingSpeed > 0f) |
||||
{ |
||||
hideTimer = 1f / writingSpeed; |
||||
} |
||||
|
||||
bool doPunctuationPause = false; |
||||
for (int i = 0; i < words.Length; ++i) |
||||
{ |
||||
char c = words[i]; |
||||
|
||||
// Ignore leading newlines |
||||
if (glyphs.Count == 0 && c == '\n') |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
Glyph glyph = new Glyph(); |
||||
glyph.hideTimer = hideTimer; |
||||
if (doPunctuationPause && writingSpeed != 0) |
||||
{ |
||||
glyph.hasPunctuationPause = true; |
||||
glyph.hideTimer += punctuationPause; |
||||
doPunctuationPause = false; |
||||
} |
||||
|
||||
glyph.character = c.ToString(); |
||||
glyph.boldActive = boldActive; |
||||
glyph.italicActive = italicActive; |
||||
glyph.colorActive = colorActive; |
||||
glyph.colorText = colorText; |
||||
glyphs.Add(glyph); |
||||
|
||||
if (IsPunctuation(c)) // If punctuation, do punctuation pause |
||||
{ |
||||
doPunctuationPause = true; |
||||
} |
||||
|
||||
// Special case: pause just before open parentheses |
||||
if (i < words.Length - 2) |
||||
{ |
||||
if (words[i + 1] == '(') |
||||
{ |
||||
doPunctuationPause = true; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected virtual bool IsPunctuation(char character) |
||||
{ |
||||
return character == '.' || |
||||
character == '?' || |
||||
character == '!' || |
||||
character == ',' || |
||||
character == ':' || |
||||
character == ';' || |
||||
character == ')'; |
||||
} |
||||
|
||||
/** |
||||
* Returns true when all glyphs are visible. |
||||
*/ |
||||
public virtual bool UpdateGlyphs(bool instantComplete) |
||||
{ |
||||
AudioSource typingAudio = parentDialog.GetComponent<AudioSource>(); |
||||
|
||||
float elapsedTime = Time.deltaTime; |
||||
|
||||
foreach (Glyph glyph in glyphs) |
||||
{ |
||||
if (instantComplete) |
||||
{ |
||||
glyph.hideTimer = 0f; |
||||
continue; |
||||
} |
||||
|
||||
if (glyph.hideTimer > 0f) |
||||
{ |
||||
// Don't pause audio on punctuation pause as it's very noticeable and distracting |
||||
if (glyph.hasPunctuationPause) |
||||
{ |
||||
parentDialog.audioController.Pause(); |
||||
} |
||||
|
||||
bool finished = false; |
||||
if (elapsedTime > glyph.hideTimer) |
||||
{ |
||||
elapsedTime -= glyph.hideTimer; |
||||
glyph.hideTimer = 0f; |
||||
// Some elapsed time left over, so carry on to next glyph |
||||
if ((oneBeep && typingAudio != null)) |
||||
{ |
||||
if (!typingAudio.isPlaying && |
||||
(glyph.character != " " && glyph.character != "\t" && glyph.character != "\n" ) ) |
||||
{ |
||||
typingAudio.PlayOneShot(typingAudio.clip); |
||||
} |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
glyph.hideTimer -= elapsedTime; |
||||
glyph.hideTimer = Mathf.Max(glyph.hideTimer, 0f); |
||||
finished = true; |
||||
} |
||||
|
||||
// Check if we need to restore audio after a punctuation pause |
||||
if (glyph.hideTimer == 0f) |
||||
{ |
||||
parentDialog.audioController.Resume(); |
||||
} |
||||
|
||||
if (finished) |
||||
{ |
||||
return false; // Glyph is still hidden |
||||
} |
||||
} |
||||
} |
||||
|
||||
parentDialog.audioController.Stop(); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
public virtual string GetDialogText() |
||||
{ |
||||
string outputText = ""; |
||||
|
||||
bool hideGlyphs = false; |
||||
foreach (Glyph glyph in glyphs) |
||||
{ |
||||
// Wrap each individual character in rich text markup tags (if required) |
||||
string start = ""; |
||||
string end = ""; |
||||
if (glyph.boldActive) |
||||
{ |
||||
start += "<b>"; |
||||
end += "</b>"; |
||||
} |
||||
if (glyph.italicActive) |
||||
{ |
||||
start += "<i>"; |
||||
end = "</i>" + end; // Have to nest tags correctly |
||||
} |
||||
|
||||
if (!hideGlyphs && |
||||
glyph.hideTimer > 0f) |
||||
{ |
||||
hideGlyphs = true; |
||||
outputText += "<color=#FFFFFF00>"; |
||||
} |
||||
|
||||
if (!hideGlyphs && |
||||
glyph.colorActive) |
||||
{ |
||||
start += "<color=" + glyph.colorText + ">"; |
||||
end += "</color>"; |
||||
} |
||||
|
||||
outputText += start + glyph.character + end; |
||||
} |
||||
|
||||
if (hideGlyphs) |
||||
{ |
||||
outputText += "</color>"; |
||||
} |
||||
|
||||
return outputText; |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,57 @@
|
||||
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 targetAudioSourceProp; |
||||
protected SerializedProperty audioModeProp; |
||||
protected SerializedProperty beepSoundsProp; |
||||
protected SerializedProperty soundEffectProp; |
||||
protected SerializedProperty inputSoundProp; |
||||
|
||||
protected virtual void OnEnable() |
||||
{ |
||||
volumeProp = serializedObject.FindProperty("volume"); |
||||
loopProp = serializedObject.FindProperty("loop"); |
||||
targetAudioSourceProp = serializedObject.FindProperty("targetAudioSource"); |
||||
inputSoundProp = serializedObject.FindProperty("inputSound"); |
||||
audioModeProp = serializedObject.FindProperty("audioMode"); |
||||
beepSoundsProp = serializedObject.FindProperty("beepSounds"); |
||||
soundEffectProp = serializedObject.FindProperty("soundEffect"); |
||||
} |
||||
|
||||
public override void OnInspectorGUI() |
||||
{ |
||||
serializedObject.Update(); |
||||
|
||||
EditorGUILayout.PropertyField(volumeProp); |
||||
EditorGUILayout.PropertyField(loopProp); |
||||
EditorGUILayout.PropertyField(targetAudioSourceProp); |
||||
EditorGUILayout.PropertyField(inputSoundProp); |
||||
|
||||
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); |
||||
} |
||||
else |
||||
{ |
||||
EditorGUILayout.PropertyField(soundEffectProp); |
||||
} |
||||
|
||||
serializedObject.ApplyModifiedProperties(); |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,8 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 4aada7218611f4257bddea1cd4ab8fcf |
||||
guid: f07068d2254394c5d9367a7b738d8c86 |
||||
timeCreated: 1440497180 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,189 @@
|
||||
using UnityEngine; |
||||
using System.Collections; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
/* |
||||
* Manages audio effects for Dialogs |
||||
*/ |
||||
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. If none is selected then one will be created.")] |
||||
public AudioSource targetAudioSource; |
||||
|
||||
public enum AudioMode |
||||
{ |
||||
Beeps, // Use short beep sound effects |
||||
SoundEffect, // Use long looping sound effect |
||||
} |
||||
|
||||
[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. Will play maximum of one beep per character, with only one beep playing at a time.")] |
||||
public List<AudioClip> beepSounds = new List<AudioClip>(); |
||||
|
||||
[Tooltip("Long playing sound effect to play when writing text")] |
||||
public AudioClip soundEffect; |
||||
|
||||
[Tooltip("Sound effect to play on user input (e.g. a click)")] |
||||
public AudioClip inputSound; |
||||
|
||||
protected float targetVolume = 0f; |
||||
|
||||
// When true, a beep will be played on every written character glyph |
||||
protected bool playBeeps; |
||||
|
||||
public virtual void SetAudioMode(AudioMode mode) |
||||
{ |
||||
audioMode = mode; |
||||
} |
||||
|
||||
protected virtual void Awake() |
||||
{ |
||||
// Need to do this in Awake rather than Start due to init order issues |
||||
if (targetAudioSource == null) |
||||
{ |
||||
targetAudioSource = GetComponent<AudioSource>(); |
||||
if (targetAudioSource == null) |
||||
{ |
||||
targetAudioSource = gameObject.AddComponent<AudioSource>(); |
||||
} |
||||
} |
||||
|
||||
targetAudioSource.volume = 0f; |
||||
} |
||||
|
||||
public virtual void Play(AudioClip audioClip) |
||||
{ |
||||
if (targetAudioSource == null || |
||||
(audioMode == AudioMode.SoundEffect && soundEffect == null && audioClip == null) || |
||||
(audioMode == AudioMode.Beeps && beepSounds.Count == 0)) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
targetAudioSource.volume = 0f; |
||||
targetVolume = 1f; |
||||
|
||||
if (audioClip != null) |
||||
{ |
||||
// Voice over clip provided |
||||
targetAudioSource.clip = audioClip; |
||||
targetAudioSource.loop = loop; |
||||
targetAudioSource.Play(); |
||||
} |
||||
else if (audioMode == AudioMode.SoundEffect && |
||||
soundEffect != null) |
||||
{ |
||||
// Use sound effects defined in WriterAudio |
||||
targetAudioSource.clip = soundEffect; |
||||
targetAudioSource.loop = loop; |
||||
targetAudioSource.Play(); |
||||
} |
||||
else if (audioMode == AudioMode.Beeps) |
||||
{ |
||||
// Use beeps defined in WriterAudio |
||||
targetAudioSource.clip = null; |
||||
targetAudioSource.loop = false; |
||||
playBeeps = true; |
||||
} |
||||
} |
||||
|
||||
public virtual void Pause() |
||||
{ |
||||
if (targetAudioSource == null) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
// There's an audible click if you call audioSource.Pause() so instead just drop the volume to 0. |
||||
targetVolume = 0f; |
||||
} |
||||
|
||||
public virtual void Stop() |
||||
{ |
||||
if (targetAudioSource == null) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
// There's an audible click if you call audioSource.Stop() so instead we just switch off |
||||
// looping and let the audio stop automatically at the end of the clip |
||||
targetVolume = 0f; |
||||
targetAudioSource.loop = false; |
||||
playBeeps = false; |
||||
} |
||||
|
||||
public virtual void Resume() |
||||
{ |
||||
if (targetAudioSource == null) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
targetVolume = 1f; |
||||
} |
||||
|
||||
protected virtual void Update() |
||||
{ |
||||
targetAudioSource.volume = Mathf.MoveTowards(targetAudioSource.volume, targetVolume, Time.deltaTime * 5f); |
||||
} |
||||
|
||||
// |
||||
// IWriterListener implementation |
||||
// |
||||
|
||||
public virtual void OnInput() |
||||
{ |
||||
if (inputSound != null) |
||||
{ |
||||
// Assumes we're playing a 2D sound |
||||
AudioSource.PlayClipAtPoint(inputSound, Vector3.zero); |
||||
} |
||||
} |
||||
|
||||
public virtual void OnStart(AudioClip audioClip) |
||||
{ |
||||
Play(audioClip); |
||||
} |
||||
|
||||
public virtual void OnPause() |
||||
{ |
||||
Pause(); |
||||
} |
||||
|
||||
public virtual void OnResume() |
||||
{ |
||||
Resume(); |
||||
} |
||||
|
||||
public virtual void OnEnd() |
||||
{ |
||||
Stop(); |
||||
} |
||||
|
||||
public virtual void OnGlyph() |
||||
{ |
||||
if (playBeeps && beepSounds.Count > 0) |
||||
{ |
||||
if (!targetAudioSource.isPlaying) |
||||
{ |
||||
targetAudioSource.clip = beepSounds[Random.Range(0, beepSounds.Count - 1)]; |
||||
targetAudioSource.loop = false; |
||||
targetAudioSource.Play(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,12 @@
|
||||
using UnityEngine; |
||||
using System.Collections; |
||||
|
||||
public class SayTest : MonoBehaviour |
||||
{ |
||||
public int passCount; |
||||
|
||||
public void TestPassed() |
||||
{ |
||||
passCount++; |
||||
} |
||||
} |
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: abf8bf8daccdf46b4afc52dcfd59a479 |
||||
timeCreated: 1440068772 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
Binary file not shown.
@ -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: |
Binary file not shown.
@ -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: |
Binary file not shown.
@ -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: |
Binary file not shown.
@ -0,0 +1,22 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 0cdfebb6349aa4b72a1d34c47935faf8 |
||||
timeCreated: 1440492917 |
||||
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: |
Loading…
Reference in new issue