Nintendo DS


Introduction


Version History

Day 1
Environment Setup

Links

WiFiMe

PA_Lib

Linux

Emulators

Downloads

Demos




NDS Magic Key MK2/MK3

   Hosted by
FrogNet


Document made with Nvu

 

Nintendo DS Development Tutorial :: Day 9 :: BGs & Sprites #3

 

Today's tutorial will be a continuance of Day 6 and Day 7 (and I highly recommend you go back over them before going any further).  We will cover parallax scrolling again; this time it will be a vertical scroll (from top to bottom) rather than horizontal, a very commonly used technique in space or jet fighter-type games.  At the same time, we'll also take a look at one way to animate a sprite.  It will differ from Day 6, though, because the sprite has four frames of animation that change every few VBLs, regardless of user input.

One other thing that you should be aware of, if you are not already, is that I am not very good at creating graphics to be used in these demos.  I am constantly on the lookout for free sprites and textures and for today's tutorial I came across a couple of really neat sites.

Reiner's Tilesets - this is where the spaceship sprite came from

Absolute Background Textures Archive - this is where I got two of the space backgrounds

NOTE: On 09/08/2005, PA_Lib 0.50a was released.  It now comes with functions for parallax scrolling.  This tutorial has been updated to reflect the new functions.

 

// Includes
#include <PA9.h> // Include for PA_Lib
// Graphics Includes
// *** Backgrounds ***
// gfx2gba -fsrc -m -pBackgrounds.pal -t8 BG*.bmp
#include "gfx/BG1.map.c"
#include "gfx/BG1.raw.c"
#include "gfx/BG2.map.c"
#include "gfx/BG2.raw.c"
#include "gfx/BG3.map.c"
#include "gfx/BG3.raw.c"
#include "gfx/Backgrounds.pal.c"
// *** Sprites ***
// gfx2gba -D -fsrc -pSprites.pal -t8 Cloud.bmp
#include "gfx/SpaceShipAnim.raw.c"
#include "gfx/Sprites.pal.c"

// Global Variables
u8 Curr_Frame = 0; // Used to animate the spaceship
s16 Ship_X = 96; // Spaceship's X coordinate
s16 Ship_Y = 128; // Spaceship's Y coordinate
u32 vbl_count = 0; // Used to keep track of VBLs
s16 scroll = 0; // Amount of parallax scroll

// Function Prototypes
void Scroll_Backgrounds();
void Update_Sprite_Location();
void Update_Sprite_Frame();


// Function: main()
int main(int argc, char ** argv)
{
PA_Init(); // Initializes PA_Lib
PA_InitVBL(); // Initializes a standard VBL

//PA_LoadSplash(); // PA_Lib splash screen

// Load Palettes
PA_LoadPal(PAL_BG0, Backgrounds_Palette); // Backgrounds
PA_LoadPal(PAL_BG1, Backgrounds_Palette); // Backgrounds
PA_LoadPal(PAL_SPRITE0, Sprites_Palette); // Sprites

// Load Backgrounds
PA_LoadSimpleBg(0, 3, BG3_Tiles, BG3_Map, BG_256X256, 0, 1);
PA_LoadSimpleBg(0, 2, BG2_Tiles, BG2_Map, BG_256X256, 0, 1);
PA_LoadSimpleBg(0, 1, BG1_Tiles, BG1_Map, BG_256X256, 0, 1);
PA_LoadSimpleBg(1, 3, BG3_Tiles, BG3_Map, BG_256X256, 0, 1);
PA_LoadSimpleBg(1, 2, BG2_Tiles, BG2_Map, BG_256X256, 0, 1);
PA_LoadSimpleBg(1, 1, BG1_Tiles, BG1_Map, BG_256X256, 0, 1);

// Setup vertical parallax scrolling for backgrounds
PA_InitParallaxY(0, 0, 256, 192, 128);
PA_InitParallaxY(1, 0, 256, 192, 128);

// Load Sprite
PA_CreateSpriteEx(0,0,(void*)&SpaceShipAnim_Bitmap[4096*Curr_Frame],
OBJ_SIZE_64X64,1,0,0,0,0,0,1,0,Ship_X,Ship_Y);

// Infinite loop to keep the program running
while (1)
{
++vbl_count; // Increase VBL Counter

Scroll_Backgrounds(); // Parallax scroll BGs
Update_Sprite_Location(); // Move sprite based on input

// Change the sprite frame every 3 VBLs
if (vbl_count%3==0) Update_Sprite_Frame();

PA_WaitForVBL();
}

return 0;
} // End of main()


void Scroll_Backgrounds()
{
// Increment scroll amount
(scroll < 512) ? ++scroll : scroll=0;

// Vertically scroll backgrounds
PA_ParallaxScrollY(0, -scroll);
PA_ParallaxScrollY(1, -scroll);

return;
} // End of Scroll_Backgrounds()


void Update_Sprite_Frame()
{
// Increment the current frame counter
(Curr_Frame < 3) ? ++Curr_Frame : Curr_Frame = 0;

// Update sprite graphics
PA_UpdateSpriteGfx(0,0,(void*)&SpaceShipAnim_Bitmap[4096*Curr_Frame]);

return;
} // End of Update_Sprite_Frame()


void Update_Sprite_Location()
{
// Check for button press
PA_UpdatePad();

// Move sprite based on input
if ((Ship_X >= -8) && Pad.Held.Left) Ship_X -= 2;
if ((Ship_X <= 200) && Pad.Held.Right) Ship_X += 2;
if ((Ship_Y >= -8) && Pad.Held.Up) Ship_Y -= 2;
if ((Ship_Y <= 130) && Pad.Held.Down) Ship_Y +=2;

// Update Sprite Position
PA_SetSpriteXY(0,0,Ship_X,Ship_Y);

return;
} // End of Update_Sprite_Location()

 

Code Explanation

Pretty much everything up to the while() statement should be familiar, or should make sense without explanation.  There are a few things to note, however.  

First, I decided to use the same backgrounds images on both screens.  If you look carefully enough, you'll realize that the backgrounds you see on both screens are exactly the same - even the parallax scrolling effect.

Second, in Day 6's tutorial, I was able to use a standard 256x256 background with only 256x192 viewable pixels.  Why?  Because that is how big the Nintendo DS' screen is and there are no extra pixels on the left or right side of the image to worry about when scrolling horizontally.  For today's tutorial, I chose to use the full 256x256 pixels for each background.  Why?  Because when you scroll an image vertically, there is that extra space at the bottom that is normally not used (and pink in color in my examples).  Take a look at the bitmaps included with any of the previous tutorials if you don't know what I mean.  You could probably figure out a way to do vertical scrolling with 256x192 viewable pixels, but this way is so easy, why bother?

if (vbl_count%3==0) Update_Sprite_Frame();
Let me explain this just in case you are not familiar with the modulus operator.  % means the remainder when dividing.  So, this statement means when vbl_count divided by 3 has no remainder, or every three VBLs.

You'll notice that I broke the main parts of today's code into three functions.  As I mentioned in Day 6, this makes looking at code - and figuring it out - much easier.

Scroll_Backgrounds()
This code is very similar to what was done in Day 7.  In fact, I simply copied and pasted that code here and made only a few changes.  The main difference is that I am using a negative number for the scrolling so that the backgrounds would scroll from top to bottom.  If you used positive numbers, they would scroll from bottom to top instead - which is totally weird for a spaceship game!

Update_Sprite_Frame()
(Curr_Frame < 3) ? ++Curr_Frame : Curr_Frame = 0;
If you take a look at SpaceShipAnim.bmp, you'll see that it consists of four frames of a spaceship image that all look very similar.  In fact, the only difference you'll see is the lights on the front of the wings and the flames at the back of the ship.  That's okay, though, because there is just enough difference to show you how to animate a sprite.  Oh, and the frame counter goes from 0 to 3 and gets multiplied by 4096 (64x64 pixels) just like in Day 6.

You'll notice that this function gets called every 3 VBLs.  If you call it any more often, the sprite animations get so fast that you can hardly notice them.

Update_Sprite_Location()
Again, this is almost exactly the same as Day 6 except that I threw a bunch of weird numbers in the if statements.  The spaceship sprite does not take up a full 64x64 pixels, so I had to increase the allowable bounds for moving the ship around the screen.  For example, there are about 8 pixels on the left and right-hand side of the ship that are not viewable so the X coordinate can actually be allowed to move from -8 to 200.

Well, that's about it for today.  Now you know how to parallax scroll backgrounds horizontally (Day 7) and vertically (Day 9) and animate sprites based on user input (Day 6) and without input (Day 9). At this point you may want to take a little break and write your own little demo.  Then you can come back and learn some other neat tricks to add to it!

 

Download

Day9_BGs_Sprites_3

 

Screenshot

Day1_Hello_World

 

Last Update: 10/31/2005

 

Google
 
Web aaronrogers.com/nintendods

 

<<

HOME

>>