diff --git a/Assets/Fungus/Narrative/Scripts/Character.cs b/Assets/Fungus/Narrative/Scripts/Character.cs index 4f865033..917c6ab3 100644 --- a/Assets/Fungus/Narrative/Scripts/Character.cs +++ b/Assets/Fungus/Narrative/Scripts/Character.cs @@ -20,6 +20,7 @@ namespace Fungus public AudioClip soundEffect; public Sprite profileSprite; public List portraits; + public Sprite[] cachedPortraits; public FacingDirection portraitsFace; public PortraitState state; @@ -38,6 +39,12 @@ namespace Fungus { activeCharacters.Add(this); } + + if (cachedPortraits == null) + { + cachedPortraits = new Sprite[portraits.Count]; + portraits.CopyTo(cachedPortraits); + } } protected virtual void OnDisable() @@ -59,30 +66,33 @@ namespace Fungus nameText = standardText; } + public bool NameStartsWith(string matchString) + { + return name.StartsWith(matchString, true, System.Globalization.CultureInfo.CurrentCulture) + || nameText.StartsWith(matchString, true, System.Globalization.CultureInfo.CurrentCulture); + } + /// /// Looks for a portrait by name on a character /// If none is found, give a warning and return a blank sprite /// /// /// Character portrait sprite - public virtual Sprite GetPortrait(string portrait_string) + public virtual Sprite GetPortrait(string portrait_string) { - if (portrait_string == null) + if (String.IsNullOrEmpty(portrait_string)) { - Debug.LogWarning("No portrait specifed for character " + name); - //Would be nice to have a sprite show up instead - return new Sprite(); + return null; } - foreach (Sprite portrait in portraits) + for (int i = 0; i < cachedPortraits.Length; i++) { - if ( String.Compare(portrait.name, portrait_string, true) == 0) + if ( String.Compare(cachedPortraits[i].name, portrait_string, true) == 0) { - return portrait; + return cachedPortraits[i]; } } - Debug.LogWarning("No portrait \"" + portrait_string + "\" found for character \"" + name + "\""); - return new Sprite(); + return null; } public virtual string GetDescription() diff --git a/Assets/Fungus/Narrative/Scripts/PortraitController.cs b/Assets/Fungus/Narrative/Scripts/PortraitController.cs index fbe03a47..217c0c3c 100644 --- a/Assets/Fungus/Narrative/Scripts/PortraitController.cs +++ b/Assets/Fungus/Narrative/Scripts/PortraitController.cs @@ -53,7 +53,7 @@ namespace Fungus waitUntilFinished = false; onComplete = null; - // Special values that can be overriden + // Special values that can be overridden fadeDuration = 0.5f; moveDuration = 1f; this.useDefaultSettings = useDefaultSettings; @@ -112,6 +112,7 @@ namespace Fungus void Awake() { stage = GetComponentInParent(); + stage.CachePositions(); } /// @@ -394,11 +395,13 @@ namespace Fungus options.moveDuration = moveDuration; options.waitUntilFinished = waitUntilFinished; - DoMoveTween(CleanPortraitOptions(options)); + DoMoveTween(options); } public void DoMoveTween(PortraitOptions options) { + CleanPortraitOptions(options); + // LeanTween doesn't handle 0 duration properly float duration = (options.moveDuration > 0f) ? options.moveDuration : float.Epsilon; @@ -422,7 +425,7 @@ namespace Fungus options.character = character; options.fromPosition = options.toPosition = stage.GetPosition(position); - Show(CleanPortraitOptions(options)); + Show(options); } /// @@ -441,7 +444,7 @@ namespace Fungus options.toPosition = stage.GetPosition(toPosition); options.move = true; - Show(CleanPortraitOptions(options)); + Show(options); } /// @@ -453,7 +456,7 @@ namespace Fungus /// Moonsharp Table public void Show(Table optionsTable) { - Show(CleanPortraitOptions(PortraitUtil.ConvertTableToPortraitOptions(optionsTable, stage))); + Show(PortraitUtil.ConvertTableToPortraitOptions(optionsTable, stage)); } /// @@ -462,6 +465,8 @@ namespace Fungus /// public void Show(PortraitOptions options) { + options = CleanPortraitOptions(options); + if (options.shiftIntoPlace) { options.fromPosition = Instantiate(options.toPosition) as RectTransform; @@ -507,9 +512,12 @@ namespace Fungus } // Fade in the new sprite image - options.character.state.portraitImage.sprite = options.portrait; - options.character.state.portraitImage.color = new Color(1f, 1f, 1f, 0f); - LeanTween.alpha(options.character.state.portraitImage.rectTransform, 1f, duration).setEase(stage.fadeEaseType); + if (options.character.state.portraitImage.sprite != options.portrait) + { + options.character.state.portraitImage.sprite = options.portrait; + options.character.state.portraitImage.color = new Color(1f, 1f, 1f, 0f); + LeanTween.alpha(options.character.state.portraitImage.rectTransform, 1f, duration).setEase(stage.fadeEaseType); + } DoMoveTween(options); @@ -548,7 +556,7 @@ namespace Fungus options.fromPosition = options.toPosition = character.state.position; } - Show(CleanPortraitOptions(options)); + Show(options); } /// @@ -560,7 +568,7 @@ namespace Fungus PortraitOptions options = new PortraitOptions(true); options.character = character; - Hide(CleanPortraitOptions(options)); + Hide(options); } /// @@ -575,7 +583,7 @@ namespace Fungus options.toPosition = stage.GetPosition(toPosition); options.move = true; - Hide(CleanPortraitOptions(options)); + Hide(options); } /// @@ -587,7 +595,7 @@ namespace Fungus /// Moonsharp Table public void Hide(Table optionsTable) { - Hide(CleanPortraitOptions(PortraitUtil.ConvertTableToPortraitOptions(optionsTable, stage))); + Hide(PortraitUtil.ConvertTableToPortraitOptions(optionsTable, stage)); } /// @@ -596,6 +604,8 @@ namespace Fungus /// public void Hide(PortraitOptions options) { + CleanPortraitOptions(options); + if (options.character.state.display == DisplayType.None) { return; diff --git a/Assets/Fungus/Narrative/Scripts/Stage.cs b/Assets/Fungus/Narrative/Scripts/Stage.cs index 50852da6..dabc0424 100644 --- a/Assets/Fungus/Narrative/Scripts/Stage.cs +++ b/Assets/Fungus/Narrative/Scripts/Stage.cs @@ -25,6 +25,7 @@ namespace Fungus public Vector2 shiftOffset; public Image defaultPosition; public List positions; + public RectTransform[] cachedPositions; public List charactersOnStage = new List(); [HideInInspector] @@ -38,6 +39,12 @@ namespace Fungus } } + public void CachePositions() + { + cachedPositions = new RectTransform[positions.Count]; + positions.CopyTo(cachedPositions); + } + protected virtual void OnDisable() { activeStages.Remove(this); @@ -61,21 +68,19 @@ namespace Fungus /// public RectTransform GetPosition(String position_string) { - if (position_string == null) + if (string.IsNullOrEmpty(position_string)) { - Debug.LogWarning("Missing stage position."); - return new RectTransform(); + return null; } - foreach (RectTransform position in positions) + for (int i = 0; i < cachedPositions.Length; i++) { - if ( String.Compare(position.name.Replace(" ", ""), position_string.Replace(" ", ""), true) == 0 ) + if ( String.Compare(cachedPositions[i].name, position_string, true) == 0 ) { - return position; + return cachedPositions[i]; } } - Debug.LogWarning("Unidentified stage position: " + position_string); - return new RectTransform(); + return null; } } } diff --git a/Assets/Fungus/Thirdparty/FungusLua/Scripts/ConversationManager.cs b/Assets/Fungus/Thirdparty/FungusLua/Scripts/ConversationManager.cs index 24fa58e1..7cdbe9aa 100644 --- a/Assets/Fungus/Thirdparty/FungusLua/Scripts/ConversationManager.cs +++ b/Assets/Fungus/Thirdparty/FungusLua/Scripts/ConversationManager.cs @@ -9,36 +9,24 @@ namespace Fungus public class ConversationManager { protected Stage stage; + protected Character[] characters; - protected CharacterItem[] characters; + protected Character currentCharacter; + protected Sprite currentPortrait; + protected RectTransform currentPosition; - protected struct CharacterItem - { - public string name; - public string nameText; - public Character character; - - public bool CharacterMatch(string matchString) - { - return name.StartsWith(matchString, true, System.Globalization.CultureInfo.CurrentCulture) - || nameText.StartsWith(matchString, true, System.Globalization.CultureInfo.CurrentCulture); - } - } + protected Character previousCharacter; + protected Sprite previousPortrait; + protected RectTransform previousPosition; protected bool exitSayWait; - public ConversationManager () { + public ConversationManager () + { stage = Stage.activeStages[0]; - - Character[] characterObjects = GameObject.FindObjectsOfType(); - characters = new CharacterItem[characterObjects.Length]; - - for (int i = 0; i < characterObjects.Length; i++) - { - characters[i].name = characterObjects[i].name; - characters[i].nameText = characterObjects[i].nameText; - characters[i].character = characterObjects[i]; - } + + // cache characters for faster lookup + characters = GameObject.FindObjectsOfType(); } /// @@ -61,40 +49,59 @@ namespace Fungus //find SimpleScript say strings with portrait options //You can test regex matches here: http://regexstorm.net/tester - var sayRegex = new Regex(@"((?\w*)( ?(?\w*)( ?(?\w*)))?:)?(?.*\r*\n)"); - var sayMatches = sayRegex.Matches(conv); + Regex sayRegex = new Regex(@"((?[\w ,]*):)?(?.*\r*\n)"); + MatchCollection sayMatches = sayRegex.Matches(conv); - foreach (Match match in sayMatches) + for (int i = 0; i < sayMatches.Count; i++) { - string characterKey = match.Groups["character"].Value; - string portrait = match.Groups["portrait"].Value; - string position = match.Groups["position"].Value; - string text = match.Groups["text"].Value; - Character character = null; - - sayDialog.gameObject.SetActive(true); + previousCharacter = currentCharacter; + previousPortrait = currentPortrait; + previousPosition = currentPosition; - if (!string.IsNullOrEmpty(characterKey)) + string sayParams = sayMatches[i].Groups["sayParams"].Value; + if (!string.IsNullOrEmpty(sayParams)) { - for (int i = 0; i < characters.Length; i++) + string[] separateParams; + if (sayParams.Contains(",")) { - if( characters[i].CharacterMatch(characterKey)) { - character = characters[i].character; - break; + separateParams = sayParams.Split(','); + for (int j = 0; j < separateParams.Length; j++) + { + separateParams[j] = separateParams[j].Trim(); } } + else + { + separateParams = sayParams.Split(' '); + } + + SetParams(separateParams); } - //We'll assume that if no character is specified, we'll leave it as the last one. - //It's probably a continuation of the last character's dialog - if (character != null) + else { - sayDialog.SetCharacter(character); + //no params! Use previous settings? + } + + string text = sayMatches[i].Groups["text"].Value; + + sayDialog.gameObject.SetActive(true); - string currentPosition = null; - if (character.state.position != null) currentPosition = character.state.position.name; - if (stage != null) stage.Show(character, portrait, currentPosition ?? position, position); + if (currentCharacter != null && currentCharacter != previousCharacter) + { + sayDialog.SetCharacter(currentCharacter); } + if (stage != null && currentCharacter != null && (currentPortrait != previousPortrait || currentPosition != previousPosition)) + { + PortraitOptions portraitOptions = new PortraitOptions(true); + portraitOptions.character = currentCharacter; + portraitOptions.fromPosition = currentCharacter.state.position ?? previousPosition; + portraitOptions.toPosition = currentPosition; + portraitOptions.portrait = currentPortrait; + + stage.Show(portraitOptions); + } + exitSayWait = false; sayDialog.Say(text, true, true, true, false, null, () => { exitSayWait = true; @@ -106,7 +113,39 @@ namespace Fungus } exitSayWait = false; } + + } + + /// + /// Using the string of say parameters before the ':', + /// set the current character, position and portrait if provided. + /// + /// The list of say parameters + private void SetParams(string[] sayParams) + { + Sprite portrait = null; + RectTransform position = null; + + //find the character first, since we need to get its portrait + for (int i = 0; i < sayParams.Length; i++) + { + for (int j = 0; j < characters.Length; j++) + { + if (characters[j].NameStartsWith(sayParams[i])) + { + currentCharacter = characters[j]; + break; + } + } + } + + for (int i = 0; i < sayParams.Length; i++) + { + if (portrait == null) portrait = currentCharacter.GetPortrait(sayParams[i]); + if (position == null) position = stage.GetPosition(sayParams[i]); + } + currentPosition = position; + currentPortrait = portrait; } } -} - \ No newline at end of file +} \ No newline at end of file diff --git a/Assets/FungusExamples/FungusLua/Narrative/PortaitControlExample.unity b/Assets/FungusExamples/FungusLua/Narrative/PortaitControlExample.unity index b5009224..8d93e3df 100644 --- a/Assets/FungusExamples/FungusLua/Narrative/PortaitControlExample.unity +++ b/Assets/FungusExamples/FungusLua/Narrative/PortaitControlExample.unity @@ -399,9 +399,10 @@ MonoBehaviour: indentLevel: 0 luaEnvironment: {fileID: 1332690758} luaFile: {fileID: 0} - luaScript: "conversation [[\r\nWhat is that smell??\nsherlock: Ugh.\r\nS bored:ew!\r\nwatson - annoyed left: That was me.\r\nW confident right: I'm not Sorry!\r\nW confident - offscreenright: GOOD DAY!\n]]" + luaScript: "conversation [[\r\nsherlock right: Character+position.\r\nThis is a + continuation of the last line.\nS bored left:All three options with name shortened.\nwatson + annoyed right: Adding a new character on the right.\r\nW, confident, offscreen + right: Move Watson offscreen using commas.\r\n]]" runAsCoroutine: 1 waitUntilFinished: 1 returnVariable: {fileID: 0} @@ -716,6 +717,9 @@ MonoBehaviour: portraits: - {fileID: 21300000, guid: a92b08a118b7d46f59dd091acb2e4102, type: 3} - {fileID: 21300000, guid: 03bc547cc0049594bae51f00903eedef, type: 3} + cachedPortraits: + - {fileID: 21300000, guid: a92b08a118b7d46f59dd091acb2e4102, type: 3} + - {fileID: 21300000, guid: 03bc547cc0049594bae51f00903eedef, type: 3} portraitsFace: 0 setSayDialog: {fileID: 0} description: @@ -766,6 +770,9 @@ MonoBehaviour: portraits: - {fileID: 21300000, guid: 8f5b5b110e73a414eb229eeead86200f, type: 3} - {fileID: 21300000, guid: c779e34c6eb8e45da98c70cf2802a54c, type: 3} + cachedPortraits: + - {fileID: 21300000, guid: 8f5b5b110e73a414eb229eeead86200f, type: 3} + - {fileID: 21300000, guid: c779e34c6eb8e45da98c70cf2802a54c, type: 3} portraitsFace: 0 setSayDialog: {fileID: 0} description: