[Util] String Scroller (with colours!)

Discussion in 'Resources' started by Chinwe, Oct 19, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    Chinwe

    Ahoy!
    I've made a resource that will take a String, and split it up so the next() method can be called continually, which scrolls the message along a sign, scoreboard, a LivingEntity's custom name etc.

    The method takes four arguments: a String, two ints and a character.
    String string: The message you want to scroll
    int width: The width of each message - i.e. for a sign, the maximum width is 16
    int spaceBetween: The amount of spaces between each repetition of the message
    char colourChar: The character you are using for colour codes (normally '&' or '§')

    For example:
    Code:
    Scroller scroller = new Scroller("&aThis is a scrolling string!", 10, 5, '&');
    Calling scroller.next() will give these outputs respectively (in green):
    Code:
    "This is a "
    "his is a s"
    "is is a sc"
    When used correctly, the String that scrolls by will appear to be this:
    Code:
    "This is a scrolling string!    This is a scrolling string!    This is a scrolling string!" etc.
    A Bukkit example, that will scroll a message along a sign:
    Code:
    new BukkitRunnable()
    {
        Scroller scroller = new Scroller("&aThis is an &2important &amessage!", 16, 5, '&');
        Sign sign = a-sign-from-somewhere;
     
        public void run()
        {
            sign.setLine(0, scroller.next());
            sign.update();
        }
    }.runTaskTimer(plugin, 0L, 3L); // runs every 3 ticks
    The code!
    Code:
    /**
    * A util to scroll coloured Strings
    * @author Chinwe
    */
    public class Scroller
    {
        private static final char COLOUR_CHAR = '§';
        private int position;
        private List<String> list;
        private ChatColor colour = ChatColor.RESET;
     
     
        /**
        * @param message      The String to scroll
        * @param width        The width of the window to scroll across (i.e. 16 for signs)
        * @param spaceBetween The amount of spaces between each repetition
        * @param colourChar  The colour code character you're using (i.e. & or §)
        */
        public Scroller(String message, int width, int spaceBetween, char colourChar)
        {
            list = new ArrayList<String>();
     
            // Validation
            // String is too short for window
            if (message.length() < width)
            {
                StringBuilder sb = new StringBuilder(message);
                while (sb.length() < width)
                    sb.append(" ");
                message = sb.toString();
            }
     
            // Allow for colours which add 2 to the width
            width -= 2;
     
            // Invalid width/space size
            if (width < 1)
                width = 1;
            if (spaceBetween < 0)
                spaceBetween = 0;
     
            // Change to §
            if (colourChar != '§')
                message = ChatColor.translateAlternateColorCodes(colourChar, message);
     
     
            // Add substrings
            for (int i = 0; i < message.length() - width; i++)
                list.add(message.substring(i, i + width));
     
            // Add space between repeats
            StringBuilder space = new StringBuilder();
            for (int i = 0; i < spaceBetween; ++i)
            {
                list.add(message.substring(message.length() - width + (i > width ? width : i), message.length()) + space);
                if (space.length() < width)
                    space.append(" ");
            }
     
            // Wrap
            for (int i = 0; i < width - spaceBetween; ++i)
                list.add(message.substring(message.length() - width + spaceBetween + i, message.length()) + space + message.substring(0, i));
     
            // Join up
            for (int i = 0; i < spaceBetween; i++)
            {
                if (i > space.length())
                    break;
                list.add(space.substring(0, space.length() - i) + message.substring(0, width - (spaceBetween > width ? width : spaceBetween) + i));
            }
        }
     
        /**
        * @return Gets the next String to display
        */
        public String next()
        {
            StringBuilder sb = getNext();
            if (sb.charAt(sb.length() - 1) == COLOUR_CHAR)
                sb.setCharAt(sb.length() - 1, ' ');
     
            if (sb.charAt(0) == COLOUR_CHAR)
            {
                ChatColor c = ChatColor.getByChar(sb.charAt(1));
                if (c != null)
                {
                    colour = c;
                    sb = getNext();
                    if (sb.charAt(0) != ' ')
                        sb.setCharAt(0, ' ');
                }
            }
     
            return colour + sb.toString();
     
        }
     
        private StringBuilder getNext()
        {
            return new StringBuilder(list.get(position++ % list.size()).substring(0));
        }
     
    }
    Find the gist here!

    Or version 1 here (without colour support)

    Please leave any (constructive) critisism below!
     
  2. Offline

    Garris0n

    I would've made a 'ScrollingString' and just used a .next() method(have the constructor take a String and a length), but this is nice :)
     
  3. Offline

    DarkBladee12

    Garris0n I already made such a class, it's a bit shorter! You can see it here.
     
  4. Offline

    Garris0n

    Nice :)
     
  5. Offline

    DevRosemberg

    Chinwe Really nice, for sure will be using this in my network :p
     
  6. Offline

    Ultimate_n00b

    I made a fork here that is yet smaller, and only requires a string (using the length of the string as a width).
     
  7. Offline

    MrSparkzz

  8. Offline

    Ultimate_n00b

    Nah, I figured I would use this in MCBrawl somehow. Decided to fork it, and try that out.4
    EDIT: Speaking of that, working on a version that could work with color codes.
     
    MrSparkzz likes this.
  9. Offline

    MrSparkzz

    Ultimate_n00b
    Well I'll make one that you wont even have to place a sign, it'll just know to place it, and what you want to say. It will also look into the future ;)

    EDIT: Good luck with that, once half of the color code goes off the line it wont have color anymore. I'm sure that even saving it into a string would mess it up.

    Unless you saved all the color codes to a string array and checked what position they were at, then once you got to that position you removed both the ampersand and the number/letter then put the color code in front of it before updating the sign. Then once you get to the next one, go to the next color in the array. (Just some food for thought).
     
  10. Offline

    DarkBladee12

    MrSparkzz Well I also used a scrolling text on the PaintWar signs, but I didn't add color codes, I just made a ScrollingString with 14 width and added "§e" before this text :D But making something that keeps the color codes sounds interesting to try out, but it won't work for signs then.
     
  11. Offline

    Chinwe

    Added colour support and turned it into its own object with .next() :)

    I'm aware it isn't the most efficient/shortest method, but it works :confused:



     
    GrandmaJam likes this.
  12. Offline

    Garris0n

    Ultimate_n00b
    Perhaps using this to get the last colors from the full string then prefixing it to the returned string?
     
  13. Offline

    DarkBladee12

    Chinwe Does this also support multiple colors in a string like "§1This §2is §3a §4String"?
     
  14. Offline

    Chinwe

    DarkBladee12
    Yus, though sometimes (it seems) the § sign flashes as the colour changes :confused: - but apart from that, yes it does!
     
  15. Offline

    SacredWaste

    Thanks, I see this being pretty useful for someone lazy like me... Out of curiousity, have you tried to use this along multiple signs?
     
  16. Offline

    Chinwe

    SacredWaste
    I haven't, though I assume you would need to do some trickery on it to make colour codes transfer :confused:
    I tried doing scrolling along multiple signs before making this, and it didn't work at all - now I gotta try with this :)
     
  17. Chinwe How would I add this to a scoreboard?
     
  18. Offline

    Jake0oo0

    Scroller scroller = new Scroller("&aThis is a scrolling string!", 10, 5, '&');
    scoreboard.setDisplayName(scroller.next());

    and run the second line in a task for every few seconds
     
    KevyPorter likes this.
  19. Offline

    DevRosemberg

    Chinwe for some reason Maven dosent like the § and wont compile it and also i am experiencing a bug when i do this:

    Code:java
    1. final ScrollerUtils scroller = new ScrollerUtils("&lWelcome " + player.getName() + " to Minereach!", 20, 1, '&');
    2.  
    3. MinereachLobby.getInstance().getServer().getScheduler().scheduleSyncRepeatingTask(MinereachLobby.getInstance(), new Runnable() {
    4. public final void run() {
    5. objective.setDisplayName(scroller.next());
    6. }
    7. }
    8. , 4L,4L);


    It dosent set it to bold or it displays the &l also.
     
    GrandmaJam likes this.
  20. Offline

    SoThatsIt

    you could just create 2 scrollers and set the second one to start 16 characters into the string

    so scroller1 = "this is a scrolling text, awesome"
    and scroller2 = "ing text, awesome <not sure how many spaces you use :p> this is a scroll"
     
  21. Offline

    chasechocolate

    Haha, nice; I literally made one a week before you posted to be used with my boss health bar util :p
     
    GrandmaJam likes this.
  22. Offline

    Skyost

    Screens ? :)
     
    GrandmaJam likes this.
  23. Chinwe
    How can I do this with scoreboard objectives?
     
    GrandmaJam likes this.
  24. Offline

    Chinwe

    The Gaming Grunts
    I don't know much about the mechanics of scoreboards, although you should do something like this:
    Code:
    // create a single Scroller
    Scroller scroller = new Scroller("This will scroll on scoreboards", 16, 5, '&');
     
    // create a BukkitRunnable that runs every few ticks to update everyone's scoreboards
    // ...
    public void run()
    {
        // get the next scroll
        String next = scroller.next();
     
        // loop through all players
        for (Player p : Bukkit.getOnlinePlayers())
        {
          // update their scoreboard with 'next'
        }
         
    }
     
    GrandmaJam likes this.
  25. Chinwe
    I know how to do it for the scoreboard "title", but every time I try it for the individual objectives it bugs out :(
     
  26. Offline

    sgavster

  27. Offline

    moose517

    What kind of performance impact are you talking if for example you were to have hundreds of signs scrolling like that?
     
  28. This looks nice however why not take in a ChatColor instead of a color char?
     
    sgavster likes this.
Thread Status:
Not open for further replies.

Share This Page