001package squidpony.squidgrid.gui.gdx; 002 003import com.badlogic.gdx.graphics.g2d.Batch; 004import com.badlogic.gdx.scenes.scene2d.Stage; 005import com.badlogic.gdx.utils.viewport.StretchViewport; 006import com.badlogic.gdx.utils.viewport.Viewport; 007import squidpony.squidmath.GWTRNG; 008 009/** 010 * A convenience class that groups several commonly-used GUI classes into one object and provides ways to 011 * initialize these kits for specific purposes, some of which would be a challenge to write without this code. 012 * Created by Tommy Ettinger on 8/11/2016. 013 */ 014public class StarterKit { 015 /** 016 * One of the more critical parts of rendering text is what font to use, and textFactory should usually 017 * not be reassigned during a game because so many things depend on this value or a copy of it (so the 018 * change might not affect what it was expected to, and might break other things). 019 */ 020 public TextCellFactory textFactory; 021 /** 022 * The main way to interact with a text-based grid as for roguelikes. A SquidLayers object stores a 023 * background and foreground SquidPanel, and this configures them as requested. 024 */ 025 public SparseLayers layers; 026 /** 027 * The number of grid spaces on the x axis. 028 */ 029 public int gridWidth; 030 /** 031 * The number of grid spaces on the y axis. 032 */ 033 public int gridHeight; 034 /** 035 * The width of a cell that holds one char, in "relative pixels," where the screen is expected to stretch so 036 * one relative pixel does not generally refer to one actual screen pixel (since high-DPI phones and 037 * laptops may make a single pixel virtually impossible to see with the naked eye). 038 * <br> 039 * By default, this value is doubled to make stretching look more smooth. 040 */ 041 public int cellWidth; 042 /** 043 * The height of a cell that holds one char, in "relative pixels," where the screen is expected to stretch 044 * so one relative pixel does not generally refer to one actual screen pixel (since high-DPI phones and 045 * laptops may make a single pixel virtually impossible to see with the naked eye). 046 * <br> 047 * By default, this value is doubled to make stretching look more smooth. 048 */ 049 public int cellHeight; 050 051 /** 052 * All visible parts of this class are in the Stage, and if you add additional widget or scene2d.ui Actor 053 * values to your game, they should probably be added to this Stage. 054 */ 055 public Stage stage; 056 /** 057 * Used to draw lots of things, but mostly handled internally by the Stage. 058 * You may need to call {@code batch.begin()} and {@code batch.end()} in some cases where you want to 059 * render something that isn't a child of stage but is an Actor or similar render-able object. 060 * This can apply a filter from {@link FloatFilters} (or a custom {@link FloatFilter}) to all drawn colors. 061 */ 062 public FilterBatch batch; 063 /** 064 * An important part of how this will be displayed; the viewport defaults to a displayed width of 065 * {@code cellWidth * gridWidth} and a displayed height of {@code cellHeight * gridHeight}, after cellWidth 066 * and cellHeight were doubled by default, and will be stretched or shrunk to fit the actual screen size. 067 */ 068 public Viewport viewport; 069 070 /** 071 * Almost all of SquidLib comes into contact with randomness at some point, so this is a good place to show one 072 * way of handling that randomness. GWTRNG acts as a normal implementation of {@link squidpony.squidmath.IRNG}, 073 * can be "seeded" at the start to set the initial state, like any other RNG, but it can also have the current state 074 * acquired later with {@link GWTRNG#getState()} or have the current state set in-place with 075 * {@link GWTRNG#setState(long)} (note, this doesn't create a new RNG, like you would have to do to re-seed with 076 * java.util.Random). This can be useful to get a snapshot of the random sequence where you might want to take an 077 * action, undo it back to the snapshot, and try again. It can also be useful for saving the game and reloading it 078 * exactly, though the optional serialization in squidlib-extra also does this. You can pass a GWTRNG to anything 079 * that expects an IRNG, and you'll encounter a lot of methods that employ IRNG (and some that specifically require 080 * or prefer {@link squidpony.squidmath.IStatefulRNG}, which includes GWTRNG) throughout squidlib-util. 081 * <br> 082 * This field defaults to a GWTRNG seeded with the number SQUIDLIB (written in base 36), or 2252637788195L in 083 * base 10. Its algorithm can produce 2 to the 64 minus 1 numbers before repeating, and as the name might suggest, 084 * it should perform especially well on Google Web Toolkit for HTML deployment. 085 */ 086 public GWTRNG rng = new GWTRNG(2252637788195L); 087 088 /** 089 * Constructs a StarterKit with the given width and height in cells (gridWidth and gridHeight) and the given width 090 * and height for each letter (cellWidth and cellHeight), using a default font that is about half as wide as it is 091 * tall but can stretch to other aspect ratios. 092 * @param gridWidth the width of the display area in cells 093 * @param gridHeight the height of the display area in cells 094 * @param cellWidth the width of a single cell in pixels, before any stretching is applied 095 * @param cellHeight the height of a single cell in pixels, before any stretching is applied 096 */ 097 public StarterKit(int gridWidth, int gridHeight, int cellWidth, int cellHeight) 098 { 099 this(DefaultResources.getStretchableFont(), gridWidth, gridHeight, cellWidth, cellHeight); 100 } 101 /** 102 * Constructs a StarterKit with the given width and height in cells (gridWidth and gridHeight) and the given width 103 * and height for each letter (cellWidth and cellHeight), using the given TextCellFactory for the font. You can use 104 * any of the pre-constructed TextCellFactory objects in {@link DefaultResources}, such as 105 * {@link DefaultResources#getCrispLeanFamily()}, {@link DefaultResources#getCrispDejaVuFont()}, 106 * {@link DefaultResources#getCrispSlabFamily()}, or {@link DefaultResources#getStretchableTypewriterFont()}, as 107 * long as you have the right assets available (their documentation says the exact files you need). While you can 108 * construct your own TextCellFactory given a BitmapFont, that won't work well as a distance field font unless you 109 * used some very unusual configuration making the font, so the font would only look good at one size or possibly a 110 * multiple of that size. The defaults are recommended for now; a separate project is used to make the distance 111 * field monospace fonts (<a href="https://github.com/tommyettinger/Glamer">tommyettinger/Glamer</a> on GitHub) 112 * That project also serves as storage for fonts that were made with Glamer, and appropriately-licensed fonts are 113 * added to the "premade" folder once they are converted. 114 * <br> 115 * If you don't know what font to pick, {@link DefaultResources#getCrispLeanFamily()} and 116 * {@link DefaultResources#getCrispSlabFamily()} have the same (very large) character coverage, and have bold and 117 * italic modes that can be accessed with {@link GDXMarkup} if you decide to use that later. 118 * @param textFactory the TextCellFactory to use for the font 119 * @param gridWidth the width of the display area in cells 120 * @param gridHeight the height of the display area in cells 121 * @param cellWidth the width of a single cell in pixels, before any stretching is applied 122 * @param cellHeight the height of a single cell in pixels, before any stretching is applied 123 */ 124 public StarterKit(TextCellFactory textFactory, int gridWidth, int gridHeight, int cellWidth, int cellHeight) { 125 this(textFactory, gridWidth, gridHeight, cellWidth, cellHeight, 0, 0); 126 } 127 /** 128 * Constructs a StarterKit with the given width and height in cells (gridWidth and gridHeight) and the given width 129 * and height for each letter (cellWidth and cellHeight), using the given TextCellFactory for the font; this 130 * overload also allows specifying additional space in pixels to be added to the right or bottom sides of the area 131 * with the grid of chars. You can use any of the pre-constructed TextCellFactory objects in 132 * {@link DefaultResources}, such as {@link DefaultResources#getCrispLeanFamily()} 133 * {@link DefaultResources#getCrispDejaVuFont()}, {@link DefaultResources#getCrispSlabFamily()}, or 134 * {@link DefaultResources#getStretchableTypewriterFont()}, as long as you have the right assets available (their 135 * documentation says the exact files you need). While you can construct your own TextCellFactory given a 136 * BitmapFont, that won't work well as a distance field font unless you used some very unusual configuration making 137 * the font, so the font would only look good at one size or possibly a multiple of that size. The defaults are 138 * recommended for now; a separate project is used to make the distance field monospace fonts 139 * (<a href="https://github.com/tommyettinger/Glamer">tommyettinger/Glamer</a> on GitHub). That project also serves 140 * as storage for fonts that were made with Glamer, and appropriately-licensed fonts are added to the "premade" 141 * folder once they are converted. 142 * <br> 143 * If you don't know what font to pick, {@link DefaultResources#getCrispLeanFamily()} and 144 * {@link DefaultResources#getCrispSlabFamily()} have the same (very large) character coverage, and have bold and 145 * italic modes that can be accessed with {@link GDXMarkup} if you decide to use that later. 146 * @param textFactory the TextCellFactory to use for the font 147 * @param gridWidth the width of the display area in cells 148 * @param gridHeight the height of the display area in cells 149 * @param cellWidth the width of a single cell in pixels, before any stretching is applied 150 * @param cellHeight the height of a single cell in pixels, before any stretching is applied 151 * @param additionalWidth the width in pixels to add to the stretched area, before any stretching is applied 152 * @param additionalHeight the height in pixels to add to the stretched area, before any stretching is applied 153 */ 154 public StarterKit(TextCellFactory textFactory, int gridWidth, int gridHeight, int cellWidth, int cellHeight, 155 int additionalWidth, int additionalHeight) { 156 this.cellWidth = cellWidth; 157 this.cellHeight = cellHeight; 158 this.textFactory = textFactory == null ? DefaultResources.getCrispLeanFamily() : textFactory; 159 layers = new SparseLayers(gridWidth, gridHeight, this.cellWidth, this.cellHeight, this.textFactory); 160 this.gridWidth = gridWidth; 161 this.gridHeight = gridHeight; 162 batch = new FilterBatch(); 163 viewport = new StretchViewport(this.cellWidth * gridWidth + additionalWidth, this.cellHeight * gridHeight + additionalHeight); 164 stage = new Stage(viewport, batch); 165 stage.addActor(layers); 166 } 167 168 /** 169 * Not a complete drawing solution; so much of the logic related to drawing is specific to each game, like 170 * FOV being used to make certain things not render if they are out of sight, that this doesn't even try to 171 * guess at what a particular game needs for its rendering code. Any {@link TextCellFactory.Glyph} objects in 172 * {@link #layers} will be rendered by that SparseLayers, but any that aren't stored in layers must be drawn 173 * separately (Glyph has a {@link TextCellFactory.Glyph#draw(Batch, float)} method that must be called between 174 * {@link Batch#begin()} and {@link Batch#end()}, typically with begin() called before all Glyphs are drawn in 175 * a loop and then with end() called after). 176 * <br> 177 * Specifically, this applies the current viewport to the stage, draws the stage, and makes any actions or 178 * events related to the stage take effect. Should not be called inside a {@link FilterBatch#begin()} block, 179 * since this calls it itself by drawing the stage, and also calls {@link FilterBatch#end()} afterwards. 180 */ 181 public void draw() 182 { 183 stage.getViewport().apply(true); 184 stage.act(); 185 stage.draw(); 186 } 187 188 /** 189 * Not a complete resize method; this is meant to handle the resizing of this StarterKit only and should be 190 * called inside your main Game, ApplicationListener, etc. class' resize method. 191 * @param width the new width of the screen; should be a parameter from the other resize() method 192 * @param height the new height of the screen; should be a parameter from the other resize() method 193 */ 194 public void resize(int width, int height) { 195 viewport.update(width, height, true); 196 } 197 198}