Browse Source
Refactored the dialog class to separate parsing story text and displaying text into separate classes.master
chrisgregan
10 years ago
5 changed files with 495 additions and 406 deletions
@ -0,0 +1,165 @@
|
||||
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 |
||||
WaitOnPunctuation, // wp, wp=0.5 |
||||
Clear, // c |
||||
Speed, // s, s=60 |
||||
Exit // x |
||||
} |
||||
|
||||
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 - 1) |
||||
{ |
||||
string postText = storyText.Substring(position, storyText.Length - position); |
||||
AddWordsToken(tokens, postText); |
||||
} |
||||
} |
||||
|
||||
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.WaitOnPunctuation; |
||||
paramText = tag.Substring(3, tag.Length - 3); |
||||
} |
||||
else if (tag == "wp") |
||||
{ |
||||
type = TokenType.WaitOnPunctuation; |
||||
} |
||||
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.Speed; |
||||
paramText = tag.Substring(2, tag.Length - 2); |
||||
} |
||||
else if (tag == "s") |
||||
{ |
||||
type = TokenType.Speed; |
||||
} |
||||
else if (tag == "x") |
||||
{ |
||||
type = TokenType.Exit; |
||||
} |
||||
|
||||
Token token = new Token(); |
||||
token.type = type; |
||||
token.param = paramText.Trim(); |
||||
|
||||
tokenList.Add(token); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 674037e0ad6e34e149f9bbab6940e155 |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
@ -0,0 +1,197 @@
|
||||
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>(); |
||||
|
||||
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 AudioSource typingAudio { get; set; } |
||||
|
||||
public virtual void Clear() |
||||
{ |
||||
glyphs.Clear(); |
||||
} |
||||
|
||||
public virtual void Append(string words) |
||||
{ |
||||
if (typingAudio != null) |
||||
{ |
||||
typingAudio.Stop(); |
||||
typingAudio.Play(); |
||||
} |
||||
|
||||
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) |
||||
{ |
||||
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 (i < words.Length - 2 && |
||||
IsPunctuation(c) && |
||||
!IsPunctuation(words[i + 1])) // No punctuation pause on last character, or if next character is also punctuation |
||||
{ |
||||
doPunctuationPause = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected virtual bool IsPunctuation(char character) |
||||
{ |
||||
return character == '.' || character == '?' || character == '!'; |
||||
} |
||||
|
||||
/** |
||||
* Returns true when all glyphs are visible. |
||||
*/ |
||||
public virtual bool UpdateGlyphs(bool instantComplete) |
||||
{ |
||||
float elapsedTime = Time.deltaTime; |
||||
|
||||
foreach (Glyph glyph in glyphs) |
||||
{ |
||||
if (instantComplete) |
||||
{ |
||||
glyph.hideTimer = 0f; |
||||
continue; |
||||
} |
||||
|
||||
if (glyph.hideTimer > 0f) |
||||
{ |
||||
if (typingAudio != null && |
||||
glyph.hasPunctuationPause) |
||||
{ |
||||
typingAudio.volume = 0f; |
||||
} |
||||
|
||||
bool finished = false; |
||||
if (elapsedTime > glyph.hideTimer) |
||||
{ |
||||
elapsedTime -= glyph.hideTimer; |
||||
glyph.hideTimer = 0f; |
||||
// Some elapsed time left over, so carry on to next glyph |
||||
} |
||||
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 (typingAudio != null && |
||||
glyph.hideTimer == 0f && |
||||
typingAudio.volume == 0f) |
||||
{ |
||||
typingAudio.volume = 1f; |
||||
} |
||||
|
||||
if (finished) |
||||
{ |
||||
return false; // Glyph is still hidden |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (typingAudio != null) |
||||
{ |
||||
typingAudio.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; |
||||
} |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue