Day 13 - Starting a platform game ← Previous
Carré Rouge is a javascript game which I find pretty cool :p Check it out over here :
French Version English Version
What this tutorial will do is show you how to make a similar game on Nintendo DS, from start to finish... We’ll do this in a few steps :
The functions we’ll use in this part are new at all... We’ll already used the MoveSprite before, as well as seen how to check collisions between 2 rectangles...
I decided to cut down this first demo into lots of functions, and so we’ll see the program one bit at a time :
// PAGfxConverter Include #include "gfx/all_gfx.c" #include "gfx/all_gfx.h" #define MAXBLUE 4 // number of blue ones... typedef struct{ s16 x, y; // position in pixels s32 fx, fy; // Position in fixed point s32 vx, vy; // speed... s16 w, h; // HALF width and HALF height, because that's what we'll use... } rectangle; rectangle blue[MAXBLUE]; // MAXBLUE possible rectangles, we'll probably use less rectangle red; // Our rectangle...
Nothing special here... We add the graphics (basic graphics...), and have a macro defined for the number of blue rectangles we want... Why ? Because that way we can change the number of rectangles, and everything that goes with it, by editing just 1 line, and not replacing the number all over the place...
Then comes the structure we’ll use for the rectangles.
Now, one might ask why we have both fixed point and normal positions... That to avoid having to do »8 all the time, nothing more, nothing less... We’ll just need to do it once per frame to update x and y, and then we’ll use x and y to check if it bounces on a wall or collides...
rectangle blue[MAXBLUE]; is the blue rectangles array... How many are there ? MAXBLUE ! If you change the 4 at the top by 5, it’ll change the array’s size automatically... nice !
We use that structure for our main sprite too...
On we go to the function declarations :
// Blue rectangle inits void Blue16x32(u8 number); void Blue32x16(u8 number); void Blue32x32(u8 number); void MoveBlue(u8 number); // Blue rect move void CheckCollision(u8 number); // Checks if there is a collision...
The next functions to come are a little different from what we are used to :
extern inline void ToFixedPoint(u8 number){ blue[number].fx = blue[number].x <<8; blue[number].fy = blue[number].y <<8; } extern inline void ToNormal(u8 number){ blue[number].x = blue[number].fx >>8; blue[number].y = blue[number].fy >>8; }
This, time, they are declared as extern inline functions, and their code is directly written... What’s the main difference between a normal function and an inline one ? When the code is compiled, each time a function is declared inline, it is just copy/pasted into the code... This means that it can be faster, because you don’t have the waiting time while calling a given function... However, if you put all your big functions inline, it’ll copy/paste all the huge chunk of code everywhere you use it, and thus produce much bigger code. I used it here to show you how it works, and because these functions just have 2 really short lines of code...
What do these functions do ? The first one, ToFixedPoint converts the .x and .y normal position to the fixed point position, storing it in .fx and .fy... The second one, ToNormal does the opposite, copying the fixed point position into normal position in .x
Then WHY do we need to have a fixed point position, if we’ll use the normal one anyway ? Because the default rectangle speed will be given like a trajectory, which allows more directions and will allow later on to make them accelerate very slowly...
Now, here comes the main function :
int main(void){ PA_Init(); PA_InitVBL(); PA_InitText(1,0); // On the top screen PA_LoadSpritePal(0, 0, (void*)sprite0_Pal); red.x = 128; red.y = 96; red.w = 16; red.h = 16; // Half width and height... PA_CreateSprite(0, 0,(void*)red_Sprite, OBJ_SIZE_32X32,1, 0, red.x - red.w, red.y - red.h); PA_InitRand(); // We'll put some random stuff in there... s32 i; for(i = 0; i < MAXBLUE; i++){ u8 random = PA_Rand()%3; if (random == 0) Blue16x32(i); else if (random == 1) Blue32x32(i); else if (random == 2) Blue32x16(i); // Position and random angle blue[i].x = (i&1)*256; blue[i].y = (i>>1)*192; u16 angle = PA_Rand()&511; blue[i].vx = PA_Cos(angle); blue[i].vy = -PA_Sin(angle); ToFixedPoint(i); // Add the fixed point values based on the position... } while(1) { if (PA_MoveSprite(0)){ red.x = PA_MovedSprite.X; red.y = PA_MovedSprite.Y; } for (i = 0; i < MAXBLUE; i++) { MoveBlue(i); // Move all the blue rectangles... CheckCollision(i); // Check collision } PA_WaitForVBL(); } return 0; }
As you can see, the main code is pretty short... The important features are stored in different functions we’ll see...
Coming someday to a computer near you!