• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Scrolling Text 2.3.0

  • Like
Reactions: EtikS and Eccho
A library for scrolling text upwards.

Uses vJass.

04/01/2013 - Version 2.3.0
- removed overhead associated with displaying ScrollingText instances
- added a way to stop displaying a ScrollingText instance immediately.
- added a way to retrieve the currently displaying ScrollingText instance

12/27/2012 - Version 2.2.1
- optimizations (building the text to display only when needed)
- refactoring for better readability

12/27/2012 - Version 2.2.0
- removed tokenization and method addEx
- renamed struct from ScrollText to ScrollingText to match the library name
- removed counting calls to DisplayTimedTextToPlayer (debug-only before)
- added comments to the main logic

08/12/2012 - Version 2.1.0
- now automatically delays destroying until after finishing displaying the text

08/12/2012 - Version 2.0.0
- major refactoring for code cleanliness, descriptive names, better interface
- fixed the major caveat of lag after too many calls to DisplayTimedTextToPlayer by reducing calls to that function by a factor of at best 15

03/26/2009 - Version 1.0.0
- initial release


JASS:
// *************************************************************
// *             Scrolling Text -- Version 2.3.0
// *                        by Deaod
// *************************************************************
// *
// *    CREDITS:
// *        - Anitarf (valuable research about in-game messages)
// *        - UnMi, overcold_ice (inspiration)
// *        - Vexorian (JassHelper)
// *        - PitzerMike (JassNewGenPack)
// *        - Pipedream (Grimoire)
// *        - SFilip (TESH)
// *
// *    HOW TO USE:
// *        * declare a variable of type ScrollingText
// *
// *        * use ScrollingText.create() to create a new instance
// *
// *        * add text to display using YourScrollingTextInstance.add(string toAdd)
// *            - toAdd is the actual text that should be displayed as credits.
// *            - make sure toAdd is not longer than a single line in-game.
// *
// *        * to display the ScrollingText, use YourScrollingTextInstance.display(real xOffset, real yOffset, real speed)
// *            - xOffset and yOffset move the point where the Credits are being spawned around
// *            - speed is the scrolling speed of the credits in lines per second
// *
// *        * to stop displaying the ScrollingText, use ScrollingText.stopDisplay()
// *            - this will clear the screen of any messages
// * 
// *        * to get the currently displaying instance, use ScrollingText.getCurrentInstance()
// *            - returns the currently displaying instance or 0 if no instance is currently displaying
// *
// *************************************************************
library ScrollingText
    
    globals
        private constant    real    LINE_HEIGHT             = 1./15 // 1./15 seems to be the optimal value
        private constant    integer MAX_DISP_LINES          = 15    // 15 is suggested upper limit
        private constant    integer MAX_LINES_PER_INSTANCE  = 1023  // 
        private constant    real    TICK                    = 1./40 // in seconds
    endglobals
    
    struct ScrollingText
        private real speed
        private real scrollDistance
        private real xOff
        private real yOff
        private string linesDisplaying
        private string array linesToDisplay[MAX_LINES_PER_INSTANCE]
        private integer linesCount = 0
        
        private boolean destroyWhenDone = false
        
        private static integer running = 0
        private static timer displayTimer = CreateTimer()
        
        method add takes string toAdd returns nothing
            if linesCount >= MAX_LINES_PER_INSTANCE then
                debug call BJDebugMsg("ScrollingText.add(): MAX_LINES_PER_INSTANCE exceeded. Discarding following text.")
                return
            endif
            set linesToDisplay[linesCount] = toAdd
            if linesToDisplay[linesCount] == "" or linesToDisplay[linesCount] == null then // avoid displaying (null)
                set linesToDisplay[linesCount] = " "
            endif
            set linesCount = linesCount + 1
        endmethod
        
        private method regenerateLinesDisplaying takes integer currentLine returns nothing
        local integer index
            set index = IMinBJ(currentLine, MAX_DISP_LINES) // number of lines to display
            // lets gather the last 'index2' lines in 'linesDisplaying'
            set linesDisplaying = ""
            loop
                exitwhen index <= 0
                if currentLine - index < linesCount then // do we need to add more lines for padding?
                    set linesDisplaying = linesDisplaying + linesToDisplay[currentLine - index] // apparently not, so just take whats there.
                else
                    set linesDisplaying = linesDisplaying + " " // we do, so add a single whitespace
                endif
                if index > 1 then
                    set linesDisplaying = linesDisplaying + "\n" // add a newline character, unless were at the end
                endif
                set index = index - 1
            endloop
        endmethod
        
        private static method callback takes nothing returns nothing
        local integer lastLine
        local integer currentLine
        local thistype this = running
            set lastLine = R2I(scrollDistance / LINE_HEIGHT) + 1
            set scrollDistance = scrollDistance + speed // scroll further
            set currentLine = R2I(scrollDistance / LINE_HEIGHT) + 1 // generate the line were currently on, offset by +1
            if lastLine < currentLine then // check whether we need to display a new line
                call regenerateLinesDisplaying(currentLine)
            endif
            
            call ClearTextMessages()
            call DisplayTimedTextToPlayer(GetLocalPlayer(), xOff, yOff + (scrollDistance - R2I(scrollDistance / LINE_HEIGHT) * LINE_HEIGHT), 16*TICK, linesDisplaying)
            
            if currentLine > linesCount + MAX_DISP_LINES then
                set running = 0
                call PauseTimer(displayTimer)
                if destroyWhenDone then
                    call destroy()
                endif
            endif
        endmethod
        
        method display takes real xOffset, real yOffset, real speed returns nothing
            if running != 0 then
                debug call BJDebugMsg("ScrollingText.display(): Can not display two instances at the same time.")
                return
            endif
            set this.speed = speed * LINE_HEIGHT * TICK
            set scrollDistance = 0
            set xOff = xOffset
            set yOff = yOffset
            set running = this
            call regenerateLinesDisplaying(1)
            
            call TimerStart(displayTimer, TICK, true, function thistype.callback)
        endmethod
        
        static method stopDisplay takes nothing returns nothing
        local thistype this
            if running != 0 then
                set this = running
                call ClearTextMessages()
                set running = 0
                call PauseTimer(displayTimer)
                if destroyWhenDone then
                    call destroy()
                endif
            endif
        endmethod
        
        static method getDisplayedInstance takes nothing returns thistype
            return running
        endmethod
        
        method destroy takes nothing returns nothing
            if running != 0 then
                set destroyWhenDone = true
                return
            endif
            call deallocate()
        endmethod
    endstruct
    
endlibrary

NOTE: Some users have reported experiencing lag near the end of the demo. This is the most serious flaw of this system, but theres nothing i can do about that bug. The only solutions are to not display too many lines of text, or to increase the scrolling speed or to increase TICK (though higher values than 1/24 are not recommended). -- Fixed in Version 2.0.0

Keywords:
Scrolling, Text
Contents

Scrolling Text (Map)

Reviews
06:48, 3rd Apr 2009 Eccho: This system is very cool. It does not leak, has pretty understandable code, and is as efficient as possible and does not desync (as far as I know.) The lag is a downside... And well, if it could be less croppy I would...

Moderator

M

Moderator

06:48, 3rd Apr 2009
Eccho:

This system is very cool. It does not leak, has pretty understandable code, and is as efficient as possible and does not desync (as far as I know.)
The lag is a downside... And well, if it could be less croppy I would be satisfied.
This is the reson why it could not get the highest rating.

Oh and, a question. How about making this system with texttags? It would work too, and I haven't seen this kind of system in the database yet.

Overall, a good job. This is approved and recommended.
 
Level 14
Joined
Nov 18, 2007
Messages
816
Yet, the string-table trashing causing the lag is a downside for sure.
The string table is not the reason for the lag. Whats causing the lag are the thousands of calls to DisplayTimedTextToPlayer. The String Table leak is roughly (2+(Length of Linebreak))*(Length of Original String (Unprocessed)) in bytes. Not a big deal.
 
Level 23
Joined
Nov 29, 2006
Messages
2,482
The string table is not the reason for the lag. Whats causing the lag are the thousands of calls to DisplayTimedTextToPlayer. The String Table leak is roughly (2+(Length of Linebreak))*(Length of Original String (Unprocessed)) in bytes. Not a big deal.

Okay, I am wrong at that point. But then again, that is the issue even though you cant do anything about it. Texttags would work much smoother.

And another personal opinion which I didnt like (doesnt matter though), is that the lines are not smoothly moving upwards. The lines so to speak, goes closer and then further and then closer away from each other while moving upwards. Is it possible to avoid? It would look better =)
 
Level 14
Joined
Nov 18, 2007
Messages
816
@Eccho:
There's a reason why i made some constants.
JASS:
    globals
        private constant real LINE_HEIGHT = 1./15
        private constant integer MAX_DISP_LINES = 16
        private constant integer MAX_LINES_PER_INSTANCE = 1023
        private constant real TICK = 1./24
    endglobals
To make things more smooth, decrease TICK (which increases the overall calls to DisplayTimedTextToPlayer), and/or adjust LINE_HEIGHT. I have been unable to make it really smooth though.

@UnMi: Meh, ive never started the map from WC3. I've always used the Test Map button. Should change that, though.

and @Dynasti: If you had taken a look at the code, you wouldve noticed i always call ClearTextMessages() before i display the new ones.
 
Level 23
Joined
Nov 29, 2006
Messages
2,482
One line itself is running smooth. What I meant was (oversized example below)

A) time = 0

-----bla----

----bla3----
B) time = 0.03 (for instance)

-----bla----
-----bla3---

C) time = 0.06 (for instance)
-----bla----

-----bla3---

So, the lines in between is not smootly running. But I guess that was what you explained. Decreasing the tick will make this even less visible.
 
Level 14
Joined
Nov 18, 2007
Messages
816
Version 2.0.0

After three and a half years i finally figured out i dont need to call DisplayTimedTextToPlayer all that often to achieve the desired effect. Enjoy.

Hows that for a bump?

EDIT:

Version 2.1.0

Apologies to the one guy who downloaded 2.0.0.
 
Last edited:
Level 1
Joined
Apr 21, 2013
Messages
1
Hello friends, please tell me as who I can add this to my map correctly???

I'm new to this, but I would like to learn

Thank you!
 
Level 14
Joined
Nov 18, 2007
Messages
816
Okay, so to add this to your map, you need to download JassNewGenPack v5d.

Now open the JassNewGenPack WorldEditor (instructions can be found on the download site). I suggest you just use that editor from now on, since theres no real downside and you get a bunch of tools to help you mapping.

Open your map.

Create a new trigger in the trigger editor. Name it ScrollingText (you can name it pretty much anything, but i would recommend you use this name).

While having your new trigger selected, click on Edit->Convert To Custom Text. You should now see a bunch of text - delete all of it, we dont need it anymore.

Copy everything inside the white box in the first post and paste it where the text was.

You can now use ScrollingText inside your map with certain conditions (libraries need to require ScrollingText in order to use it).
For a more detailed example, take a look at the map uploaded here, you should find a simple example inside the trigger called test.

If you dont know (v)JASS, this might be a good time to start learning. JASS is one of the simplest scripting languages to learn and there should be a multitude of resources available to help you get on track.

You can probably manage to use this library from GUI, but i personally dont support that usage, mostly because youre going to write vJass anyway. Im sure other people in the Triggers and Scripts forum are willing to help you in that regard.

Anyway, i hope this short description helped you. Should you still have questions, feel free to ask and ill elaborate as best i can.
 
Top