-
Notifications
You must be signed in to change notification settings - Fork 1
Tutorial) 3. Spritesheets
Note: This tutorial is specifically geared towards beginners who have little to no programming experience. Because of this, a lot of simple stuff will be explained. These explanations will become more scarce as the tutorial goes on as every section expects the reader to have read everything prior to it, so repetition is not needed.
For the rest of this tutorial, I will be using this image as my spritesheet:
Note: If your image is too small, there may be an issue when you try to use it (ie: crash your program). It is suggested that you use images at least 128x128 pixels in size.
Note: I would suggest you give your individual frames in your spritesheet a 1 pixel border on each side them as right now, images with odd dimensions (ie: 13x9) will have their sizes rounded up to the nearest round number (ie: 14x10).
Place your images in the /data/
folder as png
s, jpeg
s, or bmp
s. Now we can load those images into our program as shown below:
#include <3ds.h>
#include <spritetools.h>
#include <link_overworld_png.h>
int main(void)
{
ST_Init();
st_spritesheet *link_o_s = ST_SpritesheetCreateSpritesheetPNG(link_overworld_png);
ST_Fini();
return 0;
}
This is the method that will be used in the rest of the tutorial. If you prefer the traditional SF2D method of loading from a C file, follow step 3.1 below.
Before we can use an image as a spritesheet with sf2d, we need to convert it into a C file. To do this, open your image using the program Gimp and click File
>Export As...
and change the extension to a .c
file using the settings shown below. It's recommended that the file name and the prefixed name are the same and required that they both contain no spaces.
Now open your new c file using a text editor and remove the static
from the first line of code.
Before:
static const struct {
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
unsigned char pixel_data[286 * 104 * 4 + 1];
} link_overworld = {
After:
const struct {
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
unsigned char pixel_data[286 * 104 * 4 + 1];
} link_overworld = {
Now save the file and place it in /source/spritesheets/
in your project's folder. We can load it into a spritesheet with the line extern const st_image IMAGE;
before our main
function (change IMAGE
to whatever the prefix name is from 3.0).
extern const st_image link_overworld;
int main(void)
Now we can take this image and make a spritesheet using the function ST_SpritesheetCreateSpritesheet(const unsigned char *pixel_data, unsigned int width, unsigned int height)
. It's important to know that this returns a pointer to an allocated section of memory, meaning your spritesheets must be freed before you finish SpriteTools using ST_SpritesheetFreeSpritesheet(st_spritesheet *spritesheet)
int main(void)
{
/* ...Code... */
st_spritesheet *link_o_s = ST_SpritesheetCreateSpritesheet(link_overworld.pixel_data, link_overworld.width, link_overworld.height);
while (aptMainLoop())
{
/* ...Code... */
}
ST_SpritesheetFreeSpritesheet(link_o_s);
ST_Fini();
return 0;
}
To use sprites in our program, we'll need to remove everything that prints to the top screen. To make this easier, here's what your program should look like when you start:
#include <3ds.h>
#include <spritetools.h>
#include <stdio.h>
int main(void)
{
int linkX = 50;
int linkY = 50;
ST_Init();
ST_DebugSetOn();
ST_DebugAddVar("Link X",(void *)&linkX, INT);
ST_DebugAddVar("Link Y",(void *)&linkY, INT);
consoleInit(GFX_BOTTOM, NULL);
while (aptMainLoop())
{
ST_InputScan();
if (ST_InputButtonDown(KEY_DUP))
linkY--;
if (ST_InputButtonDown(KEY_DDOWN))
linkY++;
if (ST_InputButtonDown(KEY_DLEFT))
linkX--;
if (ST_InputButtonDown(KEY_DRIGHT))
linkX++;
if (ST_InputButtonPressed(KEY_START))
break;
ST_DebugDisplay();
}
ST_Fini();
return 0;
}
First, we'll include our image file. In my case, I'm using link_overworld.png
in the /data/
folder.
#include <3ds.h>
#include <spritetools.h>
#include <stdio.h>
#include <link_overworld_png.h>
int main(void)
Now let's start and end the frame in the while
loop using ST_RenderStartFrame(gfxScreen_t screen)
and ST_RenderEndRender()
.
while (aptMainLoop())
{
ST_RenderStartFrame(GFX_TOP);
/* ...Code... */
ST_RenderEndRender();
}
Between these, we can now render some sprites in our spritesheet between these two functions using the following functions:
Function | Description |
---|---|
ST_RenderSpritesheetPosition(st_spritesheet *spritesheet, int x, int y) |
Draw the entire spritesheet at the given position |
ST_RenderSpritesheet(st_spritesheet *spritesheet) |
Draw the entire spritesheet at the given 0, 0 |
ST_RenderSpritePosition(st_spritesheet *spritesheet, unsigned int xleft, unsigned int ytop, unsigned int width, unsigned int height, int x, int y) |
Draws a sprite at a given position |
ST_RenderSprite(st_spritesheet *spritesheet, unsigned int xleft, unsigned int ytop, unsigned int width, unsigned int height) |
Draws a sprite at a 0,0 |
ST_RenderSpritePositionScale(st_spritesheet *spritesheet, unsigned int xleft, unsigned int ytop, unsigned int width, unsigned int height, int x, int y, double scale) |
Draws a scaled sprite at a given position |
ST_RenderSpritePositionRotate(st_spritesheet *spritesheet, unsigned int xleft, unsigned int ytop, unsigned int width, unsigned int height, int x, int y, double rotate) |
Draws a rotated sprite at a given position |
ST_RenderSpritePositionScaleRotate(st_spritesheet *spritesheet, unsigned int xleft, unsigned int ytop, unsigned int width, unsigned int height, int x, int y, double scale, double rotate) |
Draws a scaled and rotated sprite at a given position |
ST_RenderSpriteAdvanced(st_spritesheet *spritesheet, unsigned int xleft, unsigned int ytop, unsigned int width, unsigned int height, int x, int y, double scale, double rotate, u8 red, u8 green, u8 blue, u8 alpha); |
Draws a scaled, rotated, and blended sprite at a given position |
To keep it simple, I'll use ST_RenderSpritePosition(link_o_s, 4, 2, 18, 24, linkX, linkY);
to draw the frame of Link standing south at the given position.
Let's also change the background using ST_RenderSetBackground(u8 red, u8 green, u8 blue)
before the while
loop. My background will be a grass color #82E111
so my line is ST_RenderSetBackground(0x82, 0xE1, 0x11);
.
If you wanted to get the background in an RGBA8 format, you can use the function ST_RenderGetBackground()
which returns a u64.
Finally, we can throw in a "Made with SpriteTools" splashscreen after initializing using ST_Splashscreen(u64 time)
It takes 510 ms for the splashscreen to fade in and out, so I'll use 2510 as my time so it fades in, displays for 2 seconds, then fades out.
Our final main.c
file should look like this:
#include <3ds.h>
#include <spritetools.h>
#include <stdio.h>
#include <link_overworld_png.h>
int main(void)
{
int linkX = 50;
int linkY = 50;
ST_Init();
ST_Splashscreen(2510);
ST_DebugSetOn();
ST_DebugAddVar("Link X",(void *)&linkX, INT);
ST_DebugAddVar("Link Y",(void *)&linkY, INT);
consoleInit(GFX_BOTTOM, NULL);
st_spritesheet *link_o_s = ST_SpritesheetCreateSpritesheetPNG(link_overworld_png);
ST_RenderSetBackground(0x82, 0xE1, 0x11);
while (aptMainLoop())
{
ST_RenderStartFrame(GFX_TOP);
ST_InputScan();
if (ST_InputButtonDown(KEY_DUP))
linkY--;
if (ST_InputButtonDown(KEY_DDOWN))
linkY++;
if (ST_InputButtonDown(KEY_DLEFT))
linkX--;
if (ST_InputButtonDown(KEY_DRIGHT))
linkX++;
if (ST_InputButtonPressed(KEY_START))
break;
ST_RenderSpritePosition(link_o_s, 4, 2, 18, 24, linkX, linkY);
ST_DebugDisplay();
ST_RenderEndRender();
}
ST_SpritesheetFreeSpritesheet(link_o_s);
ST_Fini();
return 0;
}
New to SpriteTools? Start here!