Search Unity

TextMesh Pro Using linked overflow with pages?

Discussion in 'UGUI & TextMesh Pro' started by MartinIsla, Apr 10, 2020.

  1. MartinIsla

    MartinIsla

    Joined:
    Sep 18, 2013
    Posts:
    104
    Update:
    This was yet another XY Problem. I solved this by using Linked pages (so I only set left page text, overflow goes to right page) and set left page's firstVisibleCharacter to right page's firstOverflowCharacterIndex when I want to go to the next two pages.

    Have a nice day everyone, just like the one I'm having right now.


    Hello everyone!

    This is something I've been dealing with for quite some time now. I tried multiple solutions, all of them seem to work initially, but a new problem always appears after every couple of weeks, some case where they don't work, and I need to find a new approach. That's why I'm asking for help now.

    I have a book, you can click arrows to go to the next/previous two pages. The problem I want to solve is how do I fit the text (that is a single string and can contain <sprites> that take up multiple lines so they look like illustrations in the book) into as many pages as needed.

    I tried:
    - Using TextGenerator with TMPro component values to estimate how much text will fit in each page.
    - Using hardcoded values.
    - A very ugly, desperate thing where I actually assigned the text, rebuilt the layout and checked how much text was shown. This one worked amazingly, but it was also non-surprisingly extremely expensive.

    An ideal solution would be something like using Linked overflow (so the content on the left page continues on the right page) but combined with Page overflow, so I can go to next/previous pages after I finished reading the right page. For what I've seen, there's no built-in solution (of course there isn't, it's a pretty specific thing that would rarely be useful for something that's not this game), so I'm looking for a workaround. I could try having multiple linked texts so leftPageOne is linked to rightPageOne, then rightPageOne is linked to leftPageTwo and so on. This would work but also be disgusting (and not fail-proof, since I don't know how long books will be).

    Any idea is appreciated right now. Going crazy here!

    Thanks :)
     
    Last edited: Apr 10, 2020
    ClawtheWolf likes this.
  2. ClawtheWolf

    ClawtheWolf

    Joined:
    Apr 4, 2019
    Posts:
    2
    May I see the code you used? Because when I do it, I get an IndexOutOfRange Exception, a blank right page and the left page stays the way it was originally.
     
  3. MartinIsla

    MartinIsla

    Joined:
    Sep 18, 2013
    Posts:
    104
    I can't really share the entire code cause it's for work, but this is how I move to the next two pages:

    Code (CSharp):
    1. leftPage.contentText.firstVisibleCharacter = rightPage.contentText.firstOverflowCharacterIndex;
    Going to the previous pages was a bit tricky, I came up with a solution I'm really not proud of, but it works. Whenever I move to the next two pages, I save the index of the first character in a list

    Code (CSharp):
    1.    // Save current firstVisibleCharacter
    2.    if (_pagesFirstVisibleCharacters.Count - 1 < _currentPageIndex) {
    3.       _pagesFirstVisibleCharacters.Add(leftPage.contentText.firstVisibleCharacter);
    4.    }
    So when I want to go back, I set the firstVisibleCharacter of the text using the value saved in that list

    Code (CSharp):
    1. leftPage.contentText.firstVisibleCharacter = _pagesFirstVisibleCharacters[_currentPageIndex];
     
    ClawtheWolf likes this.
  4. ClawtheWolf

    ClawtheWolf

    Joined:
    Apr 4, 2019
    Posts:
    2
    Thanks so much!! It was really helpful!
     
  5. Damjan-Mozetic

    Damjan-Mozetic

    Joined:
    Aug 15, 2013
    Posts:
    46
    edit: Calling ForceMeshUpdate() on the TMP_Texts populated the fields. Problem solved!

    @MartinIsla this has been very helpful, thank you! I am creating a journal for my RPG in development and I am doing the same thing: Two pages visible at a time. The only thing I am stuck at, is figuring out when I've reached the end of the "book", so I can disable the "next page" button.

    I've tried checking textRight.firstOverflowCharacterIndex != -1 but it is always -1 in my case, even when the text overflows (right page is set to truncate). Also the other properties, like isTextOverflowing, for example but it always seems to be set to false.

    I would appreciate any insight! Thank you!
     
    Last edited: Aug 26, 2020
  6. MartinIsla

    MartinIsla

    Joined:
    Sep 18, 2013
    Posts:
    104
    Glad I could help!
    I'm looking at my code and I use rightPageText.isTextTruncated (extremely close to what you tried!) to know if I've reached the end. If isTextTruncated is false, you've reached the end of the book. Here's the part of my code that enables or disables the left/right navigation buttons:

    Code (CSharp):
    1.       // Enable or disable navigation arrows depending on whether or not you can keep navigating
    2.       leftArrow.interactable = leftPage.contentText.firstVisibleCharacter > 0;
    3.       rightArrow.interactable = rightPage.contentText.isTextTruncated;
    Hope this works for you!

    Sidenote: your game looks really interesting, I'm following you!

    Edit: I just saw your edit and it made me remember. I went back to that code once again and it turns out I'm waiting a frame before checking if text.isTextTruncated. This is because TMPro (and many other UI things) doesn't refresh some values until the next frame. If ForceMeshUpdate gives you problems or impacts your performance (which I doubt tbh), using a coroutine and yield return null before checking the text values should work just as fine.
     
    Last edited: Aug 26, 2020
    Damjan-Mozetic likes this.
  7. Damjan-Mozetic

    Damjan-Mozetic

    Joined:
    Aug 15, 2013
    Posts:
    46
    Thanks MartinIsla. I solved the buttons issue in a very similar way (just tracking the currentPageIndex > 0 instead of firstVisibleCharacter > 0).

    P.S. Thanks for following! :)
     
  8. Slink472

    Slink472

    Joined:
    Jul 22, 2017
    Posts:
    6
    Thank you so much for the information here! I'm working on a similar book system and this saved me a lot of time messing around with the code.

    I had a question though, how did you manage to let your illustrations take up multiple lines of text like you mentioned in your first post? Did you just use repeated line breaks? I'm also trying to fit in whole-page illustrations into my books but am finding that TextMesh Pro only allows for the glyph to take up a single line, regardless of their scale. And if I start nesting my sprite in line breaks, I have to manually adjust its positioning every time I add text to the book or change the font size. Thanks again!
     
  9. MartinIsla

    MartinIsla

    Joined:
    Sep 18, 2013
    Posts:
    104
    If you select your SpriteAsset you'll have options for ascend and descend values, which are the vertical space before and after the sprite. You can play with those!

    In my case, all the images are the same size (272x272), so I could just set ascend and descend globally to spriteHeight / 2 + someWhiteSpaceAround (so 272 / 2 = 136 + 4 = 140 for both ascend and descend).

    If your images aren't always the same size, you can set these values for each image in the sprite asset too.

    Good luck!
     
    Slink472 likes this.
  10. Slink472

    Slink472

    Joined:
    Jul 22, 2017
    Posts:
    6
    Ah got it! I spent half an hour looking for this field before I realized I was running a version of Unity from more than a year ago. I updated the project and found the field - it worked perfectly. Thank you again! You really made my day with this thread.
     
  11. MartinIsla

    MartinIsla

    Joined:
    Sep 18, 2013
    Posts:
    104
    Oh, I totally missed that possibility. I'm glad I could help!