Java tutorial
/* * The MIT License (MIT) * * Copyright (c) 2016 Tellerva, Marc Lawrence * * Permission is hereby granted, free of charge, to any * person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the * Software without restriction, including without * limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software * is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice * shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ package me.scarlet.undertailor.gfx.text; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.utils.Array; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import me.scarlet.undertailor.Undertailor; import me.scarlet.undertailor.audio.SoundFactory.Sound; import me.scarlet.undertailor.gfx.text.parse.TextParam; import me.scarlet.undertailor.gfx.text.parse.TextPiece; /** * A segment of text with a number of properties within a * parent {@link Text} object. */ public class TextComponent { static final float DEFAULT_SPEED = 35.0F; static final int DEFAULT_SEGMENT = 1; /** * Builder-type class for building {@link TextComponent} * s. */ public static class Builder { TextComponent component; public Builder() { this(new TextComponent()); } protected Builder(TextComponent target) { this.component = target; } /** * Sets the text held by the {@link TextComponent}. * * @param text the text for the component * * @return this Builder */ public Builder setText(String text) { this.component.text = text; return this; } /** * Sets the font held by the {@link TextComponent}. * * @param font the font for the component * * @return this Builder */ public Builder setFont(Font font) { this.component.font = font; return this; } /** * Sets the color used by the {@link TextComponent}. * * @param color the color for the component * * @return this Builder */ public Builder setColor(Color color) { this.component.color = color; return this; } /** * Sets the sound associated with the * {@link TextComponent}. * * @param sound the sound for the component * * @return this Builder */ public Builder setSound(Sound sound) { this.component.sound = sound; return this; } /** * Add {@link TextStyle}s altering how the text of * the {@link TextComponent} is rendered. * * @param styles TextStyles to add * * @return this Builder */ public Builder addStyles(TextStyle... styles) { for (TextStyle style : styles) { this.component.styles.add(style); } return this; } /** * Sets the speed value associated with the * {@link TextComponent}. * * @param speed the speed value of the component * * @return this Builder */ public Builder setSpeed(float speed) { this.component.speed = speed; return this; } /** * Sets the segment size value associated with the * {@link TextComponent}. * * @param size the segment size value of the * component * * @return this Builder */ public Builder setSegmentSize(int size) { this.component.segmentSize = size; return this; } /** * Sets the delay value associated with the * {@link TextComponent}. * * @param delay the delay value of the component * * @return this Builder */ public Builder setDelay(float delay) { this.component.delay = delay; return this; } /** * Copies all the parameters of the provided * {@link TextComponent} into the one to be * generated. * * @param source the source component to copy from * * @return this Builder */ public Builder copy(TextComponent source) { this.component.color = source.color == null ? null : new Color(source.color); this.component.delay = source.delay; this.component.font = source.font; this.component.segmentSize = source.segmentSize; this.component.sound = source.sound; this.component.speed = source.speed; this.component.styles.addAll(source.styles); return this; } /** * Builds the {@link TextComponent} with the * parameters assigned to this {@link Builder} and * returns it. * * @return a new TextComponent */ public TextComponent build() { if (this.component.text == null || this.component.text.isEmpty()) { throw new IllegalArgumentException("Component text cannot be null or empty"); } if (this.component.delay < 0F) this.component.delay = 0F; return this.component; } } static final Logger logger = LoggerFactory.getLogger(TextComponent.class); /** * Returns a new {@link Builder} instance to build a new * {@link TextComponent}. * * @return a Text Builder */ public static Builder builder() { return new Builder(); } /** * Generates a new {@link TextComponent} using the * properties set upon the given {@link TextPiece}. * * @param tailor the current Undertailor instance * @param piece the TextPiece to read from * * @return a new TextComponent */ public static TextComponent of(Undertailor tailor, TextPiece piece) { Builder builder = TextComponent.builder(); TextComponent.applyParameters(builder, tailor, piece); builder.setText(piece.getMessage()); return builder.build(); } /** * Internal method. * * <p>Applies the parameters found on a single * {@link TextPiece} onto the provided {@link Builder} * .</p> * * @param builder the Builder to apply parameters to * @param tailor the current Undertailor instance * @param piece the TextPiece to read from */ protected static void applyParameters(Builder builder, Undertailor tailor, TextPiece piece) { piece.getParams().entries().forEach(entry -> { TextParam paramType = entry.key; String value = entry.value; if (value == null || value.trim().isEmpty()) { return; } switch (paramType) { case FONT: Font font = tailor.getAssetManager().getFontManager().getFont(value); if (font == null && (value != null && !value.trim().isEmpty())) logger.warn("Couldn't find font " + value + " to assign to text"); builder.setFont(font); break; case SOUND: Sound sound = tailor.getAssetManager().getAudioManager().getSound(value); if (sound == null) logger.warn("Couldn't find sound " + value + " to assign to text"); builder.setSound(sound); break; case STYLE: String[] split = value.split(","); for (String styleValue : split) { TextStyle style = tailor.getAssetManager().getStyleManager().getStyle(styleValue); if (style == null) logger.warn("Couldn't find style " + value + " to assign to text"); builder.addStyles(style); } break; case COLOR: case DELAY: case SEGMENTSIZE: case SPEED: try { if (paramType == TextParam.COLOR) { String[] rgb = value.trim().split(","); if (rgb.length > 1) { Color color = new Color(); color.set(Float.valueOf(rgb[0]), Float.valueOf(rgb[1]), Float.valueOf(rgb[2]), rgb.length >= 4 ? Float.valueOf(rgb[3]) : 255F); } else { if (!value.startsWith("#")) { value = "#" + value; } if (value.length() < 7) { throw new IllegalArgumentException(); } builder.setColor(Color.valueOf(value)); } } else { if (paramType == TextParam.DELAY) { builder.setDelay(Float.valueOf(value)); } else if (paramType == TextParam.SEGMENTSIZE) { builder.setSegmentSize(Integer.valueOf(value)); } else if (paramType == TextParam.SPEED) { builder.setSpeed(Float.valueOf(value)); } } } catch (Exception e) { logger.warn("Invalid value " + value + " for parameter " + paramType.toString()); } break; default: break; } }); } // ---------------- object ---------------- protected Text parent; String text; Font font; Color color; Sound sound; Array<TextStyle> styles; float speed; // characters per second int segmentSize; // "flame" < size 1 = "f", size 2 = "fl" float delay; // delay before the component is played protected TextComponent() { this.text = ""; this.font = null; this.color = null; this.sound = null; this.styles = new Array<>(true, 4); this.speed = -1; this.segmentSize = -1; this.delay = 0F; } /** * Returns the text associated with this * {@link TextComponent}. * * @return this component's text */ public String getText() { return this.text; } /** * Returns the font associated with this * {@link TextComponent}, or the font of its parent * {@link Text} object if one was not assigned. * * @return the Font for this component */ public Font getFont() { if (this.font == null && parent != null) { return this.parent.getFont(); } return this.font; } /** * Returns the color associated with this * {@link TextComponent}, or the color of its parent * {@link Text} object if one was not assigned. * * @return the Color for this component */ public Color getColor() { if (this.color == null && parent != null) { return this.parent.getColor(); } return this.color; } /** * Returns the sound associated with this * {@link TextComponent}, or the sound of its parent * {@link Text} object if one was not assigned. * * @return the Sound for this component */ public Sound getSound() { if (this.sound == null && parent != null) { return this.parent.getSound(); } return this.sound; } /** * Returns the list of {@link TextStyle}s in the order * of applicance assigned to this {@link TextComponent}, * or the list of its parent {@link Text} object if no * styles were assigned. * * @return the TextStyles for this component */ public Array<TextStyle> getStyles() { if (this.styles.size <= 0 && parent != null) { return parent.getStyles(); } return this.styles; } /** * Returns the text speed value, in characters per * second, associated with this {@link TextComponent}, * or the value of its parent {@link Text} object if one * was not assigned. * * @return the text speed for this component */ public float getTextSpeed() { if (this.speed <= -1) { if (parent == null) { return DEFAULT_SPEED; } else { return this.parent.getTextSpeed(); } } return this.speed; } /** * Returns the segment size value associated with this * {@link TextComponent}, or the value of its parent * {@link Text} object if one was not assigned. * * @return the segment size value for this component */ public int getSegmentSize() { if (this.segmentSize <= -1) { if (parent == null) { return DEFAULT_SEGMENT; } else { return this.parent.getSegmentSize(); } } return this.segmentSize; } /** * Returns the delay value, in seconds, associated with * this {@link TextComponent}, or the value of its * parent {@link Text} object if one was not assigned. * * @return the delay value for this component */ public float getDelay() { return this.delay; } }