@ -3,6 +3,7 @@ using UnityEngine.UI;
using System.Collections ;
using System.Collections ;
using System.Collections.Generic ;
using System.Collections.Generic ;
using System ;
using System ;
using System.Reflection ;
namespace Fungus
namespace Fungus
{
{
@ -52,15 +53,14 @@ namespace Fungus
[Tooltip("Force the target text object to use Rich Text mode so text color and alpha appears correctly")]
[Tooltip("Force the target text object to use Rich Text mode so text color and alpha appears correctly")]
public bool forceRichText = true ;
public bool forceRichText = true ;
/ * *
[Tooltip("Click while text is writing to finish writing immediately")]
* This property is true when the writer is waiting for user input to continue
public bool instantComplete = true ;
* /
// This property is true when the writer is waiting for user input to continue
[System.NonSerialized]
[System.NonSerialized]
public bool isWaitingForInput ;
public bool isWaitingForInput ;
/ * *
// This property is true when the writer is writing text or waiting (i.e. still processing tokens)
* This property is true when the writer is writing text or waiting ( i . e . still processing tokens )
* /
[System.NonSerialized]
[System.NonSerialized]
public bool isWriting ;
public bool isWriting ;
@ -69,6 +69,9 @@ namespace Fungus
protected Text textUI ;
protected Text textUI ;
protected InputField inputField ;
protected InputField inputField ;
protected TextMesh textMesh ;
protected TextMesh textMesh ;
protected Component textComponent ;
protected PropertyInfo textProperty ;
protected bool boldActive = false ;
protected bool boldActive = false ;
protected bool italicActive = false ;
protected bool italicActive = false ;
protected bool colorActive = false ;
protected bool colorActive = false ;
@ -94,6 +97,11 @@ namespace Fungus
{
{
return textMesh . text ;
return textMesh . text ;
}
}
else if ( textProperty ! = null )
{
return textProperty . GetValue ( textComponent , null ) as string ;
}
return "" ;
return "" ;
}
}
@ -111,6 +119,10 @@ namespace Fungus
{
{
textMesh . text = value ;
textMesh . text = value ;
}
}
else if ( textProperty ! = null )
{
textProperty . SetValue ( textComponent , value , null ) ;
}
}
}
}
}
@ -126,6 +138,20 @@ namespace Fungus
inputField = go . GetComponent < InputField > ( ) ;
inputField = go . GetComponent < InputField > ( ) ;
textMesh = go . GetComponent < TextMesh > ( ) ;
textMesh = go . GetComponent < TextMesh > ( ) ;
// Try to find any component with a text property
if ( textUI = = null & & inputField = = null & & textMesh = = null )
{
foreach ( Component c in GetComponents < Component > ( ) )
{
textProperty = c . GetType ( ) . GetProperty ( "text" ) ;
if ( textProperty ! = null )
{
textComponent = c ;
break ;
}
}
}
// Cache the list of child writer listeners
// Cache the list of child writer listeners
foreach ( Component component in GetComponentsInChildren < Component > ( ) )
foreach ( Component component in GetComponentsInChildren < Component > ( ) )
{
{
@ -157,7 +183,7 @@ namespace Fungus
public virtual bool HasTextObject ( )
public virtual bool HasTextObject ( )
{
{
return ( textUI ! = null | | inputField ! = null | | textMesh ! = null ) ;
return ( textUI ! = null | | inputField ! = null | | textMesh ! = null | | textComponent ! = null ) ;
}
}
public virtual bool SupportsRichText ( )
public virtual bool SupportsRichText ( )
@ -301,8 +327,35 @@ namespace Fungus
StartCoroutine ( ProcessTokens ( tokens , onComplete ) ) ;
StartCoroutine ( ProcessTokens ( tokens , onComplete ) ) ;
}
}
protected virtual IEnumerator ProcessTokens ( List < TextTagParser . Token > tokens , Action onComplete )
virtual protected bool CheckParamCount ( List < string > paramList , int count )
{
if ( paramList = = null )
{
Debug . LogError ( "paramList is null" ) ;
return false ;
}
if ( paramList . Count ! = count )
{
Debug . LogError ( "There must be exactly " + paramList . Count + " parameters." ) ;
return false ;
}
return true ;
}
protected virtual bool TryGetSingleParam ( List < string > paramList , int index , float defaultValue , out float value )
{
value = defaultValue ;
if ( paramList . Count > index )
{
Single . TryParse ( paramList [ index ] , out value ) ;
return true ;
}
return false ;
}
protected virtual IEnumerator ProcessTokens ( List < TextTagParser . Token > tokens , Action onComplete )
{
{
// Reset control members
// Reset control members
boldActive = false ;
boldActive = false ;
@ -321,8 +374,8 @@ namespace Fungus
switch ( token . type )
switch ( token . type )
{
{
case TextTagParser . TokenType . Words :
case TextTagParser . TokenType . Words :
yield return StartCoroutine ( DoWords ( token . param ) ) ;
yield return StartCoroutine ( DoWords ( token . paramList ) ) ;
break ;
break ;
case TextTagParser . TokenType . BoldStart :
case TextTagParser . TokenType . BoldStart :
boldActive = true ;
boldActive = true ;
@ -341,17 +394,20 @@ namespace Fungus
break ;
break ;
case TextTagParser . TokenType . ColorStart :
case TextTagParser . TokenType . ColorStart :
colorActive = true ;
if ( CheckParamCount ( token . paramList , 1 ) )
colorText = token . param ;
{
break ;
colorActive = true ;
colorText = token . paramList [ 0 ] ;
}
break ;
case TextTagParser . TokenType . ColorEnd :
case TextTagParser . TokenType . ColorEnd :
colorActive = false ;
colorActive = false ;
break ;
break ;
case TextTagParser . TokenType . Wait :
case TextTagParser . TokenType . Wait :
yield return StartCoroutine ( DoWait ( token . param ) ) ;
yield return StartCoroutine ( DoWait ( token . paramList ) ) ;
break ;
break ;
case TextTagParser . TokenType . WaitForInputNoClear :
case TextTagParser . TokenType . WaitForInputNoClear :
yield return StartCoroutine ( DoWaitForInput ( false ) ) ;
yield return StartCoroutine ( DoWaitForInput ( false ) ) ;
@ -362,11 +418,8 @@ namespace Fungus
break ;
break ;
case TextTagParser . TokenType . WaitOnPunctuationStart :
case TextTagParser . TokenType . WaitOnPunctuationStart :
if ( ! Single . TryParse ( token . param , out currentPunctuationPause ) )
TryGetSingleParam ( token . paramList , 0 , punctuationPause , out currentPunctuationPause ) ;
{
break ;
currentPunctuationPause = punctuationPause ;
}
break ;
case TextTagParser . TokenType . WaitOnPunctuationEnd :
case TextTagParser . TokenType . WaitOnPunctuationEnd :
currentPunctuationPause = punctuationPause ;
currentPunctuationPause = punctuationPause ;
@ -377,10 +430,7 @@ namespace Fungus
break ;
break ;
case TextTagParser . TokenType . SpeedStart :
case TextTagParser . TokenType . SpeedStart :
if ( ! Single . TryParse ( token . param , out currentWritingSpeed ) )
TryGetSingleParam ( token . paramList , 0 , writingSpeed , out currentWritingSpeed ) ;
{
currentWritingSpeed = writingSpeed ;
}
break ;
break ;
case TextTagParser . TokenType . SpeedEnd :
case TextTagParser . TokenType . SpeedEnd :
@ -392,58 +442,69 @@ namespace Fungus
break ;
break ;
case TextTagParser . TokenType . Message :
case TextTagParser . TokenType . Message :
Flowchart . BroadcastFungusMessage ( token . param ) ;
if ( CheckParamCount ( token . paramList , 1 ) )
break ;
case TextTagParser . TokenType . VerticalPunch :
float vintensity ;
if ( ! Single . TryParse ( token . param , out vintensity ) )
{
{
vintensity = 1 0f ;
Flowchart . BroadcastFungusMessage ( token . paramList [ 0 ] ) ;
}
}
Punch ( new Vector3 ( 0 , vintensity , 0 ) , 0.5f ) ;
break ;
break ;
case TextTagParser . TokenType . HorizontalPunch :
case TextTagParser . TokenType . VerticalPunch :
float hintensity ;
{
if ( ! Single . TryParse ( token . param , out hintensity ) )
float vintensity ;
{
float time ;
hintensity = 1 0f ;
TryGetSingleParam ( token . paramList , 0 , 1 0.0f , out vintensity ) ;
}
TryGetSingleParam ( token . paramList , 1 , 0.5f , out time ) ;
Punch ( new Vector3 ( hintensity , 0 , 0 ) , 0.5f ) ;
Punch ( new Vector3 ( 0 , vintensity , 0 ) , time ) ;
break ;
}
break ;
case TextTagParser . TokenType . Punch :
case TextTagParser . TokenType . HorizontalPunch :
float intensity ;
{
if ( ! Single . TryParse ( token . param , out intensity ) )
float hintensity ;
{
float time ;
intensity = 1 0f ;
TryGetSingleParam ( token . paramList , 0 , 1 0.0f , out hintensity ) ;
}
TryGetSingleParam ( token . paramList , 1 , 0.5f , out time ) ;
Punch ( new Vector3 ( intensity , intensity , 0 ) , 0.5f ) ;
Punch ( new Vector3 ( hintensity , 0 , 0 ) , time ) ;
break ;
}
break ;
case TextTagParser . TokenType . Punch :
{
float intensity ;
float time ;
TryGetSingleParam ( token . paramList , 0 , 1 0.0f , out intensity ) ;
TryGetSingleParam ( token . paramList , 1 , 0.5f , out time ) ;
Punch ( new Vector3 ( intensity , intensity , 0 ) , time ) ;
}
break ;
case TextTagParser . TokenType . Flash :
case TextTagParser . TokenType . Flash :
float flashDuration ;
float flashDuration ;
if ( ! Single . TryParse ( token . param , out flashDuration ) )
TryGetSingleParam ( token . paramList , 0 , 0.2f , out flashDuration ) ;
{
flashDuration = 0.2f ;
}
Flash ( flashDuration ) ;
Flash ( flashDuration ) ;
break ;
break ;
case TextTagParser . TokenType . Audio :
case TextTagParser . TokenType . Audio :
{
{
AudioSource audioSource = FindAudio ( token . param ) ;
AudioSource audioSource = null ;
if ( audioSource ! = null )
if ( CheckParamCount ( token . paramList , 1 ) )
{
{
audioSource . PlayOneShot ( audioSource . clip ) ;
audioSource = FindAudio ( token . paramList [ 0 ] ) ;
}
}
}
if ( audioSource ! = null )
break ;
{
audioSource . PlayOneShot ( audioSource . clip ) ;
}
}
break ;
case TextTagParser . TokenType . AudioLoop :
case TextTagParser . TokenType . AudioLoop :
{
{
AudioSource audioSource = FindAudio ( token . param ) ;
AudioSource audioSource = null ;
if ( CheckParamCount ( token . paramList , 1 ) )
{
audioSource = FindAudio ( token . paramList [ 0 ] ) ;
}
if ( audioSource ! = null )
if ( audioSource ! = null )
{
{
audioSource . Play ( ) ;
audioSource . Play ( ) ;
@ -454,7 +515,11 @@ namespace Fungus
case TextTagParser . TokenType . AudioPause :
case TextTagParser . TokenType . AudioPause :
{
{
AudioSource audioSource = FindAudio ( token . param ) ;
AudioSource audioSource = null ;
if ( CheckParamCount ( token . paramList , 1 ) )
{
audioSource = FindAudio ( token . paramList [ 0 ] ) ;
}
if ( audioSource ! = null )
if ( audioSource ! = null )
{
{
audioSource . Pause ( ) ;
audioSource . Pause ( ) ;
@ -464,7 +529,11 @@ namespace Fungus
case TextTagParser . TokenType . AudioStop :
case TextTagParser . TokenType . AudioStop :
{
{
AudioSource audioSource = FindAudio ( token . param ) ;
AudioSource audioSource = null ;
if ( CheckParamCount ( token . paramList , 1 ) )
{
audioSource = FindAudio ( token . paramList [ 0 ] ) ;
}
if ( audioSource ! = null )
if ( audioSource ! = null )
{
{
audioSource . Stop ( ) ;
audioSource . Stop ( ) ;
@ -491,61 +560,67 @@ namespace Fungus
onComplete ( ) ;
onComplete ( ) ;
}
}
}
}
protected virtual IEnumerator DoWords ( string param )
{
string startText = text ;
string openText = OpenMarkup ( ) ;
string closeText = CloseMarkup ( ) ;
float timeAccumulator = Time . deltaTime ;
for ( int i = 0 ; i < param . Length ; + + i )
{
// Exit immediately if the exit flag has been set
if ( exitFlag )
{
break ;
}
string left = "" ;
string right = "" ;
PartitionString ( writeWholeWords , param , i , out left , out right ) ;
text = ConcatenateString ( startText , openText , closeText , left , right ) ;
NotifyGlyph ( ) ;
protected virtual IEnumerator DoWords ( List < string > paramList )
{
// No delay if user has clicked
if ( ! CheckParamCount ( paramList , 1 ) )
if ( inputFlag )
{
{
yield break ;
continue ;
}
}
string param = paramList [ 0 ] ;
// Punctuation pause
string startText = text ;
if ( left . Length > 0 & &
string openText = OpenMarkup ( ) ;
right . Length > 0 & &
string closeText = CloseMarkup ( ) ;
IsPunctuation ( left . Substring ( left . Length - 1 ) [ 0 ] ) )
{
float timeAccumulator = Time . deltaTime ;
yield return StartCoroutine ( DoWait ( currentPunctuationPause ) ) ;
}
for ( int i = 0 ; i < param . Length ; + + i )
{
// Delay between characters
// Exit immediately if the exit flag has been set
if ( currentWritingSpeed > 0f )
if ( exitFlag )
{
{
if ( timeAccumulator > 0f )
break ;
{
}
timeAccumulator - = 1f / currentWritingSpeed ;
}
string left = "" ;
else
string right = "" ;
{
yield return new WaitForSeconds ( 1f / currentWritingSpeed ) ;
PartitionString ( writeWholeWords , param , i , out left , out right ) ;
}
text = ConcatenateString ( startText , openText , closeText , left , right ) ;
}
}
NotifyGlyph ( ) ;
}
// No delay if user has clicked and Instant Complete is enabled
protected void PartitionString ( bool wholeWords , string inputString , int i , out string left , out string right )
if ( instantComplete & & inputFlag )
{
continue ;
}
// Punctuation pause
if ( left . Length > 0 & &
right . Length > 0 & &
IsPunctuation ( left . Substring ( left . Length - 1 ) [ 0 ] ) )
{
yield return StartCoroutine ( DoWait ( currentPunctuationPause ) ) ;
}
// Delay between characters
if ( currentWritingSpeed > 0f )
{
if ( timeAccumulator > 0f )
{
timeAccumulator - = 1f / currentWritingSpeed ;
}
else
{
yield return new WaitForSeconds ( 1f / currentWritingSpeed ) ;
}
}
}
}
protected void PartitionString ( bool wholeWords , string inputString , int i , out string left , out string right )
{
{
left = "" ;
left = "" ;
right = "" ;
right = "" ;
@ -593,24 +668,21 @@ namespace Fungus
return "" ;
return "" ;
}
}
protected virtual IEnumerator DoWait ( string param )
protected virtual IEnumerator DoWait ( List < string > paramList )
{
{
float duration = 1f ;
var param = "" ;
if ( ! Single . TryParse ( param , out duration ) )
if ( paramList . Count = = 1 )
{
{
duration = 1f ;
param = paramList [ 0 ] ;
}
}
NotifyPause ( ) ;
float duration = 1f ;
if ( ! Single . TryParse ( param , out duration ) )
float timeRemaining = duration ;
{
while ( timeRemaining > 0f & & ! inputFlag )
duration = 1f ;
{
}
timeRemaining - = Time . deltaTime ;
yield return null ;
yield return StartCoroutine ( DoWait ( duration ) ) ;
}
NotifyResume ( ) ;
}
}
protected virtual IEnumerator DoWait ( float duration )
protected virtual IEnumerator DoWait ( float duration )
@ -618,8 +690,13 @@ namespace Fungus
NotifyPause ( ) ;
NotifyPause ( ) ;
float timeRemaining = duration ;
float timeRemaining = duration ;
while ( timeRemaining > 0f & & ! inputFlag & & ! exitFlag )
while ( timeRemaining > 0f & & ! exitFlag )
{
{
if ( instantComplete & & inputFlag )
{
break ;
}
timeRemaining - = Time . deltaTime ;
timeRemaining - = Time . deltaTime ;
yield return null ;
yield return null ;
}
}
@ -663,7 +740,11 @@ namespace Fungus
protected virtual void Punch ( Vector3 axis , float time )
protected virtual void Punch ( Vector3 axis , float time )
{
{
iTween . ShakePosition ( this . gameObject , axis , time ) ;
if ( Camera . main = = null )
{
return ;
}
iTween . ShakePosition ( Camera . main . gameObject , axis , time ) ;
}
}
protected virtual void Flash ( float duration )
protected virtual void Flash ( float duration )