1.17.x Animation algorithm for Scoreboards

Discussion in 'Spigot Plugin Development' started by parpar8090, Aug 9, 2021.

  1. Hey, so I'm trying to make an algorithm that animates something like the scoreboard title.
    rightToLeftAnimation.gif (this is an animated gif, click on it for the animation)

    I came up with this code, which in theory (didn't test yet) should work as expected (with an additional touch, which is the middleColor).
    Code (Java):
        /**
         * Animate a text with colors that move from left to right.
         * The animation end once the firstColor reached the length of the message, which results in a half cycle.
         * @param message The message to be animated
         * @param firstColor The color for the first section of the message (example color: {@link ChatColor#YELLOW})
         * @param middleColor The color for the middle section of the message, a 1 character long section that separates between the first and last sections (example color: {@link ChatColor#WHITE}).
         * @param lastColor The color for the last section of the message (example color: {@link ChatColor#GOLD}).
         * @return List of ordered string frames.
         */

        public static List<String> leftToRight(String message, ChatColor firstColor, @Nullable ChatColor middleColor, ChatColor lastColor){
            int size = message.length();
            List<String> result = new ArrayList<>();

            for(int frame = 0; frame < size; frame++){

                String first = "";
                Character middle = '\0';
                String last = message;

                //prevent out of index error
                if(frame != 0)
                    first+=message.charAt(frame-1); // ascend

                if(middleColor != null) middle = message.charAt(frame);

                last=last.substring(1); // descend

                result.add(String.join(firstColor + first, String.valueOf(middle), lastColor+last));
            }
            return result;
        }
    The question now is how do I make a full cycle? By a full cycle I mean: Orange text -> Yellow text -> Orange text.

    NOTE: I don't use a runnable in this method, instead I use frames, which are way better for my needs.

    If I use the method above twice, for the first half cycle and the second, it will have duplicates once each half animation is completed.

    Can I please have your help?
     
    #1 parpar8090, Aug 9, 2021
    Last edited: Aug 9, 2021
  2. You could use a cursor and a ternary operator like this:

    Code (Text):

    for (int j=0; j < strLength; j++) {
    ChatColor color = this.i < j ? yellow : orange
    msg += color + heart
    }
     
    //increase i every tick and limit it
    like this:
    this.i = this.i++ % yourSize

    Also use a scheduler to repeat this every X ticks. store the SB and (re)set it's name every X ticks.
     
  3. I won't use a scheduler in this method, this method only generates the frames (stored in a list of string).

    I'm not sure how I to implement the middleColor in this method and if this will make a full cycle animation. (a full cycle is: message is fully yellow -> message is fully orange/gold -> message is fully yellow again)
     
  4. Not sure how you wanna do this without scheduler but the upper code is an algorithm you want to achieve the gif. Just in/decrease i or swap orange with yellow.

    If you want it as as a List, why you haven't wrote it?

    You only have to add another for loop and add it in a Collection

    If you want more colors you maybe need to use a switch instead of ? :

    Code (Text):

    switch(i) {
     case 4 -> yellow;
    case 8 -> orange;
      default -> white
    }
     
    Or sth else
     
    #4 Player_Schark, Aug 9, 2021
    Last edited: Aug 9, 2021
  5. I have a scheduler in another method (which is way better for my use, and I know it). Also, what is i and why is it a field?
     
  6. I have some questions with your code.
    • what is the "heart" variable? Is it the character to be colored? (if so, it might be useless to put ChatColor duplicates after each letter and might even be intensive)
    • Why do we need to color differently when i is 4, 8 and else?
    I think this code is not what I need.
     
  7. Are you looking to just alternate between the color enums or to cycle through gradients?
     
  8. I want a full cycle, from orange to yellow and then back to orange. Like here:
    [​IMG] (this is an animated gif, click on it for animation)
     

    Attached Files:

  9. I'd just make a timer (See runnable, or bukkitrunnable) that increments a counter that maxes at the length of that string.

    Each interval of the timer, increment the count.
    Splice the string up to the point of the counter, color one side gold other yellow.
    When counter maxes, set it back to 0, and then flip the colors to your desired new colors that will cycle
     
  10. I am sorry but I don't use a runnable in this method, the runnable is in a different method and we don't need it right now. This method is intended to generate the frames that will then be put in the other method.
     
  11. Okay then don't do it in a runnable and save the strings made by this in a list and iterate through them when you want your scoreboard to cycle
     
  12. Here's my code, making sure that's what you meant.
    Code (Java):

    public static List<String> leftToRightFull(String message, ChatColor firstColor, @Nullable ChatColor middleColor, ChatColor lastColor){
        int size = message.length();
        List<String> result = new ArrayList<>();

        //the *2 will make a complete cycle, -2 will remove duplicates.
        for(int frame = 0; frame < size*2-2; frame++){
            String first = "", last = message, middleColorChecked = ""+(middleColor != null ? middleColor : "");
            char middle = '\0';

            //prevent out of index error
            if(frame > 0)
                first=message.substring(0, frame-1%(size-1)); // ascend
            if(middleColor != null)
                middle = message.charAt(frame%(size-1));
            last=last.substring(1); // descend
            if(frame < size-1)
                result.add(String.join(firstColor + first, middleColorChecked+middle, lastColor+last));
            else // flip colors
                result.add(String.join(lastColor + first, middleColorChecked+middle, firstColor+last));
        }
        return result;
    }
     
     
  13. I was thinking more like:
    Code (Java):
        /**
         * Gets a list of strings representing changes in individual characters instead of the entire string at once.
         *
         * @param message message to have colors changed.
         * @param newColor new color for the message to be.
         * @return list of strings representing changes in individual characters instead of the entire string at once.
         */

        public static List<String> getColorTransitionFrames(final String message, final Color newColor, final Color oldColor) {
            return new ArrayList<>() {
                {
                    for (int i = 0; i < message.length(); i++) {
                        final String messageFrame = newColor + message.substring(0, i) + oldColor + message.substring(i);
                        add(messageFrame);
                    }
                    add(newColor + message);
                }};
        }
    }
    Then you just called it for whatever colors you want to cycle. E.G.

    Code (Java):
        public static void main(String[] args) {
            final List<String> allFrames = new ArrayList<>() {{
            addAll(getColorTransitionFrames("hello", GOLD, YELLOW));
            addAll(getColorTransitionFrames("hello", YELLOW, GOLD));
           }}
        }
     
    Edit:
    Here's what the output would look like:
    Code (Java):
    GOLDYELLOWhello
    GOLDhYELLOWello
    GOLDheYELLOWllo
    GOLDhelYELLOWlo
    GOLDhellYELLOWo
    GOLDhello
    YELLOWGOLDhello
    YELLOWhGOLDello
    YELLOWheGOLDllo
    YELLOWhelGOLDlo
    YELLOWhellGOLDo
    YELLOWhello