playMaker

Author Topic: String Typewriter - Mid sentence pause, change speed, change color  (Read 2641 times)

createasaurus

  • Full Member
  • ***
  • Posts: 134
    • View Profile
The wonderful, magical String Typewriter action is unlocking my dreams to make Nintendo-ish style classic text.  Thank you!!!  Thank you!!!

I can totally use it in my game AS IS, and it will be GREAT.  However, there are some additional features that would take things to the next level. 

1) ability to make a short pause mid sentence.
2) the ability to adjust speed mid sentence.
3) the ability to adjust color mid sentence.

One idea to do this is to allow "code" in the text field.
Pause could be [p1], to pause 1 second.
Speed could be [s.5], to change the speed to .5
Color could be [ c50,177,65] to change the color to greenish.

An example of how this might look in action is:
Who are you???[p1] You couldn't be[s.5][c50,177,65] The LEPRECHAUN!!!

Thank you for this great action,
Chris (createasaurus)

PS I most likely will be using Unity 4.3 for my project, so I am hopeful this action would continue to be backward compatible.  Thank you again.
« Last Edit: December 31, 2014, 07:00:57 AM by createasaurus »

Lane

  • Administrator
  • Hero Member
  • *****
  • Posts: 2484
  • Yup.
    • View Profile
    • Cleverous
Re: String Typewriter - Mid sentence pause, change speed, change color
« Reply #1 on: December 31, 2014, 07:17:08 AM »
I'll see what I can do with the pausing and speed triggers mid sentence. For the colors you should be able to use HTML tags on text that supports Rich Text formatting, but I haven't tested it.. See Rich Text docs... Probably would be pretty buggy now that I think about it....

http://docs.unity3d.com/Manual/StyledText.html (UI)
http://docs.unity3d.com/Manual/class-GuiText.html (Legacy)
« Last Edit: December 31, 2014, 07:21:16 AM by Lane »

LogLady

  • Full Member
  • ***
  • Posts: 125
    • View Profile
Re: String Typewriter - Mid sentence pause, change speed, change color
« Reply #2 on: January 02, 2015, 11:32:48 AM »
Using the String typewriter or looping the string to display each character at determined time intervals gives me this problem while the characters are being typed:

Hi! <color=green>This is Sparta.</color> You are <color=red>NOT welcome!</color>

When the typing is done the markups disappears and everything is correct but I'd like to get this while the string is being typed:

Hi! This is Sparta. You are NOT welcome!

I tried to the get the already typed rich text to a string and the retype to another string and then display it with no success. To tell the truth I don't even know if it is possible to put in a string an already formated text.

Thanks!
« Last Edit: January 02, 2015, 11:35:21 AM by LogLady »

Lane

  • Administrator
  • Hero Member
  • *****
  • Posts: 2484
  • Yup.
    • View Profile
    • Cleverous
Re: String Typewriter - Mid sentence pause, change speed, change color
« Reply #3 on: January 02, 2015, 12:34:30 PM »
Yeah I took a whack at doing the Rich Text formatting but unfortunately I think it's out of scope for the moment. I may get time to look back at it and implement Rich Text support some time soon but I would not recommend holding your development for it.

It was fairly easy to recognize the opening of a format block for the supported types (<size>, <color>, <b>and <i>) but i ran into problems trying to cache what type of formats have been opened and how many times. If the blocks are not closed and closed out the correct number of times then Rich Text won't recognize it and hence it becomes visible in the printed string. I tried a couple of quick tricks to get around it which actually work under simple circumstances but will fail if you add any kind of advanced formatting combinations to a string and would not be suitable for publishing.

I ended up with creating a suffix that goes on the end of the string and is modified when a closing block is detected so that the suffix on the end of the string will always complete the opener blocks while being typed. The opener (and closer) blocks are detected and skipped through the index so you don't see them being typed, of course.

If someone wants to continue the code the latest is below but be aware it is not working in this state and has a lot of loose ends. It's possibly not too far from working.

Code: [Select]
// (c) Copyright HutongGames, LLC 2010-2015. All rights reserved.
/*--- __ECO__ __ACTION__ ---*/

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

namespace HutongGames.PlayMaker.Actions
{
[ActionCategory(ActionCategory.String)]
[Tooltip("Automatically types into a string.")]
public class StringTypewriter : FsmStateAction
{
[RequiredField]
[UIHint(UIHint.TextArea)]
[Tooltip("The string with the entire message to type out.")]
public FsmString baseString;

[RequiredField]
[UIHint(UIHint.Variable)]
[Tooltip("The target result string (can be the same as the base string).")]
public FsmString resultString;

[Tooltip("The time between letters appearing.")]
public FsmFloat pause;

[Tooltip("When punctuation is encountered then pause is multiplied by this.\n(period, exclamation, question, comma, semicolon, colon and ellipsis).\nIt also handles repeating characters and pauses only one time at their end.")]
public FsmFloat punctuationMultiplier;

[Tooltip("True is realtime: continues typing while game is paused. False will subject time variable to the game's timeScale.")]
public FsmBool realtime;

[Tooltip("Support Rich Text formatting, eg <color>, <b>, <i>, <size>.")]
public bool richText;

[Tooltip("Send this event when finished typing.")]
public FsmEvent finishEvent;

[UIHint(UIHint.Description)]
public string d1 = "     Optional Sounds Section:";

[Tooltip("Check this to play sounds while typing.")]
public bool useSounds;

[Tooltip("Check this to not play a sound when it is a spacebar character.")]
public bool noSoundOnSpaces;

[ObjectType(typeof(AudioClip))]
[Tooltip("The sound to play for each letter typed.")]
public FsmObject typingSound;

[Tooltip("The GameObject with an AudioSource component.")]
public FsmOwnerDefault audioSourceObj;

// Time data
float p = 0.0f;
float startTime;
float timer = 0.0f;

// Character data
char[] punctuation = {'.', '!', '?', ',', ';', ':'};
string message = "";
int index = 0;
char lastChar;
char nextChar;

// Rich Text formatting
private string block;
private string suffix;

// Audio
private AudioSource audioSource;
private AudioClip sound;

public override void Reset()
{
// --- Basic ---
baseString = null;
resultString = null;
pause = 0.05f;
punctuationMultiplier = 10.0f;
realtime = false;
richText = true;
finishEvent = null;

// --- Sounds ---
useSounds = false;
noSoundOnSpaces = true;
typingSound = null;
audioSourceObj = null;
}

public override void OnEnter()
{
// sort out the sound stuff
if (useSounds){
var go = Fsm.GetOwnerDefaultTarget(audioSourceObj);
if (go != null){
audioSource = go.GetComponent<AudioSource>();
if (audioSource == null){
Debug.LogError ("String Typewriter Action reports: The <color=#ffa500ff>AudioSource component</color> was not found! Does the target object have an Audio Source component?");
useSounds = false;
}

sound = typingSound.Value as AudioClip;
if (sound == null){
Debug.LogError ("String Typewriter Action reports: The <color=#ffa500ff>AudioClip</color> was not found!");
useSounds = false;
}
}

else {
Debug.LogError ("String Typewriter Action reports: The <color=#ffa500ff>target Game Object</color> for the audio source was not found!");
useSounds = false;
}
}

index = 0;
message = baseString.Value; // clone the base string.
resultString.Value = ""; // clear the target string.
startTime = Time.realtimeSinceStartup; // get the actual time since the game started.
}

// Here in OnUpdate we handle...
// 1) Pausing between letters
// 2) Checking for punctuation marks
// 3) Processing Rich Text
public override void OnUpdate()
{
// Check if the string is complete
if (message == resultString.Value)
{
DoFinish();
}

// If the string is not complete, continue work
else
{
p = pause.Value; // clone the pause variable in OnUpdate in case it is changed by the user at runtime.

nextChar = message[index];

// fetch/compare the characters to see if they exist in the punctuation array or not
int _iLast = Array.IndexOf (punctuation, lastChar); // get last index
int _iNext = Array.IndexOf (punctuation, nextChar); // get next index

// compare the result
bool _lastIsMark = _iLast != -1; // if index is not -1, there is a punctuation mark.
bool _nextIsMark = _iNext != -1; // if index is not -1, there is a punctuation mark.

if (_lastIsMark)
{
// if the next char is a punctuation mark then we should not pause.
if (!_nextIsMark)
{
pause = (p * punctuationMultiplier.Value);
}
}

// if we run into a format opener, we should process the block!
if (richText && message[index] == '<')
{

DoRichText();
}

if (realtime.Value)
{
// check the current time minus the previous Typing event time.
// if that's more than the pause gap, then its time for another character.
if (Time.realtimeSinceStartup - startTime >= pause.Value)
{
DoTyping();
}
}

if (!realtime.Value)
{
// add delta time until its more than the pause gap.
timer += Time.deltaTime;
if (timer >= pause.Value)
{
DoTyping();
}
}

pause.Value = p; // done with pausing, so revert the pause in case it was changed for punctuation.
}
}

// Here in DoTyping we handle...
// 1) Playing sound
// 2) Adding text to the message
// 3) Iterating the character index value
// 4) Resetting the timer and getting time
public void DoTyping()
{
// play the sound if enabled
if (useSounds)
{
if (noSoundOnSpaces && message[index] != ' ')
{
audioSource.PlayOneShot (sound);
}

else
{
audioSource.PlayOneShot (sound);
}
}

// build the display string
if (richText)
{
resultString.Value = message.Substring(0, index) + (message[index] + suffix); // add one character to the string, and the suffix.

//Debug.Log ("INDEX: "+index+", current string result: "+resultString.Value);
Debug.Log ("RESULT: "+resultString.Value+", INDEX: "+index+", SUFFIX: "+suffix);
}

if (!richText)
{
resultString.Value += message[index]; // add one character to the string
}

lastChar = message[index]; // store the index that we just typed
index++; // iterate the index

timer = 0.0f; // reset timer
startTime = Time.realtimeSinceStartup; // update realtime
}

public void DoRichText()
{
block = "";
// Construct the <block>
while (index < message.Length)
{
block += message[index];
index++;

if (message[index] == '>')
{
block += message[index];
index = index+1;
break;
}
}

block = block.ToLower();

if (block.Contains("/"))
{
Debug.Log ("_________Removing : "+block+" from Suffix: "+suffix);
int remove = suffix.Length - block.Length;
if (remove<=0)
{
suffix.Equals("");
}
else{
suffix.Remove (remove);
}
Debug.Log ("_________Removed : "+block+" from Suffix: "+suffix);
}

if (!block.Contains("/"))
{
if (block.Contains ("<c")){
block = "</color>";}
if (block.Contains ("<s")){
block = "</size>";}
if (block.Contains ("<i")){
block = "</i>";}
if (block.Contains ("<b")){
block = "</b>";}

suffix += block;
}
}

public void DoFinish()
{
Finish();
if (finishEvent != null)
{
Fsm.Event(finishEvent);
}
}

public override void OnExit()
{
// if the state exits before finishing the string
// then it needs to be auto-completed.
resultString.Value = message;
}
}
}
« Last Edit: January 02, 2015, 12:37:36 PM by Lane »

LogLady

  • Full Member
  • ***
  • Posts: 125
    • View Profile
Re: String Typewriter - Mid sentence pause, change speed, change color
« Reply #4 on: January 02, 2015, 03:58:03 PM »
Is there any way to typewrite the string without redrawing it?
Or "burn" the writen text to the background?


LogLady

  • Full Member
  • ***
  • Posts: 125
    • View Profile
Re: String Typewriter - Mid sentence pause, change speed, change color
« Reply #5 on: January 05, 2015, 10:04:08 AM »
I remember that when I used a 2D engine someone made a "text blitter". I took a look at what it is and to me it appears similar to this: http://docs.unity3d.com/410/Documentation/ScriptReference/Graphics.Blit.html

I searched the forum and the Ecosystem but couldn't find any action for this.
Is there another way to do this?

Lane

  • Administrator
  • Hero Member
  • *****
  • Posts: 2484
  • Yup.
    • View Profile
    • Cleverous
Re: String Typewriter - Mid sentence pause, change speed, change color
« Reply #6 on: January 05, 2015, 10:16:24 AM »
Do you mean you want to bake the text into a texture or renderTexture?

We should probably move this discussion to the actual String Typewriter thread. Would you guys mind replying to that thread with an outline of feature requests there? It'll be easier for me to track when I get around to doing the next iteration for the action.

Thanks

LogLady

  • Full Member
  • ***
  • Posts: 125
    • View Profile
Re: String Typewriter - Mid sentence pause, change speed, change color
« Reply #7 on: January 05, 2015, 11:22:04 AM »
That's it!

But I don't know if it is better than the actual method or is just overkill.

My hope is to make easier to draw text, change material and color but leaving what was already displayed.

Gotta jump to the thread you suggested, Lane!