Forum rules - please read before posting.

Delay before speech scrolls?

Hey! I have a short speech bubble animation (0.3s) for a Unity UI prefab speech menu (appear type: when speech plays; position type: above speaking character). "Scroll speech text?" is ticked. It works almost perfectly, but I would like the text to start scrolling only after the menu transition is completed. Is there a way to do this? I could add a [wait:0.4] token to the begin of every speech line, but there are two issues with this:

(1) It's a little cumbersome (not a deal breaker though);

(2) It appears that a [wait:x] token triggers the speech text scroll audio, even though no letters are displayed on the screen.

A solution for (1) would be ideal, but it'd also be great if the token could stop triggering the scroll audio as well.

Comments

  • Also, I've been playing with the new integration with the TextMeshPro typewriter effect, and I haven't been able to set up a Unity UI menu that obeys the "Always fit within the screen?" option. Is this working as intended? It might be just an error on my end.

  • edited September 2021

    I figured out the "always fit within the screen" problem, please ignore that part. :P Though I still have a smaller issue there: is there are a way to make the menu always fit within a specific area of the screen rather than the entire screen? My screen is framed by two black bars with a few icons each, and I need the speech bubble not to overlap with those bars.

  • Having an option to set a delay before scrolling would be convenient, agreed. I shall give this some thought.

    Either way, though, the audio should not play when a token is processed. What is your AC version?

    is there are a way to make the menu always fit within a specific area of the screen rather than the entire screen?

    Not with AC - it'd be a case of playing with Unity UI component values and/or a custom script.

    You may, however, be able to repurpose AC's AutoCorrectUIDimensions component. This script is used to rescale and reposition a canvas based on the screen size. You might be able to get somewhere by duplicating this and changing its calls to GetPlayableScreenArea with your own Rect that represents your "safe" screen dimensions.

  • Having an option to set a delay before scrolling would be convenient, agreed. I shall give this some thought.

    Thanks!

    Either way, though, the audio should not play when a token is processed. What is your AC version?

    It's the latest one, 1.74.

    Not with AC - it'd be a case of playing with Unity UI component values and/or a custom script.

    Cheers, I think for now It works to create an invisible panel with an extra border on top to coincide with the size of the top bar. I'm not too concerned about the bottom bar, but if it is ever an issue, I'll look into repurposing AutoCorrectUIDimensions.

  • I have rereated the audio issue, and will issue a fix in v1.74.1.

    On the pre-scrolling delay: it's possible to automatically precede your speech text with a wait token by hooking into the OnStartSpeech_Alt event and modifying the speech class:

    using UnityEngine;
    using AC;
    
    public class DelayScrolling : MonoBehaviour
    {
    
        private void OnEnable () { EventManager.OnStartSpeech_Alt += StartSpeech; }
        private void OnDisable () { EventManager.OnStartSpeech_Alt -= StartSpeech; }
    
        private void StartSpeech (Speech speech)
        {
            speech.ReplaceDisplayText ("[wait:1]" + speech.FullText);
        }
    
    }
    

    There is a minor issue with this, however, in that doing this will remove any wait tokens in the original dialogue text. I will add an "OriginalText" property that can be used insead of "FullText" in v1.74.1.

  • Thank you, Chris! That sounds great.

    One more question. I've made progress setting up my new chat bubble, and now I only need to be able to position the tail of the bubble accurately:

    The "Tail" rect transform is exactly the same width as the "bubble panel", and "Invisible Padding" (the RectTransform boundary I fed to the AC menu) is only a little wider than both. Also, Invisible Padding's pivot more or less coincides with the the Tail's pivot, so that the the tail appears directly above the speaking character. I say "more or less" because their widths are not quite the same, so depending on the size of the text their pivots won't be truly the same, but this looks fine in practice.

    So far so good. The issue only happens when the character is near the edge of the screen, as "Always fit within the screen?" pushes the bubble into full view (as it should), and the tail no longer appears under the speaking character. What I've been trying to do without much success is this:

    • Get the speaking character's X coordinate.
    • Get the X coordinates for both ends of the Bubble Panel.
    • Interpolate those numbers so that 0 is the left end of the Bubble Panel, 1 is the right end, and the speaking character's x coordinate falls somewhere between 0 and 1. Maybe use Mathf.Clamp if the character is not within that range.
    • Adjust the Tail's pivot so that it is the same as the number above.

    I think I can do the maths above + the adjustments, but I'm having a really hard time getting the initial numbers to work with. I know about menu.speech.GetSpeakingCharacter().GetSpeechScreenPosition(), and I can get some numbers from the RectTransforms, but I'm not really sure what to make of them.

    This gets me 90% there. Then I'll have to deal with the vertical side of things, e,g. what if a big speech bubble is pushed over the speaking character because of the upper screen boundary? The bottom tail should at the very least be removed in that case, but ideally the bubble would be pushed sideways and a new side tail would be displayed. But I'll try and figure this out once the horizontal one is working properly.

  • Have a look at the "UI Template: Speech bubble" package on the Downloads page - you may find it easier to adapt it rather than create one from scratch.

  • Thanks! I took a look, but it seems that I'd already implemented all the functionality it provides?

    The script provided, if I understand it correctly, only serves to determine the min and max width of the speech bubble and let it vary within those constraints. Then it places the arrow at a specific point relative to the current width of the bubble.

    What I'm trying to write is a script that tells me where on the screen the width of the bubble is currently placed (say 0.85 to 1 if the screen's total width ranges from 0 to 1). I also need to know where on the screen the speaker is currently placed (say, 0.95). I can use these numbers to dynamically move the arrow so it's placed directly above the speaker. The arrow is almost always displayed above the speaker, but not when the speaker is near the edge of the screen and the bubble is pushed to be entirely within the screen. I'm trying to account for that specific scenario.

    I think my only issue is that I don't know how to get those positions (the bubble's and the speaker's) in the same format/scale. Any advice? Once I figure this out, I think I know how to do the rest.

  • edited September 2021

    I got it. In case anybody else needs this:

    Vector2 characterposition = menu.speech.GetSpeakingCharacter().GetSpeechScreenPosition();
    characterposition = MainCamera.ConvertRelativeScreenSpaceToUI(characterposition);
    

    That's the speaker position. This is the bubble panel width and central x coordinate:

    public RectTransform BubblePanel;
    
    var worldCorners = new Vector3[4];
    BubblePanel.GetWorldCorners(worldCorners);
    var result = new Rect(
                      worldCorners[0].x,
                      worldCorners[0].y,
                      worldCorners[2].x - worldCorners[0].x,
                      worldCorners[2].y - worldCorners[0].y);
    
    float bubblepanelwidth = result.width;
    float bubblepanelcenter = BubblePanel.position.x
    
  • Chris, I gave this a try:

    You may, however, be able to repurpose AC's AutoCorrectUIDimensions component. This script is used to rescale and reposition a canvas based on the screen size. You might be able to get somewhere by duplicating this and changing its calls to GetPlayableScreenArea with your own Rect that represents your "safe" screen dimensions.

    And I don't think I got anywhere with it? Both the script as it is and my modified version didn't seem to do anything to my menu. So I created a new prefab with a canvas and only one image child, and hooked it to an AC menu that appears above the speaker during speech. I added the unmodified AutoCorrectUIDimensions to it and then edited this bit of code in a bunch of different ways (dividing numbers by 10, adding to them, etc, anything to cause disruption):

            protected Vector2 ConvertToPlayableSpace (Vector2 screenPosition)
            {
                Rect playableScreenArea = KickStarter.mainCamera.GetPlayableScreenArea (true);
                return new Vector2 (screenPosition.x * playableScreenArea.width, screenPosition.y * playableScreenArea.height) + playableScreenArea.position;
    
            }
    

    And this didn't change the boundaries where the element can be at all? "Always fit within screen?" still works but for the entire screen.

    What did you have in mind when you said this could work? I think I'm missing something.

  • Actually, all sorted. If anyone else needs a solution for this, all I did was create a panel, child it to the canvas and add an Aspect Ratio Fitter to it (aspect mode: fit to parent, and the ratio would be the one you picked for AC). Then I added my speech bubble as a child of that panel.

    Then I attached the following script to it. It will stop "Panel to Clamp" from being moved outside the "Parent Panel" when all offset variables are 0. By manipulating the variables, you are able to draw a safe rectangle wherever you want.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class ClampToCanvas : MonoBehaviour
    {
    
    
        public RectTransform panelToClamp;
        public RectTransform parentPanel;
        public float xMinPositionOffset;
        public float xMaxPositionOffset;
        public float yMinPositionOffset;
        public float yMaxPositionOffset;
    
    
        // Update is called once per frame
        void Update()
        {
            ClampToWindow();
        }
    
    
        void ClampToWindow()
        {
            Vector3 pos = panelToClamp.localPosition;
    
            Vector3 minPosition = parentPanel.rect.min - panelToClamp.rect.min;
            Vector3 maxPosition = parentPanel.rect.max - panelToClamp.rect.max;
    
            pos.x = Mathf.Clamp(panelToClamp.localPosition.x, minPosition.x+xMinPositionOffset, maxPosition.x+xMaxPositionOffset);
            pos.y = Mathf.Clamp(panelToClamp.localPosition.y, minPosition.y+yMinPositionOffset, maxPosition.y+yMaxPositionOffset);
    
            panelToClamp.localPosition = pos;
        }
    
    }
    
  • With v1.74.1 released, this script can now be used to automatically add a delay to all speech:

    using UnityEngine;
    using AC;
    
    public class DelaySpeechScrolling : MonoBehaviour
    {
    
        private void OnEnable () { EventManager.OnStartSpeech_Alt += OnStartSpeech; }
        private void OnDisable () { EventManager.OnStartSpeech_Alt -= OnStartSpeech; }
    
        private void OnStartSpeech (Speech speech)
        {
            speech.ReplaceDisplayText ("[wait:1] "+ speech.OriginalText);
        }
    }
    
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.