Skip to content

Tutorial) 3. Spritesheets

Bryce "BtheDestroyer" Dixon edited this page Mar 21, 2017 · 5 revisions

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.

3.0. Importing an Image

For the rest of this tutorial, I will be using this image as my spritesheet:

Link 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 pngs, jpegs, or bmps. 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.

3.1 Alternative: Converting to Use with SF2D

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.

Gimp Export

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;
}

3.2. Rendering a Spritesheet

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.

3.3. Changing the background

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.

3.4. Splashscreen

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;
}

Splashscreen on launch Link on green background Moving Link using the D-Pad