Alright, here is the lesson that you all have been waiting for, Lesson 4. This lesson will show you how to create game sprite animations in your program. This lesson will show you how to animate a sprite in all directions. It can be a little bit tricky so I will try to explain everything in a simple and basic way.
We will be using the same background image from the last lesson, lesson 3. That way you can tell the difference between sprite movement from lesson 3 and sprite animation from this lesson.
Here is the background image again:
I will also post a modified source so that you can see the sprite animation with a solid PSP background color instead of a background image.
Here is the sprite sheet that we will be using for this lesson:
Take a good look at that sprite sheet we will be using. If you don't know why the background of the sprite sheet is pink, please refer to lesson 3 for an explanation of transparent colors.
Notice how there are 4 rows of sprites: one for
down movement, one for
up movement, one for
right movement and one for
left movement. Now each row also has 6 different movements for each direction plus a static sprite for when the sprite is just staying still in that direction. That makes 7 total sprites in each row.
In lesson 3, we used a sprite that has the dimension of 22x35 pixels. In this lesson, we are using the same sprite character with the same dimensions of 22x35 pixels. Notice how the total dimension of the sprite sheet is 154x140. There are 7 sprites in each row and since each sprite is 22x35, 7 times 22 = 154. There are also 4 directions that the sprite is placed on the sprite sheet. So 4 times 35 = 140. That is why the sprite sheet is 154x140 in dimension. There are a total of 32 individual sprites in the sprite sheet each with it's own dimension of 22x35 just like in lesson 3.
OK, here is the Makefile we will be using:
Code:
TARGET = Donkey_Lesson4
OBJS = main.o
INCDIR =
CFLAGS = -G4 -Wall -O2
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)
LIBDIR =
LDFLAGS =
STDLIBS= -losl -lpng -lz \
-lpspsdk -lpspctrl -lpspumd -lpsprtc -lpsppower -lpspgu -lpspaudiolib -lpspaudio -lm
LIBS=$(STDLIBS)$(YOURLIBS)
EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = Donkey_Lesson4
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak
Again, the Makefile we are using is the same standard Makefile we have always used in these lessons except for the target and eboot title name change.
Here is the source code that we will be using:
Code:
//OSlib header file
#include <oslib/oslib.h>
//Necessary to create eboot
PSP_MODULE_INFO("OSLib Sample", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU);
//declaration of the pointers of our images
OSL_IMAGE *background, *sprite;
//definitions
#define DOWN 0
#define UP 35
#define RIGHT 70
#define LEFT 105
//variables
int sprite_position;
int sprite_march;
//function declarations
void Buttons();
void SpriteAnimate();
int main()
{
//Initialization of the Oslib library
oslInit(0);
//Initialization of the graphics mode
oslInitGfx(OSL_PF_8888, 1);
//Sets the transparency color (pink)
oslSetTransparentColor(RGB(255,0,255));
//loads our images into memory
background = oslLoadImageFile("background.png", OSL_IN_RAM, OSL_PF_5551);
sprite = oslLoadImageFile("sprite.png", OSL_IN_RAM, OSL_PF_5551);
//Disables the transpaent color (pink)
oslDisableTransparentColor();
//verification that all files are present
if (!background || !sprite)
oslDebug("It is impossible to load one or more of the images that are required in this program. Please make sure you have all the files required in the eboot folder");
//Sets the sprite's original position on the screen
sprite->x = 155;
sprite->y = 95;
sprite_position = DOWN;
//main while loop
while (!osl_quit)
{
//To be able to draw on the screen
oslStartDrawing();
//calls the Buttons() function
Buttons();
//Draw the images to the screen
oslDrawImage(background);
oslDrawImage(sprite);
//Ends drawing mode
oslEndDrawing();
//Synchronizes the screen
oslSyncFrame();
}
//Terminate the program
oslEndGfx();
oslQuit();
return 0;
}
void Buttons()
{
//initiate the PSP's buttons
oslReadKeys();
if (osl_keys->held.down)
{
//Sprite movement
sprite->y += 2;
//Sets the sprite's position on the spritesheet
sprite_position = DOWN;
//Calls the SpriteAnimate() function
SpriteAnimate();
}
if (osl_keys->held.up)
{
sprite->y -= 2;
sprite_position = UP;
SpriteAnimate();
}
if (osl_keys->held.right)
{
sprite->x += 2;
sprite_position = RIGHT;
SpriteAnimate();
}
if (osl_keys->held.left)
{
sprite->x -= 2;
sprite_position = LEFT;
SpriteAnimate();
}
//If a button is not pressed
if (!osl_keys->held.value)
{
//Start the variable over for when a button is pressed again
sprite_march = 0;
//Sets the sprite's direction
oslSetImageTileSize(sprite,0,sprite_position,22,35);
}
}
void SpriteAnimate()
{
//Moves the sprite in the row that it is in
sprite_march++;
//Moves the sprite constantly
oslSetImageTileSize(sprite,(sprite_march * 22),sprite_position,22,35);
//resets the sprite movement in that row
if (sprite_march == 6) sprite_march = 0;
}
Source code explanation:
The parts of the source code that I have already explained in the previous lessons, I will not explain again. If you don't understand a part of the code that I do not explain in this lesson, then you will need to refer back to one of the previous lessons for an understanding.
1) #define DOWN 0
#define UP 35
#define RIGHT 70
#define LEFT 105
Notice on the sprite sheet that the first sprite position is the down position, second is the up position, third is the right position and fourth is the left position.
The down position starts at 0 at the very top. Since each sprite has a dimension of 22x35, 22 the X coordinate (left and right) and 35 the Y coordinate (up and down), the next position the up position would start at 35. The next position, the right position would be 35+35 which would be 70. The final position, the left position would be 35+70 which would be 105.
So every time we use these numbers, instead of getting confused with numbers, we will just define this numbers as:
DOWN,
UP,
RIGHT,
LEFT
2) void Buttons();
void SpriteAnimate();
These are simple functions that I created to make the source easier to understand. I could have created the source code with no functions but then there would be a lot of messy and repetitive code. We will put all the button usage code we need into the
Buttons() function and we will put all of the animation code into the
SpriteAnimate() function.
3) sprite->x = 155;
sprite->y = 95;
As the source says, this sets the sprites position on the screen. The sprite will be located at coordinates
(155,95) when the program first loads up.
4) sprite_position = DOWN;
This sets the position of the sprite when the program first loads. Remember, that we
#defined
DOWN to be 0. So that means the position of the sprite will be at the 0 coordinate on the sprite sheet which is the first position which is the DOWN position.
5) if (osl_keys->held.down)
{
sprite->y += 2;
sprite_position = DOWN;
SpriteAnimate();
}
This is part of the code in the
Buttons() function. That means every time you see
Buttons() (which is a function call) the program will do everything that is inside the 2 braces {} under the
Buttons() function.
Basically what these lines of code means that if the user holds down the down button, then the sprite will continue to move 2 pixels on the screen downward. That is what
y+=2 means (
y+=2 actually means
y=y+2).
y is the
y coordinate on the screen. The new value of
y will = whatever the old value of
y was + 2 more.
If you are moving the sprite
up, then it would be
y-=2 or
y=y-2. That is because if you are moving upwards, you are decreasing the
y coordinate since you are going closer to the top which the top of the screen = 0.
This is the same for left and right. For
right, you would use
x+=2 or
x=x+2. When you are moving towards the right of the screen, you are moving in a positive direction toward 480. (The PSP screen size is 480x272). If you are moving
left, you would use
x-=2 or
x=x-2. Moving left makes the sprite move toward 0.
Once you do that, then you are calling the
SpriteAnimate(); function which will do everything that is in that function before moving on.
6) if (!osl_keys->held.value)
This means that if a button is not pressed or held then do ...
When a button is held, a value of 1 (true) is stored in the memory. If no button is being pressed or help, a value a 0 (false) is stored into the memory.
7) oslSetImageTileSize(sprite,0,sprite_position,22,35 );
This one of the important parts of the code to understand. Lets take a look at that line of code with no variables.
oslSetImageTileSize (image, X, y, width, height);
image would be the image name which in our case is
sprite.
X and
y are the coordinates and
width and
height are the dimensions of each sprite. Remember that each sprite has a dimension of 22x35 so that is what our width and height is.
Now we use 0 as our
x coordinate because all of our sprite positions start from the very left side of the sprite sheet. Now for our
y coordinate, we use the variable
sprite_position to let us know whether to use 0 or 35 or 70 or 105 for the direction we want the sprite to move.
Notice in the
Button() function if the down button is pressed,
sprite_position is set to =
DOWN. And remember,
DOWN = 0 from our
#define at the beginning of our code. So if the user pressed the down button, then this is how the function would look:
oslSetImageTileSize(sprite,0,0,22,35);
It would take the
sprite at coordinates
0,0 (the very first one on the sprite sheet) with a dimension of
22x35. If the user press the up button everything would stay the same except the y coordinate would be 35 etc.
8) oslSetImageTileSize(sprite,(sprite_march * 22),sprite_position,22,35);
This is under the
SpriteAnimate() function. Again, lets take a look of this function with no variables inside:
oslSetImageTileSize (image, X, y, width, height);
Notice how everything is the exact same as the previous code I just explained except for the
x coordinate. In the previous code, the
x coordinate is 0. In this code, the
x coordinate is
(sprite_march * 22). Now in the
Buttons() function, the
sprite_march variable is set to 0. But in the
SpriteAnimate() function you see this line:
sprite_march++;
That means to increase
sprite_march by one. So now
sprite_march=1. So 1*22 =22. So that is our
x coordinate 22. Our
y coordinate is still whatever the
sprite_position is which again depends on whether the user is pressing down, up, right or left. So by pressing the DOWN button this is what you would get for this function:
oslSetImageTileSize(sprite,22,0,22,35);
Then you see this line of code:
if (sprite_march == 6) sprite_march = 0;
That means since there are 6 moving positions for each direction on the sprite sheet, once the last or 6 position is reach, restart the position back to 0. So the sprite will keep walking and when it finishes it's last sprite position for that row, it will restart the walking position all over again.
This concludes Lesson 4. I know it seems a little bit complicated but all you need to do is study the code line by line until everything clicks. I tried to explain my code as best as I could but it might take time for everyone to understand it. Once you understand this code completely, you are ready to code your own game as everything else is easy compared to this. If you still don't understand something I will try to explain it again or maybe ZingaBurga or someone else can give a better explanation of my animation code.
Here is the source code if you just want to use a plain screen filled with a solid color as your background instead of an image:
Code:
//OSlib header file
#include <oslib/oslib.h>
//Necessary to create eboot
PSP_MODULE_INFO("OSLib Sample", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU);
//declaration of the pointers of our images
OSL_IMAGE *background, *sprite;
//definitions
#define DOWN 0
#define UP 35
#define RIGHT 70
#define LEFT 105
//variables
int sprite_position;
int sprite_march;
//function declarations
void Buttons();
void SpriteAnimate();
int main()
{
//Initialization of the Oslib library
oslInit(0);
//Initialization of the graphics mode
oslInitGfx(OSL_PF_8888, 1);
//Sets the transparency color (pink)
oslSetTransparentColor(RGB(255,0,255));
//loads our image into memory
sprite = oslLoadImageFile("sprite.png", OSL_IN_RAM, OSL_PF_5551);
//Disables the transpaent color (pink)
oslDisableTransparentColor();
//verification that all files are present
if (!sprite)
oslDebug("It is impossible to load one or more of the images that are required in this program. Please make sure you have all the files required in the eboot folder");
//Sets the sprite's original position on the screen
sprite->x = 155;
sprite->y = 95;
sprite_position = DOWN;
//main while loop
while (!osl_quit)
{
//To be able to draw on the screen
oslStartDrawing();
//calls the Buttons() function
Buttons();
//Draws a green background for the PSP
oslDrawGradientRect(0,0,480,272,RGB(0,128,0),RGB(0,128,0), RGB(128,255,128), RGB(128,255,128));
//Draw the images to the screen
oslDrawImage(sprite);
//Ends drawing mode
oslEndDrawing();
//Synchronizes the screen
oslSyncFrame();
}
//Terminate the program
oslEndGfx();
oslQuit();
return 0;
}
void Buttons()
{
//initiate the PSP's buttons
oslReadKeys();
if (osl_keys->held.down)
{
//Sprite movement
sprite->y += 2;
//Sets the sprite's position on the spritesheet
sprite_position = DOWN;
//Calls the SpriteAnimate() function
SpriteAnimate();
}
if (osl_keys->held.up)
{
sprite->y -= 2;
sprite_position = UP;
SpriteAnimate();
}
if (osl_keys->held.right)
{
sprite->x += 2;
sprite_position = RIGHT;
SpriteAnimate();
}
if (osl_keys->held.left)
{
sprite->x -= 2;
sprite_position = LEFT;
SpriteAnimate();
}
//If a button is not pressed
if (!osl_keys->held.value)
{
//Start the variable over for when a button is pressed again
sprite_march = 0;
//Sets the sprite's direction
oslSetImageTileSize(sprite,0,sprite_position,22,35);
}
}
void SpriteAnimate()
{
//Moves the sprite in the row that it is in
sprite_march++;
//Moves the sprite constantly with no static position
oslSetImageTileSize(sprite,(sprite_march * 22),sprite_position,22,35);
//resets the sprite movement in that row
if (sprite_march == 6) sprite_march = 0;
}
Here is the link to download all the necessary files and a precompiled EBOOT and source code for this lesson.
http://www.mediafire.com/?4q3nazhkgwq
In the next lesson, I will show you how to load background music and use sound effects in your game.