Skip to content

Tutorial) 7. Cameras

Bryce "BtheDestroyer" Dixon edited this page Mar 21, 2017 · 2 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.

7.0. Starting with Cameras

When you start this section of the tutorial, you should already know how to create and use spritesheets, frames, animations, entities, and the debugger. Make sure you understand everything in this code, as you should start with it for this section:

#include <3ds.h>
#include <spritetools.h>
#include <stdio.h>
#include <link_overworld_png.h>

int main(void)
{
  ST_Init();
  ST_Splashscreen(2510);
  consoleInit(GFX_BOTTOM, NULL);

  st_spritesheet *link_o_s = ST_SpritesheetCreateSpritesheetPNG(link_overworld_png);
  st_entity *link_o_e = ST_EntityCreateEntity(50, 50, 8);

  ST_EntityAddAnimation(link_o_e,
    ST_AnimationCreateAnimation(0, 0, 1,
      ST_AnimationCreateFrameOffset(link_o_s, 4, 2, 18, 24, 0, 12)),
    "standing south");
  ST_EntityAddAnimation(link_o_e,
    ST_AnimationCreateAnimation(0, 0, 1,
      ST_AnimationCreateFrameOffset(link_o_s, 3, 29, 17, 23, 1, 11)),
    "standing east");
  ST_EntityAddAnimation(link_o_e,
    ST_AnimationCreateAnimation(0, 0, 1,
      ST_AnimationCreateFrameOffset(link_o_s, 4, 56, 18, 23, 0, 10)),
    "standing north");
  ST_EntityAddAnimation(link_o_e,
    ST_AnimationCreateAnimation(0, 0, 1,
      ST_AnimationCreateFrameOffset(link_o_s, 6, 81, 17, 23, -1, 11)),
    "standing west");
  ST_EntityAddAnimation(link_o_e,
    ST_AnimationCreateAnimation(4, 0, 10,
      ST_AnimationCreateFrameOffset(link_o_s, 30, 2, 18, 24, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 56, 1, 18, 25, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 82, 0, 18, 26, 0, 13),
      ST_AnimationCreateFrameOffset(link_o_s, 108, 0, 18, 26, 0, 13),
      ST_AnimationCreateFrameOffset(link_o_s, 134, 1, 18, 25, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 160, 2, 18, 24, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 186, 1, 18, 25, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 212, 0, 18, 26, 0, 13),
      ST_AnimationCreateFrameOffset(link_o_s, 238, 0, 18, 26, 0, 13),
      ST_AnimationCreateFrameOffset(link_o_s, 264, 1, 18, 25, 0, 12)),
    "walking south");
  ST_EntityAddAnimation(link_o_e,
    ST_AnimationCreateAnimation(4, 0, 10,
      ST_AnimationCreateFrameOffset(link_o_s, 26, 29, 21, 23, 3, 11),
      ST_AnimationCreateFrameOffset(link_o_s, 53, 29, 20, 23, 2, 11),
      ST_AnimationCreateFrameOffset(link_o_s, 81, 27, 20, 25, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 106, 27, 20, 25, 1, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 131, 28, 20, 24, 2, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 156, 29, 20, 23, 3, 11),
      ST_AnimationCreateFrameOffset(link_o_s, 183, 29, 19, 23, 3, 11),
      ST_AnimationCreateFrameOffset(link_o_s, 211, 27, 19, 25, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 236, 27, 19, 25, 1, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 261, 28, 20, 24, 2, 12)),
    "walking east");
  ST_EntityAddAnimation(link_o_e,
    ST_AnimationCreateAnimation(4, 0, 10,
      ST_AnimationCreateFrameOffset(link_o_s, 30, 55, 18, 24, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 56, 55, 18, 23, 0, 11),
      ST_AnimationCreateFrameOffset(link_o_s, 82, 53, 18, 25, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 108, 53, 18, 25, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 134, 54, 18, 24, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 160, 55, 18, 23, 0, 11),
      ST_AnimationCreateFrameOffset(link_o_s, 186, 54, 18, 24, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 212, 53, 18, 25, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 238, 53, 18, 25, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 264, 54, 18, 24, 0, 12)),
    "walking north");
  ST_EntityAddAnimation(link_o_e,
    ST_AnimationCreateAnimation(4, 0, 10,
      ST_AnimationCreateFrameOffset(link_o_s, 31, 81, 21, 23, -3, 11),
      ST_AnimationCreateFrameOffset(link_o_s, 57, 81, 20, 23, -2, 11),
      ST_AnimationCreateFrameOffset(link_o_s, 81, 79, 20, 25, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 108, 79, 20, 25, -1, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 135, 80, 20, 24, -2, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 161, 81, 21, 23, -3, 11),
      ST_AnimationCreateFrameOffset(link_o_s, 188, 81, 19, 23, -3, 11),
      ST_AnimationCreateFrameOffset(link_o_s, 212, 79, 19, 25, 0, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 239, 79, 19, 25, -1, 12),
      ST_AnimationCreateFrameOffset(link_o_s, 265, 80, 20, 24, -2, 12)),
    "walking west");

  ST_RenderSetBackground(0x82, 0xE1, 0x11);
  while (aptMainLoop())
  {
    ST_RenderStartFrame(GFX_TOP);
    ST_InputScan();

    if (ST_InputButtonPressed(KEY_START))
      break;

    if (ST_InputButtonDown(KEY_DLEFT))
    {
      ST_EntityModifyXPosition(link_o_e, -1);
      ST_EntitySetDirection(link_o_e, "west");
    }
    if (ST_InputButtonDown(KEY_DRIGHT))
    {
      ST_EntityModifyXPosition(link_o_e, 1);
      ST_EntitySetDirection(link_o_e, "east");
    }
    if (ST_InputButtonDown(KEY_DUP))
    {
      ST_EntityModifyYPosition(link_o_e, -1);
      ST_EntitySetDirection(link_o_e, "north");
    }
    if (ST_InputButtonDown(KEY_DDOWN))
    {
      ST_EntityModifyYPosition(link_o_e, 1);
      ST_EntitySetDirection(link_o_e, "south");
    }
    sprintf(tempstr, "standing %s", link_o_e->dir);
    ST_EntitySetAnimationName(link_o_e, tempstr);
    ST_RenderEntity(link_o_e);

    if (ST_InputButtonPressed(KEY_SELECT))
    {
      if(ST_DebugGet())
        ST_DebugSetOff();
      else
        ST_DebugSetOn();
    }
    if (ST_InputButtonDown(KEY_DUP) && ST_InputButtonDown(KEY_L))
      ST_DebugScrollUp(1);
    if (ST_InputButtonDown(KEY_DDOWN) && ST_InputButtonDown(KEY_L))
      ST_DebugScrollDown(1);
    ST_DebugDisplay();

    ST_RenderEndRender();
  }

  ST_SpritesheetFreeSpritesheet(link_o_s);

  ST_Fini();

  return 0;
}

6.1. Creating a Camera

First, we need to create an entity using the function ST_CameraCreate(double x, double y) and free it at the end of our program before freeing our spritesheet with the function ST_CameraFree(st_camera *cam).

int main(void)
{
  /* ...Code... */
  st_camera *my_cam = ST_CameraCreate(0, 0);
  while (aptMainLoop())
  {
    /* ...Code... */
  }
  ST_CameraFree(my_cam);
  /* ...Code... */
}

Now let's give our camera some properties like rotation and zoom:

#include <math.h>
/* ...Code... */
st_camera *my_cam = ST_CameraCreate(0, 0);
ST_CameraRotateSet(my_cam, M_PI / 4); // Set rotation to 45 degrees
ST_CameraZoomSet(my_cam, 1.5); // Set zoom to 1.5x
/* ...Code... */

6.2. Rendering with a Camera

With a camera, we can render entities with it using ST_RenderEntityCamera(st_entity *entity, st_camera *cam) instead of `ST_RenderEntity(st_entity *entity). The difference between rendering entities with and without a camera is that by using a camera, we can modify all of the entities positions, rotations, and scales at the same time by modifying the camera they're being rendered with.

/* ...Code... */
st_spritesheet *link_o_s = ST_SpritesheetCreateSpritesheetPNG(link_overworld_png);
st_entity *link_o_e = ST_EntityCreateEntity(50, 50, 8);
/* ...Code... */
st_camera *my_cam = ST_CameraCreate(0, 0);

while (aptMainLoop())
{
  /* ...Code... */
  ST_RenderEntityCamera(link_o_e, cam);
  /* ...Code... */
}
ST_CameraFree(my_cam);
ST_EntityFreeEntity(link_o_e);
ST_SpritesheetFreeSpritesheet(link_o_s);
/* ...Code... */

6.3. Following Entities with Cameras

6.4. Advanced Entity Rendering

You can also use the following functions to modify how an entity is rendered:

Function Description
ST_EntitySetXPosition(st_entity *entity, s64 x) Sets the entity's X position to the given value
ST_EntitySetYPosition(st_entity *entity, s64 y) Sets the entity's Y position to the given value
ST_EntitySetPosition(st_entity *entity, s64 x, s64 y) Sets the entity's position to the given values
ST_EntitySetScale(st_entity *entity, double scale) Sets the entity's scale to the given value
ST_EntitySetRotation(st_entity *entity, double rotation) Sets the entity's rotation to the given value
ST_EntitySetRed(st_entity *entity, u8 red) Sets the red of an entity's blending color
ST_EntitySetGreen(st_entity *entity, u8 green) Sets the green of an entity's blending color
ST_EntitySetBlue(st_entity *entity, u8 blue) Sets the blue of an entity's blending color
ST_EntitySetAlpha(st_entity *entity, u8 alpha) Sets the alpha of an entity's blending color
ST_EntitySetColor(st_entity *entity, u8 red, u8 green, u8 blue, u8 alpha) Sets the values of an entity's blending color
ST_EntitySetDirection(st_entity *entity, char *dir) Sets the entity's direction by name ie: "west", "south", "north east"
ST_EntitySetDirectionId(st_entity *entity, u8 dir) Sets the entity's direction by id ie: 0 for "east", 3 for "south west", 6 for "north"
ST_EntitySetAnimationName(st_entity *entity, char *name) Sets the entity's current animation by name (if the animation exists)
ST_EntitySetAnimationId(st_entity *entity, u8 id) Sets the entity's current animation by id (if the animation exists)
Function Description
ST_EntityModifyXPosition(st_entity *entity, s64 x) Adds the given value to the entity's x position
ST_EntityModifyYPosition(st_entity *entity, s64 y) Adds the given value to the entity's y position
ST_EntityModifyPosition(st_entity *entity, s64 x, s64 y) Adds the given values to the entity's position values
ST_EntityModifyScale(st_entity *entity, double scale) Adds the given value to the entity's scale
ST_EntityModifyRotation(st_entity *entity, double rotation) Adds the given value to the entity's rotation
ST_EntityModifyRotationNoWrap(st_entity *entity, double rotation) Same as above, but will not wrap past 0 or 2*pi
ST_EntityModifyRed(st_entity *entity, u8 red) Adds the given value to the red of an entity's blending color
ST_EntityModifyRedNoWrap(st_entity *entity, u8 red) Same as above, but will not wrap past 0 or 255
ST_EntityModifyGreen(st_entity *entity, u8 green) Adds the given value to the green of an entity's blending color
ST_EntityModifyGreenNoWrap(st_entity *entity, u8 green) Same as above, but will not wrap past 0 or 255
ST_EntityModifyBlue(st_entity *entity, u8 blue) Adds the given value to the blue of an entity's blending color
ST_EntityModifyBlueNoWrap(st_entity *entity, u8 blue) Same as above, but will not wrap past 0 or 255
ST_EntityModifyAlpha(st_entity *entity, u8 alpha) Adds the given value to the alpha of an entity's blending color
ST_EntityModifyAlphaNoWrap(st_entity *entity, u8 alpha) Same as above, but will not wrap past 0 or 255
ST_EntityModifyColor(st_entity *entity, u8 red, u8 green, u8 blue, u8 alpha) Adds the given values to the values of an entity's blending color
ST_EntityModifyColorNoWrap(st_entity *entity, u8 red, u8 green, u8 blue, u8 alpha) Same as above, but will not wrap past 0 or 255
ST_EntityModifyDirection(st_entity *entity, s8 dir) Modifies the entity's direction by the given value. Positive turns right, negative turns left