yellowstonegames / SquidLib

Useful tools for roguelike, role-playing, strategy, and other grid-based games in Java. Feedback is welcome!
Other
454 stars 46 forks source link

[Question] What is the best way to display images from a spritesheet in SquidLib? #199

Open Rakaneth opened 6 years ago

Rakaneth commented 6 years ago

I have several tilesets I'd like to start experimenting with. What is the best way to use tilesets in .png format with SquidLib?

tommyettinger commented 6 years ago

That's a good question... Personally I haven't used sprites much with squidlib's text-based display, since I prefer using only text or only graphics. I'm guessing you want to mix text-based sections with a tileset. There are ways to add images to a SquidPanel specifically (which also is used by SquidLayers), or to any GUI component by placing an Image Actor wherever you want. You may want to look at IconsTest.java. It renders images from a TextureAtlas and mixes a distance field font with special icon assets that also use a distance field effect. I'm not sure, but I don't think the images like the icons need that effect to be usable with such a font, as long as the images you supply don't have partial transparency (distance field shaders, at least for SDF fonts or images, interpret that as information for smoothing). A fair warning is that I haven't looked at IconsTest too deeply in a while, so it may use outdated techniques for handling various things (for instance, I use GreasedRegion a lot in more recent code, but the class hasn't been around as long as some demos). There's also ImageSquidPanel, which is tested in ImageLayersTest.java, but has hardly been used at all. It may be what you're looking for.

As for what I have used more with sprites and parts of SquidLib, I use squidlib-util and libGDX in my wargame project, ColorGuard. I don't use the text-based display module (the one just called squidlib) because the graphics are isometric and don't make sense to mix with grids of text. That project uses libGDX's 2D graphics code to draw the maps and military units on that map, but the maps are largely generated by squidlib-util, and any random or data structure code is likely to involve squidlib-util. In that case, I also wrote a hefty C# project to produce the art for that and some other games how I wanted it, so I had total control over the art that would be used. That allowed me to do some fancy palette swapping with a shader, effectively making about 200 palettes (8 different uniform and paint colors, about 25 hair/skin color combinations for each) from one specially colored set of sprites in this very large image. That image may be colorless, but the variations in lightness are interpreted by a shader to mean different parts of a palette, where the palette can be swapped around between sprites.

While a roguelike could definitely use similar palette swapping (red dragon vs. blue dragon, etc.), the main thing to take away is that all the sprites are split up individually with as much space as they should have around them in-game, then they are all passed in a folder to a texture packer ( https://github.com/libgdx/libgdx/wiki/Texture-packer is a vital link) and put together into (ideally) one png image that contains all the sprites, plus a second file that contains the positions and names for each sprite so they can be looked up. This acts like a sprite sheet with lookup by-name, and you can use a sprite sheet with libGDX (TextureRegion I think has a split() method for getting TextureRegions from a rectangular-grid sprite sheet), but using a texture packer to make a texture atlas can allow packing more original images onto one all-together image, as well as images with different sizes.

This includes the images used by BitmapFonts; in the bottom left of the very large ColorGuard image, there's the font that game uses, which the .fnt file associated with that font image knows where to find. Unfortunately, most of the fonts that have had attention paid to them in SquidLib are distance field fonts (either SDF or the newer MSDF). MSDF won't work at all with other art unless you switch the shader from the MSDF shader to the normal SpriteBatch shader and back when you want to show fonts. I'm not sure, but SDF (stretchable fonts in DefaultResources) may work as long as the pixel art sprites don't have partial transparency, though the sprites won't stretch smoothly like the fonts can. You could pack a font's png image into a texture atlas (not a grid-like spritesheet) and keep the .fnt font description next to that atlas and its image(s), like I do in ColorGuard: https://github.com/tommyettinger/ColorGuard/blob/master/assets/NanoOKExtended.fnt . This would let the font be drawn at the same time as the sprites in the atlas, which helps performance. Unfortunately most of the stretchable fonts are very large (at least 1024x1024), though if a subset of chars was all that was needed, they could be much smaller. If you can pack a font image in with the rest of the sprites, that could be optimal and only need one large all-together image to hold all of the game's graphics. If this is not meant to scale, you could use a normal BitmapFont without an SDF effect; you can make one of these with Hiero if you set the renderer right (I think FreeType or Native will render fixed-width fonts correctly, but the one that allows effects will not).

Sorry if this is just a wall of text, but I'm not totally sure what the plan is here. I may be able to investigate ImageSquidPanel and other solutions and see how they can be improved once I know how people would want to use them.