Libwiisprite/tutorial
Programming for Nintendo Wii with Libwiisprite.
Foreword
Programming for the Nintendo Wii with Libwiisprite, a tutorial by WiiPhlex.
There are several things users should note before proceeding any further with the tutorial. This tutorial is released on the latest release of the Libwiisprite library, 0.3.0b which you can download here -> http://chaosteil.googlepages.com/libwiisprite-0.3.0b.tar.gz.
The tutorial will be written almost entirely in C++ with the possible exception of some C standard libraries functions. I will try and point this out where applicable. Also note that it is not a C++ programming tutorial, I will assume you have some knowledge in programming with C++ before you attempt the following. If you have learned C, and wish to use this, you will need some knowledge in Classes and protection levels, for more information on both of these topics visit www.cprogramming.com . If you are completely new to programming altogether I advise that you learn how to program C++ for PC before moving onto the Nintendo Wii.
I do not guarantee the accuracy of this document, I will attempt to give all correct information, but no one is perfect, if you find an error please contact me on the one of the below ways.
I will also be referring to the Libwiisprite documentation for functions parameters and class hierarchy, and where required the source code for the functions, although if you wish to see the source code for the library you will need to contact the Author, this can be done at chaosteil@gmail.com.
If you wish to contact me, the author of this document, feel free to do so by emailing me at phlex.wii@gmail.com or sending me a pm at the wiidev forums here http://forum.wiibrew.org/. I spell words the English way, for example, initialise rather than initialize and colour instead of color. Of course if color is what a program requires I shall leave it so otherwise the program will not work as it is supposed to.
Setting up Libwiisprite for use.
If you haven’t read the foreword, read it and don’t be lazy. This will be a fairly short lesson and at this point I will assume you have downloaded the Libwiisprite. First, you need to know how to set your make file. The basic template will look something like this:
#---------------------------------------------------------------------------------
# Clear the implicit built in rules
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPPC)),)
$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=<path to>devkitPPC")
endif
include $(DEVKITPPC)/wii_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := source
DATA := data
INCLUDES :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS = -g -O2 -mrvl -Wall $(MACHDEP) $(INCLUDE) -I$(DEVKITPPC)/local/include
CXXFLAGS = $(CFLAGS)
LDFLAGS = -g $(MACHDEP) -mrvl -Wl,-Map,$(notdir $@).map
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lwiisprite -lpng -lz -lwiiuse -lbte -lfat -logc -lm
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS :=
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
#---------------------------------------------------------------------------------
# automatically build a list of object files for our project
#---------------------------------------------------------------------------------
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
export LD := $(CC)
else
export LD := $(CXX)
endif
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \
$(sFILES:.s=.o) $(SFILES:.S=.o)
#---------------------------------------------------------------------------------
# build a list of include paths
#---------------------------------------------------------------------------------
export INCLUDE := $(foreach dir,$(INCLUDES), -iquote $(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD) \
-I$(LIBOGC_INC)
#---------------------------------------------------------------------------------
# build a list of library paths
#---------------------------------------------------------------------------------
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \
-L$(LIBOGC_LIB) -L$(DEVKITPPC)/local/lib
export OUTPUT := $(CURDIR)/$(TARGET)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol
#---------------------------------------------------------------------------------
run:
psoload $(TARGET).dol
#---------------------------------------------------------------------------------
reload:
psoload -r $(TARGET).dol
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).dol: $(OUTPUT).elf
$(OUTPUT).elf: $(OFILES)
#---------------------------------------------------------------------------------
# This rule links in binary data with the .jpg extension
#---------------------------------------------------------------------------------
%.jpg.o : %.jpg
#---------------------------------------------------------------------------------
@echo $(notdir $<)
$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
(taken from the Libwiisprite template make file) If you wish to add other libraries to your project to this by editing the LIBS flag by appending the name of the library prefixed with a -. As this a Libwiisprite tutorial, I won’t go into much detail on make files, if you wish to learn more visit http://www.gnu.org/software/make/manual/make.html. In order to ‘install’ Libwiisprite, follow these steps
- Open the folder “libwiisprite-master” then open the command prompt in this folder
- Execute the commands "make clean" followed by "make"
- Execute the command "make install"
Disclaimer : You may need to install "ppc-freetype" to devkitpro in order for these commands to work. This can be done by opening Msys2, and typing the command : "pacman -S ppc-freetype"
Now you are set up to start programming.
- WiiPhlex
Setting up the Video display.
Now it is time to see some real program code! The following it taken from the Libwiisprite example template (libwiisprite\examples\template\source\template.cpp). The entire program is as follow and is the minimum to get up a screen of RGBA colour values (if you don’t understand this you will soon) and render it. The source is as follows:
#include <wiiuse/wpad.h>
#include <wiisprite.h>
// libwiisprite uses wsp as it's namespace
using namespace wsp;
int main(int argc, char **argv)
{
// Create the game window and initalise the VIDEO subsystem
GameWindow gwd;
gwd.InitVideo();
gwd.SetBackground((GXColor){ 255, 255, 255, 255 });
// Initialise Wiimote
WPAD_Init();
for(;;)
{
WPAD_ScanPads();
if(WPAD_ButtonsDown(WPAD_CHAN_0)&WPAD_BUTTON_HOME)
break;
gwd.Flush();
}
return 0;
}
Ok, so let’s look at it piece by piece. First two lines include the required header files to just get the program going. The header file is for getting input from the wiimote which at this stage will only be used to exit the program. The functions used by this file are WPAD_Init(), WPAD_ScanPads() and WPAD_Buttons_Down(), these functions are not related to Libwiisprite so I will not describe their functions, visit the wiibrew wiki for more information on the Wiimote. The second header file, wiisprite.h, this is a fairly short file that’s main purpose is to include all the other files, yep, all this file does is add gamewindow.h, layermanager.h, layer.h, image.h, sprite.h, tiledlayer.h, and finally quad.h. Now this isn’t the best practice in programming as you should only include the files that your program will actually require, but for now don’t worry about this. Other than including the rest of the library, it defines two macros for correcting the wii pointer location to (200, 250). The next line of importance that you must note is
using namespace wsp;
most people use std namespace a lot and may be wondering what wsp could mean, if you don’t know about namespaces I won’t tell you here as it is related to C++ programming, if you wish to learn about namespaces visit one of the many C++ programming sites. All of the Libwiisprite classes work in the wsp namespace, so this little declaration saves us typing the namespace followed by scope resolution operators followed by more tedious typing that we can’t be bothered doing. Now that we have all of our classes included into our program, we need to be able to use them. For the purpose we will just use one of these classes, GameWindow. We create an instance of the GameWindow in the main loop called gwd. The first function we call from the GameWindow class is InitVideo(), the Libwiisprite documentation defines the InitVideo function as follows
void wsp::GameWindow::InitVideo ( ) Initializes the whole video subsystem. Should be the first command called with the library.
As you can see, this function takes care of a whole lot of dirty work that we avoid by calling a single function and not even passing it anything! Thank heavens for such a function . The next function however, is not so simple and is called as such:
gwd.SetBackground((GXColor){ 255, 255, 255, 255 });
Again, this is part of the GameWindow class and is defined in the documentation like this:
void wsp::GameWindow::SetBackground ( GXColor bgcolor ) Sets the background clear color Parameters: bgcolor is a GXColor containing r, g, b and a.
At this point I will explain a little about colour displays. Now I’ll assume you understand that a 800x600 display means 800 dots horizontally and 600 dots vertically, if you didn’t you do now. The tricky part about a colour display is depth. The first thing to know is that he number of bits in a colour display determines how much video card memory each pixel on the screen consumes. For example, 16 bits is 2 bytes, so each pixel of a 16 bit colour display requires 2 bytes of memory. So if your program is set to an 800x600 display resolution with 16 bit colour, your video card requires 800x600x2 bytes of memory or a total of 960,000 bytes of memory. If the same display uses 32-bit colour, the video card memory is 1,920,000 bytes or twice that required by a 16 bit scenario. For the purpose of this document, colours on the screen are red, green and blue. These are called RGB colour modes. One of the simplest display modes to understand is 24-bit colour which uses 3 bytes for each pixel. One byte represents the red intensity, on represents green and the other blue. Because a byte of memory can hold a value from 0 to 255, each of these three colour elements can be set to one of 256 intensities (the 0 is counted as being an intensity there for 1 + 255 is 256). So, a 24 bit colour may look like this (255, 0, 0), this would be full intensity red with no green and no blue, (0, 255, 0) would be no red, ‘full’ green and no blue, and of course, blue would be (0, 0, 255), every other colour falls between (0, 0, 0) which is black and (255, 255, 255) which is white. Now that you know about 24-bit displays, forget them, computers hate working in odd numbered bytes and so does Libwiisprite. All of your programs will (or at least should be) in 32 bit colour. This adds an extra byte to the colour. This extra byte is called the Alpha value and determines the opacity or transparency of a pixel. So for example let’s look at red, in a 24 bit display it would be (255, 0, 0), full red, no green and no blue. Now by default, this has an alpha value of 255, in other words it has no transparent value at all, so if we were to convert that to get the same effect in 32 bit colour, we would write it as follows, (255, 0, 0, 255). Now you can see there’s a fourth component added, that is the alpha value. If we wanted our colour to be completely transparent we would change the last value to 0. Now you’re thinking, how does all of this relate to my wee program. Now that you understand about a 32 bit colour display, take a look at the last line I showed you, in case you forgot:
gwd.SetBackground((GXColor){ 255, 255, 255, 255 });
Now take a look at those numbers! Wo0t they make sense! This will set the background colour to full red, green, blue and alpha which will be a solid, white screen (if all goes well behind the scenes). For now, ignore the GXColor type and bask in your understanding of what a few numbers do, of course if you have done graphics programming before you will likely have known this already. Also, If you are used to programming in a more popular say Direc3D or OpenGL you will likely have had to input these as a float value between 0.0f and 1.0f. Also, you will often see 0xFF and 0x00, these are hexadecimal values, 0xFF base 16 for 255 and 0x00 is base 16 for 0. You won’t always need this function if you, say, print an entire image to your background that covers everything, but be aware, if you print an image to the screen then call this you may have unexpected consequences. After this function has done its work, control returns to the main function and WPAD_Init() is called, does its thing then goes back to the main function. Then the main function gets to the for loop. You may be wondering what for(;;) does, basically it says for no value and no expression do, in other words, its’ an infinite loop. I would do it differently but it’s easier to stick with the example. Upon entering the loop 2 more ‘wiiMote’ related functions are called, and ask if the user is pressing the home button, if so break the loop, return 0 and exit the program. If however the user isn’t pressing the home button, the program executes the Flush() function, another function found in the GameWindow class we used at the start of the program. This function is defined as follows in the documentation
void Flush () Finishes rendering.
Not a huge amount of information I know, and I am not allowed to release the source for I’ll explain what it does. It copy’s the back buffer to the front buffer, waits for the vertical synchronisation then renders the image to the screen and deletes the back buffer, ready for a new image to be produced (even though it will look the same all the time in our small program here). There are a few other functions in the GameVideo class that may be of use. The first I will mention is StopVideo(), the documentation defines it like this:
void StopVideo () Shuts the video subsystem down. It won't work if Video wasn't initialized before.
Again, not much info, but it doesn’t require much information to understand, this shuts down the Video systems on the Wii, it’s kind of the opposite of InitWii(), this leads me on to my second function, IsInitialized() defined in the documentation as such:
static bool wsp::GameWindow::IsInitialized ( ) [static] Checks if the video subsystem is already initialized. Returns: true if initialized, false if not.
You may be wondering why this function would be of any use. Once you have large programs, you may be starting and stopping your video setup with the first function I mentioned and InitVideo(), so you may also want to check if you have your Wii initialised and if it isn’t then call the InitVideo() function, such code may look like this:
If ( ! IsInitialized())
{
InitVideo()
}
There’s another two functions that you may want to use, and they are GetWidth() and GetHeight. They get the width and height of the current screen. A possible application of this is to make sure your character doesn’t go beyond the edge of the screen, or where to draw your background or where to print your menu so that its centred. That’s it for this lesson, I would advise you play around with the numbers in the SetBackground() function if you still don’t see how they work, playing with numbers can teach you an awful lot. Also, try and replace the wiisprite.h with the only header(s) that are required for this program.
- WiiPhlex
Loading and printing images.
This lesson will deal largely with the Image class and Layer class, simply include Image.h and Layer.h in your programs. The first thing we need to know is that there are two LoadImage() functions the first:
IMG_LOAD_ERROR LoadImage (const char *path, IMG_LOAD_TYPE loadtype=IMG_LOAD_TYPE_PATH)
and
IMG_LOAD_ERROR LoadImage (const unsigned char *path, IMG_LOAD_TYPE loadtype=IMG_LOAD_TYPE_BUFFER)
Here’s a quote from the author of Libwiisprite: “There are some situations however, where you want to load from a buffer. Say, you have a very small application you just want to run very fast. Or maybe you have your own package system where you can extract each file with its own buffer. Anyway, you will need a way to load an image directly, and not through the filesystem.” I will go over both methods of loading an image. So let’s look more closely at the first function.
IMG_LOAD_ERROR wsp::Image::LoadImage ( const char * path, IMG_LOAD_TYPE loadtype = IMG_LOAD_TYPE_PATH )
Loads an image from a file. Width and height have to be a multiple of 4, or it won't load. Once an Image is initialized, it can't be initialized again. Uses fopen(), so some basic filesystem initialization is required.
Parameters: path The path to the file. loadtype Set this to how you want to load this image. (This is probably a path) Returns: An error code based on loading status.
Before you can load your image, you need to create an instance of the a class that will allow you to use your image or sprite in the way you wish, for example, for a static background (I refer to static to mean a still image not a member that exists for an entire class) you may consider using the Image class, but if you wanted to create a sprite you would use the Sprite class. I will be using snippets from Libwiisprite/examples/spritetest and explaining the code from that, I cannot add all of the code as one file contains raw data for an image which is 545 lines long. If you want to see this file it is Libwiisprite/examples/spritetest/source/libwiisprite.cpp. Open the source file at Libwiisprite/examples/spritetest/source/spritetest.cpp. The first line of interest to us is this
Sprite sprite; // The drawable object we can modify.
This creates a sprite object of type Sprite, this is probably the most flexable class for manipulating an image, although you should use it in conjunction with the Image class, this will be shown in the following example. But remember that if you don’t should select your classes dependant on what you actually need, not just you can select a certain type. Continuing on now, we see another four declarations of various class types, the only ones we are concerned with are
Sprite sprite2; // Another drawable object we can modify.
Image image; // Holds our image/texture from the SD Card.
Image image2; // Holds our buffer image/texture.
At this point don’t worry why there are declarations of the same things twice in small example, basically, it’s to show you how to load an object of type Sprite from the buffer as well as from file and the same goes for the two images of type Image. Skip a few lines and go to
// Initialize filesystem to load from SD Card
fatInitDefault();
This function is included in fat.h and is called as #include <fat.h>, this is for file management and makes it easier and safer to handle files from the SD card, unless you know what you are doing with file handling and even if you do, it’s always a good idea to include this. Now we shall move down a little further and skip a few things along the way until we reach this wee section of code here:
if(image.LoadImage("libwiisprite.png") != IMG_LOAD_ERROR_NONE)exit(0);
This function is one of the ones that reads from the SD card. If the image isn’t at found at the location specified in the quotation marks, the function will return false and the program will automatically exit, otherwise it will return an address in memory where the image has been loaded and assign a value to our Image object, image. The next line is very similar but differs substantially in the details:
if(image2.LoadImage(libwiisprite) != IMG_LOAD_ERROR_NONE)exit(0);
libwiisprite (the one between the bracts in the above line) is defined in libwiisprite as a huge, fat array of constant, unsigned char’s. It’s been generated so that it can be loaded directly into memory on runtime which is what happens as soon as the program sees this chunky piece of code. So the above code segment attempts to find it in memory, if the image isn’t in memory, the program will exit, otherwise the value of libwiisprite is assigned to image2, and has been loaded from the buffer rather than the SD card. Easy! Next we make use of our two sprite objects, sprite and sprite2 (imaginative names aren’t they?), with these two lines:
sprite.SetImage(&image);
sprite2.SetImage(&image2);
To properly understand what’s going on we are going to have a look at how the documentation defines the SetImage() function, just have to love the documentation don’t you!
void wsp::Sprite::SetImage ( Image * image, u32 frameWidth = 0, u32 frameHeight = 0 )
Assigns this sprite to an image. If there is already an image with the same size, no data gets changed.
Parameters: image The image for this sprite. frameWidth The width of the frame. Should be a multiple of image->GetWidth() or 0 if it should get the same width as the image. frameHeight The height of the frame. Should be a multiple of image->GetHeight() or 0 if it should get the same height as the image.
At this stage, we are only using the first parameter and ignoring the second two. After consulting the source code for this function, it will work fine with no parameters, it will set them to 0 if no other is there. What we have done with our two images is pass the address of the images using the address of operator (&), then the function will handle the image for us the rest of the way. Now we have an image loaded into our sprite with all the abilities of the Image class as well as the Sprite class. Next line of interest is this one
sprite.SetPosition(0, 0);
Again we shall now look at the documents definition of the SetPosition() function in case you can’t guess what those 2 parameters represent.
void wsp::Layer::SetPosition ( f32 x, f32 y ) Changes the absolute position of the layer on the viewport. Parameters: x The new X position. y The new Y position.
Simple enough, takes as parameters 2 values, x then y coordinates. This is the simplest way of going about this. At this stage you should know about screen coordinates. This system uses 2D coordinates with x running horizontally and y running vertically. Here’s an example from the documentation of what the system looks like.
Coordinates:
.------------> X (640, horizontal) | | | Coordinate system starts at (0;0). | | V Y (480, vertical)
It’s just a 2D coordinate system with an inverted vertical (or y) axis. With the origin (0,0) at the top left hand corner, x increases moving right of the screen and y increases moving down. A note on depth and z is that in computers it usually increases going into the screen and decreases coming out. The reason that the coordinate system works this way is because of the way that the back buffer prints to the front buffer (front buffer is a fancy name for screen), it starts printing from the top left corner at (0,0) then moves one pixel across the x axis to (1,0). Once a top line has been rendered to the front buffer, it will start printing at the next line and do it all over again until the entire image is drawn. This happens so fast that you can’t actually see each pixel being drawn. So when we use this call:
sprite.SetPosition(0, 0);
We are setting its location to print the top left corner of the image to top left corner of the screen. This is commonly used when printing backgrounds to cover the entire screen regardless of screen size/resolution. The next print call we encounter is as follows:
sprite2.SetPosition(320, 240);
That’s it for this lesson now that you know how to load an image from the buffer or from the SD card and print them to the screen. One thing to note is that your images resolution must be a multiple of four otherwise your program will not be happy with you, in the next we will look at some more interesting stuff, specifically, manipulating images using Libwiisprite for more interesting effects.
- WiiPhlex
Basic Image Manipulation
I will still use spritetest.cpp for the purpose of this lesson. Now that we have a couple of images loaded and on screen, we want to be able to play around with them. There are several functions in Libwiisprite that allow you to manipulate images in various ways. Specifically, we will look at transformations to our images through SetStretchHeight(), SetStretchWidth, SetZoom and SetTransparency as well as a few other ‘Get’ functions. We will start this lesson at line 99 and 100 of spritetest.cpp
if(pressed & WPAD_BUTTON_MINUS)
sprite.SetZoom(sprite.GetZoom()-0.1f);
Ignore the first line for now, the second contains 2 very easy to use functions for getting and setting zoom values. Before I continue have a quick look at the definition for each of these functions:
void wsp::Sprite::SetZoom ( f32 zoom ) Sets the zooming of the sprite. It resets any defined stretch values. Parameters: zoom The new zoom of the sprite. 1 is normal size, cannot be smaller than 0.
CURRENT ZOOM CANNOT BE SMALLER THAN 0! Make sure you go by this rule, to make sure that your images zoom level never goes below 0 you may add a simple check like this:
if(pressed & WPAD_BUTTON_MINUS && sprite.GetZoom() > 0)
sprite.SetZoom(sprite.GetZoom()-0.1f);
This simply checks sprites zoom using the GetZoom() function defined like this:
f32 wsp::Sprite::GetZoom ( ) const Gets the zooming of the sprite. If StretchWidth is not the same as StretchHeight, it returns 0. Returns: The current zoom of the sprite. 1 is normal size.
This will return a float value which is being applied to the current image to scale using some formula we don’t need to worry about (thanks Libwiisprite!). So the expression
if(pressed & WPAD_BUTTON_MINUS && sprite.GetZoom() > 0)
Will be true if the user is pressing the minus button and the Zoom factor for sprite is greater than 0. Note, don’t set the sprite.GetZoom() expression to >= 0, otherwise, if = sprites zoom factor == 0 then it will decrease it further, not something we want to do as this would put it in the negatives, who knows what horrible consequences this may have! So now we understand GetZoom, what about SetZoom? Well, again this is another very easy function to use, one parameter of type float. In our example it’s called like this:
sprite.SetZoom(sprite.GetZoom()-0.1f);
if the player is pressing the minus button then this line of code executes, it will use GetZoom() to return the current zoom factor, then decreases it by a value of 0.1. So say for example that the current zoom factor is 1, the native resolution of the image, then in plain English, the expression would look like this: “set sprites zoom factor to 1 – 0.1 which equals 0.9, then multiply the images native resolution by this”. That’s simple enough in my opinion, that you should now be able to understand the next two lines in the program:
if(pressed & WPAD_BUTTON_PLUS)
sprite.SetZoom(sprite.GetZoom()+0.1f);
Just in case you aren’t sure what this does, it checks to see if the user is pressing the plus button and if this evaluates to true, then sprites zoom factor is increased by 0.1. You may be wondering why there’s and f after the increase value, this is just how most programs accept a float value, if you’ve done much graphics programming you will used to setting verticies, materials, colours, alpha values and all manner of things as a value with f at the end. Now we will move onto the next few lines of interest;
if(pressed & WPAD_BUTTON_A && sprite.GetTransparency() < 0xff-4)
sprite.SetTransparency(sprite.GetTransparency()+5);
if(pressed & WPAD_BUTTON_B && sprite.GetTransparency() > 4){
sprite.SetTransparency(sprite.GetTransparency()-5);
In many ways this is similar to the lines we just looked at, except that it changes the value of the images transparency, I will refer to transparency as alpha from now on as its the more ‘correct’ term and far easier to type. Now for a short lesson in alpha. Alpha determines the overall opacity of the pixel, usually a value from 0 to 255 (just like the RGB, it use a byte of memory to hold it) or in many API’s, a float value from 0.0f to 1.0f, we will use the first mode for this example. If the alpha is set to full (255) then the surface is fully opaque, or ‘solid’, whereas, if the alpha value is set to 0 the surface is completely transparent, clear, invisible, any number of words could describe this. When you load an image, usually it will have an alpha value of 255 unless specified differently in the image data itself. Now we will have a look at the SetTransparency() function:
void wsp::Sprite::SetTransparency ( u8 alpha ) Sets the transparency of the sprite. Parameters: alpha Sets the transparency. Has a range from 0x00 (invisible) to 0xFF (fully visible)
The values 0x00 and 0xFF are hexadecimal or more commonly called ‘hex’, this is how most of your image will be handled although the functions are just as happy to work with decimal as shown in the code segment at the start of the Transparency section. In our example, 0x00 is the same as 0 (no alpha, and 0xFF is 255 (fully opaque). Now let’s look again at that code segment
if(pressed & WPAD_BUTTON_A && sprite.GetTransparency() < 0xff-4)
sprite.SetTransparency(sprite.GetTransparency()+5);
if(pressed & WPAD_BUTTON_B && sprite.GetTransparency() > 4){
sprite.SetTransparency(sprite.GetTransparency()-5);
Line one will see if the user is pressing A first of all. The next part is a little trickier to understand, lets look at it in small sections at a time to see exactly what is happening.
sprite.GetTransparency() < 0xff-4
GetTransparency() is the alpha equivalent to GetZoom(), it is defined as such:
u8 wsp::Sprite::GetTransparency ( ) const Gets the transparency of the sprite. Returns: The current transparency of the sprite. Has a range from 0x00 (invisible) to 0xFF (fully visible)
So now we know what GetTransparency() does (if you didn’t know before), then it will compare that value to 0xFF – 4 (think of it as being 255 – 4 = 251). To put this into an equation, we will assume that the native alpha value of the image is 255, or 0xFF:
If the player is pressing A AND 255 is less than 251, execute the next statement.
Say the user was pressing A, that will result the first part of the expression to true, however, the alpha of the image must also be less than 251 in order to do this, as shown in the above example, it is fairly obvious that 255 is not less than 251, therefore the expression will return false and you aren’t able to increase the alpha anymore, after all how can you make something more solid than solid? Now we are going to look another example where the images alpha is less than 0xFF – 4, let’s say the alpha value of the image is equal to 100, and A is being pressed, because 100 is less than 251 and A is being pressed the if statement is true, so the program executes this line of code:
sprite.SetTransparency(sprite.GetTransparency()+5);
This will call SetTransparency() and pass it the current alpha and increase it by a value of 5. The next two lines of code are more or less the same but the user must be pressing B and the images alpha must be greater than 4, if so then it will call SetTransparency() to decrease the current alpha by a value of 5. The reason that the alpha must be greater than (but not and equal to) is so that if the alpha value is equal to 5 and it calls the SetTransparency() function then the current alpha value will be 0, if it were 0 and you were able to decreases the alpha value further you would have negative values (obviously) which won’t go down well with the program at all! Always make sure you have checks to stop values going below thresholds, the program will almost never do this for you so you must code your applications, games etc carefully to avoid these things. That’s four functions down, let’s move onto the next two Get and Set functions.
if(pressed & WPAD_BUTTON_UP)
sprite2.SetStretchHeight(sprite2.GetStretchHeight()+0.1f);
if(pressed & WPAD_BUTTON_DOWN)
sprite2.SetStretchHeight(sprite2.GetStretchHeight()-0.1f);
This works in the same way as the other Get and Set functions, but these adjust the Height of the images. First the program asks if the player is pressing up, if he/she is, then sprite2’s images height will be increased by a scale factor of its current Height + 0.1, again a float value, Here are the two Get and Set functions for height:
void wsp::Sprite::SetStretchHeight ( f32 stretchHeight ) Sets the height stretch of the sprite. Parameters: stretchHeight Stretches the height of the sprite by this value. 1 is normal size, cannot be smaller than 0. f32 wsp::Sprite::GetStretchHeight ( ) const Gets the height stretch of the sprite. Is equal to zoom vallue if zoom was set. Returns: The current height stretch of the sprite. 1 is normal size.
Again don’t let the stretch factor go below 0, a check similar to the one I showed with zoom will fix the problem here. GetStretchHeight() will return the current height stretch factor, when an image is loaded this value is 1 and all other values are based on that. The second two lines do pretty much the same thing again except it requires input of down from the wiimote and decreases the stretch height. Next two functions...
if(pressed & WPAD_BUTTON_RIGHT)
sprite2.SetStretchWidth(sprite2.GetStretchWidth()+0.1f);
if(pressed & WPAD_BUTTON_LEFT)
sprite2.SetStretchWidth(sprite2.GetStretchWidth()-0.1f);
same as its preceding functions although this changes the Width instead, hence the function GetStretchWidth() and SetStretchWidth(). Now we have those functions out of the way we shall move down the loop to a new line:
sprite.Move(-((f32)sprite.GetWidth()/2), -((f32)sprite.GetHeight()/2));
The Move() function is defined as follows in the documentation:
void wsp::Layer::Move ( f32 deltaX, f32 deltaY )
Moves the layer some units. Parameters: deltaX Moves the layer a specific amount of units to the left/right. deltaY Moves the layer a specific amount of units up/down.
This function is found in the Layer class, so if you wish to use this function be sure to include Layer.h in your program. First thing first, delta, if you don’t know what this is it simply means ‘the change in’, it’s often used in physics calculations and its mathematical symbol is Δ. So ΔY means the change in Y and ΔX is the change in the value of X. These X and Y values are Cartesian coordinates. The function takes two parameters, a value of type f32 that is for the x and another for y. So the line
sprite.Move(-((f32)sprite.GetWidth()/2), -((f32)sprite.GetHeight()/2));
calculates -((f32)sprite.GetWidth()/2), in other words, the inverse of the width of sprite divided by 2, and the second line does the same thing but uses GetHeight() instead of GetWidth(). This is a particularly useful function if you want to, well, move your images around, look at your average 2D side scroller, everything moves in some or other way, the character, the enemy’s, and of course the background. Say you wanted to make your image move right when you press the right button and move it left when you pressed the left button, your code might look something like this:
if(pressed & WPAD_BUTTON_RIGHT)
sprite.Move( 1, 0 );
if (pressed & WPAD_BUTTON_LEFT)
sprite.Move(-1, 0 );
In the first pair of lines, a check is done to see if the player is pressing the right button, if this results to be true, then sprite.Move() is called. I assign the first parameter which is the x value to change, 1, and the second parameter which is the y value, to 0. I set the second to 0 so that the image stays at the same height, after all we only want it to move along the x axis. You can do the same for the y axis by putting in something like this:
if(pressed & WPAD_BUTTON_UP)
sprite.Move( 0, -1 );
if (pressed & WPAD_BUTTON_DOWN)
sprite.Move(0, 1 );
This moves the image up the screen if you press up and down if you press down, remember that the y axis increases as you move down, therefore to move up you must decreases the current y value of the image. The last function that we will look at in detail is the SetRotate() function:
void wsp::Sprite::SetRotation ( f32 rotation ) Sets the rotation angle of the sprite. Parameters: rotation The new angle of the sprite. It is measured in degrees/2, so if 90 degrees is wanted, 45 degrees should be the passed
parameter.
In the program the following line of code is called.
sprite.SetRotation(ir.angle/2);
Ignore ir.angle , it’s to do with the an abbreviation for infa red and is in the ir_t structure. SetRotate() is another easy function to use, just pass the number of degrees you want and divide by two or if you know how much you want to do, calculate the value then pass it before a build. For example, if we wanted to turn it 90 degrees (as shown in the parameter documentation) we could either do it like this:
sprite.SetRotation(90/2);
or if we only needed to do it once and not get the degrees on the run we could do the calculation before hand to get the result passed to the function to save out program using up a couple of cycles to do it, like this:
sprite.SetRotation(45);
A more flexable method again is to have a variable called degrees (or whatever you want to call it), and the value of degrees depends on some input, say the angle of the wiimote then call the function like this:
Sprite.SetRotate(degrees/2);
You can also get the current rotation by calling the GetRotation() function which is defined as follows:
f32 wsp::Sprite::GetRotation ( ) const Gets the rotation angle of the sprite. Returns: The current angle of the sprite.
Returns a value of type f32 by default this is 0 when the image is loaded unless specified otherwise. Now we are almost at the end of the program, the last two functions that are called are these:
manager.Draw(0, 0);
gwd.Flush();
These two functions require the inclusion LayerManager.h and GameWindow.h as well as an instance of the classes. The first of these two functions, Draw() is used to determine off set and the second one does the rest of the rendering work but don’t worry about these too much I’ll explain them later, so that’s it for this lesson, a long lesson with lots of handy functions that are easy to use. Till next time,
- WiiPhlex
Layer Management.
Layers are a key element to using the Libwiisprite effectively and efficiently. They decide what you see, where you see it and everything in between. I’ll still by using the trusty file, spritetest.cpp by taking examples from it and how they work. First thing we need to use layers is to include LayerManager.h, this is done in our program by including libwiisprite.h, which if you remember includes everything else in the library. Now look further down the source at line 42;
LayerManager manager(3);
This is the first call in the program to LayerManager, this creates an instance of LayerManager called manager and calls its constructer and passes 3 to it. This means that we now have a limit of 3 layers for this layer manager. What the constructer does is create an array of (in this case) 3 elements of type Layer. So it will look something like this (note its only and abstraction to make it easier to understand what it looks like in memory):
elements 0 1 2 [null][null][null]
This is not a dynamic array, it is fixed on run time to the value you pass to the constructor so make sure you change the number to whatever is relevant to your program. The documentation defines it as;
wsp::LayerManager::LayerManager ( u32 boundary ) Constructor. Parameters: boundary Specifies how many layers can be grouped into this manager.
Ok, so now we have a layer manager set up, how do we use it? Let’s take a look at the source code
manager.Append(&sprite);
The append function is in the LayerManager class and is defined as such:
void wsp::LayerManager::Append ( Layer * layer ) Appends a layer at the end, thus drawing it at last. Parameters: layer The layer to append. If it is already in the list, it gets removed first.
This function takes one parameter and that’s the address of a layer object. Some things to note about our manager object, it is essentially an array, thinking about it in this manner will help you understand layers much easier. Now with this in mind let’s look at that line again:
manager.Append(&sprite);
Append as you should know means ‘add at the end’, and when you think in terms of an array, it would add at the lastlocation + 1. Currently our manager has no elements, so passing the address of sprite to Append() will add it to the element 0 as arrays begin a 0 not 1. So now our manager will look like this:
elements 0 1 2 [sprite][null][null]
The next line:
manager.Append(&sprite2);
Appends another object to the manager, this time its sprite2, now to update our manager it will look like this
elements 0 1 2 [sprite][sprite2][null]
Now 2 of our elements ( 0 and 1 ) have objects in them, simple enough so far, now I introduce to you the Insert() function found in the LayerManager class:
void wsp::LayerManager::Insert ( Layer * layer, u32 index ) Inserts a layer into the manager. Parameters: layer The layer to insert. If it is already in the list, it gets removed first. index The new index of the layer. Can't be bigger than GetSize().
Very similar to the Append() function, but this lets you add objects to your manager where ever you want. And that’s what we do with the next line:
manager.Insert(&quad, 0);
Just like with the Append function, it requires the address of an object to add to the list, but as well as this it requires the element, where you want to insert. In the above it adds at the element 0, which is the first. Inserting here will increment the element number of each element that is greater than that of the inserted layer, if your list is full and you add something at the start, the last layer will be deleted. Here’s a visual representation of Inserting a layer to a full list:
elements 0 1 2 List is full [object1][object2][object3]
Calling: manager.Insert(object4, 0);
elements 0 1 2 [object4][object1][object2] -> object3 is lost in memory. NOT GOOD!!
To avoid losing objects in memory add a check to make sure that there is an empty, or null, element in the node, if there isn’t and you still wish to add an object delete one of the elements and Insert the object where required. Back to our program now, after calling this line:
manager.Insert(&quad, 0);
our manager will look like this:
elements 0 1 2 [quad][sprite][sprite2]
Pretty slick isn’t it? Simple as that! Now you’re saying why on earth did I do all of that? Well simply put, this will now dictate what is drawn when. You may recall at the end of the previous lesson I gave you a very quick bit of information about this line:
manager.Draw(0, 0);
well now we are going to understand exactly what this function does. For your reference it is found at lines 130 and 137 in spritetest.cpp, the function is defined:
void wsp::LayerManager::Draw ( s32 x, s32 y ) const Draws all the layers in this LayerManager. Parameters: x The X offset for drawing. y The Y offset for drawing.
For the most part, you will simply leave the parameters as 0, 0 for simplicity’s sake, although it’s important to understand exactly what they are. The first parameter determines how far along the x axis the back buffer should start drawing to the front and the second relates to where the frame starts being printed on the y axis, this may be a negative value. Now you may be wondering why you would do this, an example, (just an example mind) is in say a side scroller, while there are lots of bombs dropping on the map, the screen shakes wildly around to give a better cinematic effect from the bombs exploding than just the usual still screen. At this point you would generate an image on the back buffer slightly larger than the screen and plug a formula into both of those parameters that would change the offset to make it look like a shuddering screen. another example is simply moving a menu from one side to the other like, say the iPhone, and you could fade it while it goes, then the next screen could slide in and fade in. These are just random babblings by me, feel free to use this function how you want, but most of the time you will call it as 0, 0. Now to apply what you have learned about the LayerManager class to this function. What happens when you call this function, is that the array acts sort of like a z buffer, the object at element 0 will be printed first, and in the case of our list, this is quad, this servers as a background, so it would make sense to print it at the back, next, element 1 is printed. This is out sprite object. Because of the way that this draws on the back buffer, every pixel that sprite is on will completely overwrite the ones that were behind it, in this case, where ever sprite is. But that’s supposed to happen so don’t worry, it will update every frame so your quad/background or whatever will remain intact waiting to be rendered next time. The Draw() function iterates through your manager until it has printed all of the images onto the buffer and created its nice image. That finishes all the calls for Manager in this application so then Flush() finishes the rendering and prints everything to the screen for you to admire. I would still like to explain the other functions in the LayerManager class that weren’t used in spritetest. The first of these functions is Remove().
void wsp::LayerManager::Remove ( Layer * layer ) Removes a layer from the list. Parameters: layer A layer that is in the list.
Say we have our manager set up like this:
elements 0 1 2 [object1][object2][object3]
Then we call Remove() like this: manager.Remove(&object1); Now our list will look like this:
elements 0 1 2 [null][object2][object3]
You may insert an object at element 0 as the function checks if the element is null or not. Simple enough to understand, the function requires the address of the object to remove. Next function on my list is RemoveAll():
void wsp::LayerManager::RemoveAll ( ) Clears the whole LayerManager from all Layers.
Deletes everything in the current list, example of a call would look like this:
manager.RemoveAll()
Requires no parameters.
On we go! Next function is GetSize:
u32 wsp::LayerManager::GetSize ( ) const Returns the size of the list of layers. Returns: The size of the current layerlist.
A useful check to perform when Inserting and appending layers is to check where you are inserting against object.GetSize, this will make sure you don’t go and accidently lose things in memory and get memory access violation errors cropping up with possible system crashes! Next function is GetLayerAt(). I won’t post the documentations definition as I will only briefly cover how to use it. Example of how it works: Say we have our list set up like this:
elements 0 1 2 [object1][object2][object3] 000000 000001 000002 - example memory addresses
Now a call to GetLayerAt():
manager.GetLayerAt(1);
What this does is return the address at the specified element, in this case, we have passed 1 to the function. Then the function declares a variable and assigns the value passed to it. It then iterates through the layer until the value passed == the element your at and returns the address. So in the case of out example here, it would return 000001. If we passed 2 to GetLayerAt() then we would get 000002 (note these addresses are somewhat made up by me, completely). There’s only one other function in the LayerManager class and that is SetViewWindow(), I won’t go over this yet though as it can be rather daunting (by Libwiistandards). Until then...
- WiiPhlex
Quad.
In case you live under a rock, quad means four, in graphics programming, a quad typically means a shape with four sides. It’s very handy having the ability to create a quad on the fly and fortunately, Libwiisprite gives us a class that handles GX to create and manipulate a quad. This class, is simply called, Quad. To include it in your programs you must include either libwiisprite.h or Quad.h. For the basics of Quad, I will again refer to spritetest.cpp in examples. The first line we will look at is line 25.
Quad quad;
Here we create an instance of Quad called quad that we can now use in our program, but there’s still some more work to do before we can print it to the screen! Move further down the code till you get to this section:
quad.SetPosition(-40, -40);
quad.SetWidth(800);
quad.SetHeight(600);
We encountered SetPosition() in chapter 3, so I won’t go over its function again. So instead we shall look at SetWidth() and SetHeight, they are both simple functions here is the definition:
void wsp::Quad::SetWidth ( u32 width )
Sets the width of the quad.
Parameters:
width The new width of the quad.
void wsp::Quad::SetHeight ( u32 height )
Seets the height of the quad.
Parameters:
height The new height of the quad.
Both of these functions need to be called before Draw() for a Quad object. Each of these takes as a parameter one number of type u32, this determines the pixels height and width, you can change this later in your game or app if you need to. So looking at this:
quad.SetWidth(800);
quad.SetHeight(600);
we can see this sets quad’s height to 600 pixels and quad’s width to 800. Simple enough? Lets move on. There’s only one other Quad function in this program and its used in a slightly complicated way so I’ll introduce it in an easier way, this function is SetBorderColor() its defined like this:
void wsp::Quad::SetBorderColor ( GXColor borderColor )
Sets the color of the border of the quad. Initial color is black.
Parameters:
borderColor A GXColor with the desired data.
For the purpose of this guide, we will only be dealing with a 32-bit colour stream, there are several flags you can use as it is passed directly to DX, we will use DXColor. A simple call to this using our quad object may look something like this:
quad.SetFillColor((GXColor){0x00, 0x00, 0x00, 0xFF});
first we pass the colour flag called GXColor then the required RGBA colours. This would make our quad object fill with the colour black and because the alpha value is set to full its solid. To understand what the values in hex are see chapter 2. Aside from the ability to set a colour, being able to set its alpha is very handy, you can create fade screens by creating a variable that holds the value 255, then, when something happens you could fade it out then fade in again. There’s a function in spritetest.cpp that accomplishes this task although I won’t go over it here, but it can be used in a similar way to the SetTransparency() function that we used on the sprites.
Now I’ll go through a series of Get/Set Functions that are in the Quad class, explaining what they are and how to use em.
SetRotation and GetRotation
void wsp::Quad::SetRotation ( f32 rotation )
Sets the rotation angle of the quad.
Parameters:
rotation The new angle of the quad. It is measured in degrees/2, so if 90 degrees is wanted, 45 degrees should be the passed parameter.
This works in the same way as SetRotation() in Lesson 4, the value passed must by divided by two in order to get the true result. As this simply works in the same way as SetRotation in the Sprite class, simply read that description in order to learn how to use it. GetRotation() works in the same way as any other ‘Get’ function. Simply call GetRotation from the Quad class to, well, get the current angle of rotation. Examples of how both of these functions would be used:
quad.SetRotation(90/2); // This would rotate the image +45 degrees
quad.GetRotation();
Second function will return the current rotation of the quad object which is of type Quad. After the first call for example GetRotation() will return 45.
Now I will take a short interlude to introduce a function that will allow you to understand the rest of the functions I will go over. The function of which I speak of is SetBorder(), this again is found in the Quad class.
void wsp::Quad::SetBorder ( bool border )
Turns the border of the quad on or off.
Parameters:
border Set to true if the quad should have border, false if not.
Border, as it suggests creates a border around the Quad object defined. Simply call it like this:
quad.SetBorder(true);
and to turn it off,
quad.SetBorder(false);
That’s about it for that function, now we are able to move on to the rest of the Get, Set functions.
SetBorderWidth and GetBorderWidth
void wsp::Quad::SetBorderWidth ( u16 width )
Sets the border width of the quad.
Parameters:
width The new border width of the quad.
- WiiPhlex
Basic Animation
A key element of Libwiisprite is creating an animated player that can move around the screen. This increases interactivity between the player and the program, it’s much more interesting to have your player appear to be running or what not rather than just standing there and sliding around (unless that’s the intention of your program). Imagine playing one of the ten thousand Mario bro’s games, and Mario didn’t have any animation, nor the enemies! This wouldn’t look very nice at all, so we need a system for animating our players, enemies etc. There are literally hundreds of ways of for animating something on screen, and they all have their differences, but they all have one thing in common: They all follow the same process. There are several steps in producing an animation. The following steps must be complete:
1. Load the animation images into memory. 2. Draw an animation image into the back buffer 3. Display the back buffer. 4. Go back to step 2.
Up to this point, I’ve called the pictures that make up an animation sequence “animation images.” But the correct name for such an image is a frame. An animation is made up of a series of frames. Each of these frames is displayed one after the other, usually in quick succession, at such a speed that we can’t see the difference between them and it appears to be a smooth movement. A note on storing frames, in most professional applications, the animation frames wouldn’t be in separate files and loaded into separate addresses. Instead, the entire animation sequence would be stored in a single image, which itself would be loaded into a single address in memory. The application would then use some math (which you can easily do in Libwiisprite) to determine which parts of the image to display for each frame of the animation. But will just keep it simple, we will load the individual images. First you will need to declare a few instances:
GameWindow gwd;
Sprite Frame1, Frame2, Frame3, Frame4;
Image image1, image2, image3, image4;
Quad backGroundQuad;
You don’t really need the backGroundQuad object, but it makes for a more interesting program. Now we need to load some images, we will assume that you actually have these images at the given location on an SD card:
// load images from SD card
if(image1.LoadImage("frame1.png") != IMG_LOAD_ERROR_NONE) exit(0);
if(image2.LoadImage("frame2.png") != IMG_LOAD_ERROR_NONE) exit(0);
if(image3.LoadImage("frame3.png") != IMG_LOAD_ERROR_NONE) exit(0);
if(image4.LoadImage("frame4.png") != IMG_LOAD_ERROR_NONE) exit(0);
// Set Images to Sprite objects
Frame1.SetImage(&image1);
Frame2.SetImage(&image2);
Frame3.SetImage(&image3);
Frame4.SetImage(&image4);
I won’t go over an entire program, but I will show you a couple of ways you might go about animating your player. The first method is a timer based animation, that is, the animation is based on each frame lasting a certain duration based on a value that increments over time. This is most commonly used in things like films. There’s a few functions you will be needing for this along with an array that holds the addresses of the objects. We could accomplish this as follows:
int array[] = { &Frame1, &Frame2, Frame3, Frame4 };
Now we create a function that checks each loop to see if it’s time to change to the next frame:
static int count = 0;
bool IsTimeForNextFrame()
{
count = count + 1;
if (count > 10000)
{
count = 0;
return TRUE;
}
else
return FALSE;
}
Next thing we need to do is update the frame counter, there’s several ways of doing this, but I’ll opt for this method:
Static frameNum = 0;
frameNum += 1;
if (frameNum == 4 )
frameNum = 0;
This is somewhat boring though as most of what we want to do will involve something that will change dependant on the players input. So now I will introduce a slightly more complex scenario. We have a character that we want to animate, four images for walking left and four images for walking right. For the sake of simplicity, these are loaded from the SD card and are in the ‘Images’ folder. Now we want to make a program that will use these animations to animate our player while moving around, this is what we will look into. First thing we need is our objects for sprites and images (still not using the more optimized way yet):
Sprite RightFrame1, RightFrame2, RightFrame3, RightFrame4;
Sprite LeftFrame1, LeftFrame2, LeftFrame3, LeftFrame4;
Image r1, r2, r3, r4, l1, l2, l3, l4;
Now we load the images:
if(r1.LoadImage("RightFrame1.png") != IMG_LOAD_ERROR_NONE) exit(0); . .
Etc
Then load into the appropriate Image objects:
RightFrame1.SetImage(&r1); . . Etc
Now we place the images into an array:
Sprite right[] = { RightFrame1, .. etc }; Sprite left[] = { LeftFrame1, ..etc }; That was the easy part. Now we need to determine how we will go about animating the images. I’ve chosen the easiest option I can for here although as far as animation methods go its very slow. First thing we will need is a structure that holds the players information (you may want to consider changing this to a class, then changing the members to private and creating get and set functions).
struct Player {
int x = 100;
int y = 400;
int animateImage = 0;
int time = 1;
Sprite direction[] = right[];
Sprite image = direction[animateImage]
}
Here’s what the members represent
Player.x – the x value on the screen where the player should be printed. Player.y – the y value on the screen where the player should be printed. animateImage – this is directly related to the element of the direction array from which the program should copy. time – a value that is incremented each loop and checked in animatePlayer and if it is equal to one of the if statements, image is changed. direction[] – an array that contains the images for the current direction. image – the sprite that is the current image that must be printed to the screen, it is got from the direction image array at the element from which animateImage is equal to.
An update must be applied each loop to the Players x and y members and would be called as follows:
Player. image.SetPosition(Player.x, Player.y);
Next thing we need is a function for changing our animation, I will separate this into two different functions, one will get the direction while the other changes the image. The first is the one that will get the direction:
void readControls()
{
WPAD_ScanPads();
if(pressed & WPAD_BUTTON_RIGHT)
Player.x += 2;
Player.direction[] = right[];
animatePlayer()
elseif(pressed & WPAD_BUTTON_LEFT)
Player.x -= 2;
Player.direction[] = left[];
animatePlayer()
}
This function will get whatever is being pressed on the wii mote thats what WPAD_ScanPads(); does, it’s then checked against the if statement. We will take an example, if we were pressing the Right button on the wiiMote, Player’s x member would increase by 2, then, the right array would be copied to direction in Player, then after that, control would be passed to animatePlayer() which we will have a look at now. Seeing as we’ve done all of this we will now need a function that will change the frame to which ever one relevant. The function may look something like this:
void animatePlayer()
{
Player.time++;
if ( Player.time > 10000) {
Player.time == 1;
Player. animateImage == 0;
}
elseif (Player.time > 2500) {
Player. animateImage == 1;
}
elseif (Player.time > 5000) {
Player. animateImage == 2;
}
elseif (Player.time > 7500) {
Player. animateImage == 3;
}
}
This isn’t the best way of doing it, but very easy to understand. This is called each loop and Player.time is incremented. It is then checked against a series of if statements to see if it should change the animateImage variable. Now we have a series of functions we need to know in which order we should call them, it doesn’t matter too much the way you call them but in relation to Flush and Draw function calls they should be called in a certain order so that we can actually see our animation working correctly.
1. readControls() 2. animatePlayer() 3. manager.Draw(0, 0) 4. Flush()
Something else to take into account is passing the current image to the current layer object. Another more advanced function for animation (that is far more efficient) follows:
void addAnimation(string name, int frames, int interval)
{
animationTimers[name] = {frames = frames, interval = interval, timer = 0}
}
float animate(string name)
{
if (animations[name].timer >= animations[name].frames*animations[name].interval
{
animations[name].timer = 0;
}
animations[name].timer = animations[name].timer + 1;
return math.ceil(animations[name].timer/animations[name].interval);
}
Called as: addAnimation(player,8,5) //make animation called player with 8 frames that show for 5 frames each player.img = player.d[animate(player)]
That’s the manual way of doing animation, now that you have a foundation understanding of it all let’s take a look at how Libwiisprite does it and how it makes it easier for us. The first function we will look at is SetFrameSequence() found in the Sprite class.
void wsp::Sprite::SetFrameSequence ( u32 * sequence,
u32 length
)
Sets the current frame sequence.
Parameters:
sequence An array with data for each sequence. Each member cannot be bigger than the maximum amount of frames.
length The length of the sequence. Gets length amount of data.
Seeing as how there is a section in the documentation about this specific topic, here’s what it says:
“Animation sequences help the developer handle animations more easily. Sequences are arrays of u32 variables. Each of these variables is a frame index of the sprite. The starting sequence looks like this: When you do NextFrame() on a Sprite which has 4 frames without modifying its sequence, frames get changed like this: [0] -> [1] -> [2] -> [3] -> [0] -> ... This happens, when you do PrevFrame() [0] -> [3] -> [2] -> [1] -> [0] -> ...
As you can see, it is pretty straightforward. Now we assign an own sequence. When assigning a sequence, each of its members musn't be bigger than actual frames available, or it won't get set. So if we assign the sequence to u32 seq[6] = {0, 3, 1, 1, 2, 3}; this happens:
On NextFrame(): [0] -> [3] -> [1] -> [1] -> [2] -> [3] -> [0] -> ... On PrevFrame(): [0] -> [3] -> [2] -> [1] -> [1] -> [3] -> [0] -> ...
The sequence just keeps on looping and only changes when you assign a new one or change to an Image with fewer frames than the current one. So as you may see, sequencing can help you a lot with your animation needs.” A few things to note, is that this is made primarily for sprite sheets, and will take some additional coding on the Sprite constructor to ‘cut’ up the image and determine what sections are what. There are several other functions for manipulating your animation images, I will go over the important ones briefly.
void wsp::Sprite::NextFrame ( ) Sets the current frame to the next frame in the sequence. Goes back to the first member if no frames left in the sequence.
Explanation is on the previous page, but to tell you what’s actually happening, it increments a pointer to the next element, if the pointer is at the end it will be pointing to null in which case it will move to element 0.
void wsp::Sprite::PrevFrame ( )
Sets the current frame to the previous frame in the sequence. Goes to the last member if the current frame is 0.
Similar to NextFrame() although decrements the pointer to point to the nth – 1 element, if the pointer moves past the 0th element and subsequently points to null, then it will move to the last element in the array.
u32 wsp::Sprite::GetRawFrameCount ( ) const
Gets how many frames there are at all.
Simple enough function, I don’t bother explaining what’s already written.
u32 wsp::Sprite::GetFrame ( ) const
Gets the current frame of the sprite.
Returns:
The frame this sprite is at.
This will be the element of the array passed to SetFrameSequence(). And that’s about it for this lesson, till next time...
- WiiPhlex
Collision Detection
Most games these days will have some form of collision detection weather you know it or not, in fact every game I can think of has some form of collision detection weather it stops you moving off the screen or Unreal Tournament 3’s complete physics engine, it all has some form of detecting collision. I will go over the collision detection functions that Libwiisprite supports and how to use them, along with a method of optimizing your collisions using a node based system.
An introduction to what collision detection is: say you’ve just made your game with some pretty graphics, for example, a wall and a box. You know that in real life when your box hits the wall it will stop, sadly though, your game is not real life, therefore you will simply move through (under or over if it’s 2D) your wall that you worked so hard to put there. So now we need a system that will tell use when our box is touching the wall then we act on it to stop it moving.
This would require some math and a lot of GetWidth() calls, but, Libwiisprite has brought us a bunch of functions that will allow us to check collision without having to even know what math is. First function regarding collision is CollidesWith(), if you have looked at the documentation, you will see 3 different definitions for CollidesWith(), we will first look at the second which looks like this:
bool wsp::Sprite::CollidesWith ( const Sprite * sprite,
bool complete = false
) const
Checks if another sprite collides with this sprite.
Parameters:
sprite The sprite to check.
complete Set this to true, if you also want to use zoom and rotation with the collision detecting.
Now, for a lot of people that are new to collision detection or programming in general, this will make little sense, I’ll show you a small example on how to use it. First we set up two sprite objects (lets assume that we have already passed it an Image object), called sprite and sprite2. This is how we would pass them to the function:
sprite.CollidesWith(&sprite2);
This will test both sprite and sprite2’s locations in terms of their x and y values AS WELL as their x values +width and height values + height. If sprite and sprite2 are colliding then the function will return true else it will return false. If your still a little unsure about what will return true and what will return false have a look at this and behold my awesome Paint skills:
Figure 1: Returns false; Figure 2: Returns true
Figure 1 would return false as they aren’t colliding. Whereas, figure 2 would return true because they are colliding.
Ok, so now we know weather or not they are colliding, but that doesn’t automatically stop them from moving through the object. Usually you will want to stop the image once it is touching the border of the other image, but not overlapping at all that would mean stopping the sprite2 from moving further right in any of the given situations:
Figure 3: sprite2 will be unable to move any further right without moving above sprite
So how we do we stop sprite2 from moving through sprite when CollidesWith() returns true? You would set up your main loop something like this:
NOTE: This example assumes you have a structure or class that holds sprite2’s x and y position called Player.
int main()
{
init stuff
load sprite images etc
while(true)
{
int oldX = Player.x;
get input from wiiMote
if ( sprite2.CollidesWith(&sprite))
Player.x = oldX
The previous section of code gets the players x position at the start of every loop and saves it in an int. Then, it makes a call to CollidesWith() and tests if sprite is colliding with sprite2, if this returns true then Player.x will be changed to whatever it was at the start of that loop. You have to make sure that you lay out the get x, THEN input from the wiimote then call the collision function. If you don’t understand why this must be done, I’ll walk you through an example, say Player.x = 100, when it gets to
int oldX = Player.x;
oldX will be assigned the value of Player.x (100), further, we are pressing left so when it gets the input Player.x is decreased by, say 2, now Player.x = 98. Next thing that happens is that we check for collision, collision returns true therefore we don’t want Player.x to equal 98, so because collision is true Player.x is now assigned the value of oldX which is 100, so now we are moved back to the x location, 100, therefore, stopping the player from moving left even though we are pressing left. Some people have troubles, when collision is true and they try to move away, they become locked onto the image and are unable to move, due to collision being tested after the input this is avoided and works fine for being able to move away.
Now, you may have noticed all of the calls CollidesWith() have only used the first parameter, I’ve stayed away completely from it. So now I shall reveal its functionality. Due to the nature of the collision we’ve been using, it will only work for images at their native resolution and not rotated (amongst other things) so that’s why we have the second parameter. Set it true if you want to add collision detection for objects that are rotated or zoomed, if you aren’t sure how to go about this:
sprite2.CollidesWith(&sprite, true);
There is a cost associated with this though, if you don’t need to check collision on something that’s rotating or zooming, don’t. It’s not very good programming practice and will lower the performance of your program.
One thing that can eat your programs performance is collision detection, for this reason I will introduce a method of vastly improving collision detection speed. Imagine a situation where you have to check 100 different collisions every single loop, it will take a damn long time for your loop to complete. On top of that, if you are detecting collision for images that are zoomed and not at native resolution as well as rotated, you will have a noticeable performance loss.
Chances are, most of those checks will return false, so we’ve just wasted a whole lot of cycles, so now we need a method of limiting the number of collision detections. A simple way of doing this is separating the ‘screen’ into a series of squares, known as nodes. You can’t see these squares on the screen though, consider them imaginary. Say we split our screen into 4 equal nodes, the nodes may look like figure 4.
The numbering system is simply there so I can explain things easier, so from now on I will refer to the top right node as Node1, the top right Node2 and so on.
Now, you may be wondering “how do we set up these nodes?”, I will do it using Libwiisprites Rectangle object, so we set up four nodes:
Rectangle Node1, Node2, Node3, Node4;
Rectangle is a structure defined as:
Public Attributes
f32 x
X position.
f32 y
Y position.
f32 width
Width of rectangle.
f32 height
Height of rectangle.
Detailed Description
Basic data for a rectangle.
Now we need to fill these attributes. To simplify things, let’s say our screen resolution is 800x600, now we need to separate 800x600 into 4 equal squares like in figure 4. So we take the resolution and divided it by square root of n number of nodes, so square root of 4 is 2, 800 x 600 divided by 2 = 400 x 300, this is the size of each of our nodes and will be filled in as follows:
Node1.height = 300; Node1.width = 400;
And continue on for the rest of the nodes filling in the same values. Next we need the x and y values of the nodes so the program knows where they are on the screen. This is easily done considering the top left of the screen to be (0,0) and x increases moving left with y increasing moving down the screen, look at figure 5 for a visual representation of all coordinates.
If you recall, all coordinates for images (and objects alike) are for the top left corner of the image/object, so our x and y values would look like this:
Node1.x = 0; Node1.y = 0;
Node2.x = 400; Node2.y = 0;
Node3.x = 0; Node3.y = 300;
Node4.x = 400, Node 4.y = 300;
If you still don’t see where I got the values look at the coordinates at the top left corner of every node, they correspond to the values filled in for their x and y values.
Next we check collision against each of the nodes, not the objects that we are actually colliding with within the nodes, we don’t care about weather or not we are colliding with them (note, some additional coding may be required dependant on how your program is set up), so we would do it like this:
If (Player.CollidesWith(&Node1)) { // check node1
// other stuff here }
If (Player.CollidesWith(&Node2)) { // check node2
// other stuff here }
If (Player.CollidesWith(&Node3)) { // check node3
// other stuff here }
If (Player.CollidesWith(&Node4)) { // check node4
// other stuff here }
What this does is check what nodes we are in, each will return true if we are in that node and execute ‘other stuff’ (I’ll get to what the other stuff is in just a moment) otherwise it will check the next node. Now we will get into that other stuff. Now that we know which node(s) the player is in, we know what we don’t have to check. If you don’t get what I mean look at figure 6:
First our program will check Node1, because Player isn’t colliding with or ‘in’ Node1, this will return false and it will move to Node2, Node’s 2 and 3 will return false, but Node4 will return true and execute other stuff, this other stuff is the collision checks that are within that node so let’s replace other stuff with the other collision checks for the objects that are in Node4:
If (Player.CollidesWith(&Node1)) { // check node1
if ( Player.CollidesWith(&object1))
Player.x = oldX;
Player.y = oldY;
.
.
Etc
if ( Player.CollidesWith(&objectN))
Player.x = oldX;
Player.y = oldY;
}
See now, we have cut 100 checks (25 objects in each node was the example), down to just 29, 4 for the nodes and 25 for the objects in the node, that’s 71 less checks and exactly the same result as 100 checks! Now consider the following figure (7)
First it will check Node1, this will return true as Player is inside Node1, it will then proceed to check all of the objects in Node1 against player, once this has finished, it will check Node2, which again will return true and check collision for the objects in Node2. Then it will check Nodes 3 and 4 which will both return false. This is now 54 checks rather than 100.
This hasn’t been the best way of implementing a Node based collision system, it would have been better to create a node class then instance it for easier use, although I don’t have the time. This system is similar to one called a quad tree, although it may be overkill to implement such a sophisticated system in what will mostly be 2D programs, the basics are that it will split your plane into 4 equal sized nodes just like figure 4, then check collision against those nodes, this is where it gets a little more complicated. Once it knows which nodes you are in, it will then split that node into another 4 nodes like in figure 8:
It will subdivide further to a specified level, but first it will check again which ‘leaf’ nodes you are in (leaf nodes are simply the nodes that are farthest down the tree). If all this talk of tree’s and leafs is confusing you, you best learn it as these are the proper terms, the parent is a node that has n number of leaf nodes, once a leaf node gets another node attached to it further along it becomes a parent node and the new node is the leaf. Back to our program now, after another check this happens:
Another split would look like this:
It will only subdivide a certain number of times as specified by the programmer, as you can see, it gets rather messy, but once the quadtree has reached the leaf nodes, it will check collision against the objects in each of the leave nodes. The more levels you add to your quad tree the more precise the checks will be but as I said, it gets to a point where you will lose performance rather than gain any. This method wouldn’t be at all difficult using Libwiisprite, just create a Node class and a QuadTree class, if you wish to know more, there are many resources related to computer science and large terrain rendering that feature quad trees as they are widely used for collision detection in large terrains and also sometimes for optimizing graphics rendering engines.
Something to remember with CollidesWith() is that it will only accept the address of the following objects according to the documentation:
- Rectangle - Sprite - TiledLayer
Before I finish up this section on collision detection, I’ll go over a couple more functions from Libwiisprite related to collision detection. The first is DefineCollisionRectangle().
void wsp::Sprite::DefineCollisionRectangle ( f32 x,
f32 y,
f32 width,
f32 height
)
Defines a collision rectangle. On startup it's the same as Image width and height.
Parameters:
x Offset from the upper left corners position of the sprite.
y Offset from the upper left corners position of the sprite.
width The width of the collision rectangle.
height The height of the collision rectangle.
It looks long and complicated but really it’s just the same as setting up a Rectangle object. A Collision Rectangle is an area in our plane that we can check against for collision that has 4 sides, exactly the same as our Nodes, so let’s say we wanted to create Nod1 from this, we would do it as such:
Node1.DefineCollisionRectangle(0,0,400,300);
X position = 0, y position = 0 (top left of the screen is (0,0,)), width is 400 pixels and height, 300. Simple enough, now we have a node set up. Instead of using the CollidesWith() function as we have previously been using, we will use a new function in Libwiisprite called GetCollisionRectangle()
const Rectangle* wsp::Sprite::GetCollisionRectangle
( ) const
Gets the current collision rectangle.
Returns: A pointer to the rectangle.
Rather than returning true or false, it will return a pointer the current collision rectangle, which we know as being a node. From here, we then check the player against the objects in that node just like before but use pointers for the nodes instead of the object itself. Some additional coding may be required for objects that are colliding with more than one node.
That’s about as much patience as I have for collision detection, till next time...
- WiiPhlex
Tiled Layers
Say you have an animation that requires 12 different frames for moving left, right looking up etc, it’s not very practical to load all of those 12 images individually, so many programmers opt for using a ‘sprite sheet’, this is a single image that is made up of a whole series of frames, an example of a sprite sheet:
As you can see, it’s easier to load this than the 96 individual images on that sheet. If we were to load that using the LoadImage() function it would just load the entire thing and assume it to be a single object, so that’s where Libwiisprite makes life easier again. With the TiledLayer class, we are now able to load an image then pass it to the functions that will split it up for us (given a few numbers) and then we have a nice animation we can play around with. So, first thing we need to do is load in an image so we must create an Image object
Image spirteSheet;
For this example, imagine this is our sprite sheet that we will be using throughout the program:
Obviously, this is demonstration purposes only, you would consider things like deleting all pixels that you don’t need, white pixels and invisible, they are white... So deleting them will make your image smaller and look much better when copied to the front buffer.
Now imagine a grid system on this, where the there are a total of 4 tiles vertically and 2 horizontally, like this:
Now that you know what I’m talking about, we now load
then image from memory or from file:
if(spirteSheet.LoadImage("spirteSheet.png") != IMG_LOAD_ERROR_NONE)exit(0);
or
if(spirteSheet.LoadImage(spirteSheetImage) != IMG_LOAD_ERROR_NONE)exit(0);
Instead of creating a Sprite object and passing it the address of the Image object, we set up a TiledLayer object and call its constructor, so let’s take a look at the constructor:
Constructor & Destructor Documentation
wsp::TiledLayer::TiledLayer ( s32 columns,
s32 rows,
u32 ani
)
Constructor.
Parameters:
columns The number of columns.
rows The number of rows.
ani The possible number of tiles with animations.
If we look at our sprite sheet we can see that there are 4 rows (rows go these ways <-> ) and 2 columns (go up and down). The number of possible animation tiles is rows times columns which gives us all of our values, 2, 4 and 8 (remember to include tiledlayer.h):
TiledLayer ourTileObject(2, 4, 8);
This determines how our image will be split up. The width of each tile will be the images native width divided by the number of columns you input, and the height of each tile will be the images native height divided by the number of rows you pass to the constructor. Now we have a TiledLayer object setup called ourTileObject (excellent name I believe), now we need to load our image into it, we do this using the function called SetStaticTileset()
void wsp::TiledLayer::SetStaticTileset ( Image * image,
u32 tileWidth,
u32 tileHeight
)
Parameters:
image The image to set as the new Tilesetlayer. If the Image has more or equal tiles, the data won't change.
tileWidth The width of each tile.
tileHeight The height of each tile.
The first parameter is simply the address of Image object called spriteSheet, the second ones aren’t difficult but I will explain. For our above sprite sheet, the resolution is 100 x 200, that is, 100 pixels across by 200 pixels down, the width of each tile is 50 pixels (total width divided by total number of columns) and the height of each tile 50 pixels (total height divided by total number of rows). So we can fill in the parameters as follows:
ourTileObject. SetStaticTileset(&spriteSheet, 50, 50);
This will pass our sprite sheet to outTileObject and specify that each tile must have a height and width of 50 pixels. Each tile is assigned a unique index number. The tile located in the upper-left corner of the Image is assigned an index of 1. The remaining tiles are then numbered consecutively in row-major order (indices are assigned across the first row, then the second row, and so on). These tiles are regarded as static tiles because there is a fixed link between the tile and the image data associated with it.
A static tile set is created when the TiledLayer is instantiated; it can also be updated at any time using the SetStaticTileset() function. In addition to the static tile set, the developer can also define several animated tiles. An animated tile is a virtual tile that is dynamically associated with a static tile; the appearance of an animated tile will be that of the static tile that it is currently associated with.
Animated tiles allow the developer to change the appearance of a group of cells very easily. With the group of cells all filled with the animated tile, the appearance of the entire group can be changed by simply changing the static tile associated with the animated tile. This technique is very useful for animating large repeating areas without having to explicitly change the contents of numerous cells.
Animated tiles are created using the CreateAnimatedTile () function, which returns the index to be used for the new animated tile. The animated tile indices are always negative and consecutive, beginning with -1. Once created, the static tile associated with an animated tile can be changed using the SetAnimatedTile () function.
The TiledLayer's grid is made up of equally sized cells; the number of rows and columns in the grid are specified in the constructor, and the physical size of the cells is defined by the size of the tiles.
The contents of each cell is specified by means of a tile index; a positive tile index refers to a static tile, and a negative tile index refers to an animated tile. A tile index of 0 indicates that the cell is empty; an empty cell is fully transparent and nothing is drawn in that area by the TiledLayer. By default, all cells contain tile index 0.
The contents of cells may be changed using SetCell () and FillCells() Several cells may contain the same tile; however, a single cell cannot contain more than one tile. The following example illustrates how a simple background can be created using a TiledLayer.
In this example, the area of water is filled with an animated tile having an index of -1, which is initially associated with static tile 5. The entire area of water may be animated by simply changing the associated static tile using setAnimatedTile(-1, 7).
Rendering a TiledLayer
A TiledLayer can be rendered by manually calling its paint method; it can also be rendered automatically using a LayerManager object.
The paint method will attempt to render the entire TiledLayer subject to the clip region of the Graphics object; the upper left corner of the TiledLayer is rendered at its current (x,y) position relative to the Graphics object's origin. The rendered region may be controlled by setting the clip region of the Graphics object accordingly.
Now we know how to use the main part of the functions, we will now take a look at some more functions that will help you use tiles in your programs. First I will go over a series of ‘get’ functions, the first of which is GetRows() (and GetColumns() . They are both defined as:
u32 wsp::TiledLayer::GetColumns ( ) const
Gets the size of the columns.
Returns:
The size of one column.
And
u32 wsp::TiledLayer::GetRows ( ) const
Gets the size of the rows.
Returns:
The size of one row.
Very easy to use function, just call it and it return a type u32 of the number of columns or rows in that Object. The next is a handy function for getting the address of the image passed to the TiledLayer object:
const Image* wsp::TiledLayer::GetImage ( ) const
Gets the image of the tiledlayer.
Returns:
A pointer to the image. NULL if there is no image specified.
Simple enough to use, just make sure you have something set up to handle if this function returns null otherwise your program will not be very happy. On we go to the next functions! GetCellHeight() and GetCellWidth() .
u32 wsp::TiledLayer::GetCellWidth ( ) const
Gets the cell width.
Returns:
The width of a single cell.
And
u32 wsp::TiledLayer::GetCellHeight ( ) const
Gets the cell height.
Returns:
The height of a single cell.
This will return a type u32 with the width or height in pixels (obviously you can’t have half a pixel), this can be useful if you want to manipulate the size of each cell by its current size +/- a value.
Next functions we will look at regard the alpha value of the Image object passed to, this works just the same as SetTransparency() for a Sprites image:
void wsp::TiledLayer::SetTransparency ( u8 alpha )
Sets the transparency of the tiledlayer.
Parameters:
alpha Sets the transparency. Has a range from 0x00 (invisible) to 0xFF (fully visible)
And to get...
u8 wsp::TiledLayer::GetTransparency ( ) const
Gets the transparency of the tiledlayer.
Returns:
The current transparency of the tiledlayer. Has a range from 0x00 (invisible) to 0xFF (fully visible)
I won’t bother telling you what these do, the examples enough and there’s a more detailed description on getting and setting alpha values in chapter 4.
Moving along quickly, we will now look at the last function regarding the TiledLayer class, Draw()
void Draw (f32 offsetX=0, f32 offsetY=0) const
Draws the tiledlayer to the current viewport.
A very handy function for easily drawing your tiles, ignore the parameters for now, just leave them as 0, this will draw a TiledLayer object to the viewport, so you can see it basically. Call like this:
ourTileObject.Draw(0,0);
Simple! And that brings us to the end of the Tiled Layer section of this guide. Note: some of this was taken from http://java.sun.com/ I thank the people at Sun for allowing the use of their material in this section. Until next time,
- WiiPhlex
Pixel Referencing and Offset
You may have read up to this point and have been thinking along the way, “dammit stop saying ignore offset!”, well today you become a man, erm, I mean you learn what offset and pixel referencing is, sorry I often get the two mixed up... Anyway, I’ll start with the offset first of all as it is the easiest to understand.
In plain terms, offset means not set correctly. Think about your screen, it’s a grid made up of tens of thousands of dots, each of these dots has a ‘default’ location, top left pixel is (0,0), when you change the offset, you move where these locations are. For example, when you go to print an image at location (100, 100), then it will print with its top left corner at the coordinate (0,0) and print the rest of the pixels based on that.
If however, you were to print that image at location (100,100) with an offset of (10,10) then you would print that image at location (110,110). You can calculate the offset by adding the coordinates, this goes for negatives as well, a few examples.
Coordinates OffSet PrintLocation
(10, 40) (-20, 4) (-10, 44)
(300, 0) (0, 0) (300, 0)
Etc
That’s about all there is to offset, so let’s look at the slightly more complex, Pixel Referencing. The easiest way to understand pixel references is an example. In sprite.cpp we looked at the following SetPosition() function:
sprite2.SetPosition(320, 240);
This was one method of setting where the image should be printed, but I completely ignored the other which is, SetRefPixelPositioning()
void wsp::Sprite::SetRefPixelPositioning ( REFPIXEL_POSITIONING
positioning )
Sets how the sprite should react on X and Y coordinates.
Parameters:
positioning Specifies the type of the positioning.
Usually when you print an image to the screen, it, by default, prints to the top left (wsp::REFPIXEL_POSITIONING, default parameter in the emuneration is REFPIXEL_POS_TOPLEFT), but what we have done here, is instead pass it a different parameter that lets you customize where your image will print by default. We pass the function REFPIXEL_POS_PIXEL, which in is defined in the enum section:
REFPIXEL_POS_PIXEL The reference pixel is placed at the X and Y coordinates.
This is just another method of setting where you want to print your image, the x any y coordinates move the reference pixel to the coordinate specified and when SetPosition() is called and the image is printed at the centre of the screen.
What this does is effectively cut out part of the image. Say we have an image that has a resolution of 150 x 150 pixels and we print it at location (0,0) then it may look something like this:
Now say that we have set the pixel reference to (10,10) then it will find the pixel on the image that is at location (10,10) which would be where the black dot is on the below image:
The image will be printed like this at location (0,0)
If you look closely you can see that some of the image has been cut off, 10 pixels starting at the right side and 10 pixels starting from the top have been cut off and the image is printed at the coordinate (0,0) just as it would if it had no pixel referencing. You essentially crop the image from the top left corner using whatever values you have assigned the parameters. So looking at the call in sprite.cpp to the refpixel function you can see that the image is still being printed but is also passed the enumeration REFPIXEL_POS_PIXEL. That brings me to the end of another (but short) lesson on the Libwiisprite, hope you learned something.
If you wish to contact me drop me an email at phlex.wii@gmail.com
EXAMPLE PROGRAMS
Lesson 1: Setting up Libwiisprite for use.
Description: This is the same code encountered in chapter 1, to build, make sure to have to include the correct lib’s (as shown in chapter 1) in your make file. For a template make file, refer to lesson 1.
Lesson 2: Setting up the Video display.
Description: basic template for using Libwiisprite, in order to build make sure you have included the correct lib’s as stated above. The following program will set up the wii and render the background with the colour white.
main.cpp
#include <wiiuse/wpad.h>
#include <wiisprite.h>
// libwiisprite uses wsp as it's namespace
using namespace wsp;
int main(int argc, char **argv)
{
// Create the game window and initalise the VIDEO subsystem
GameWindow gwd;
gwd.InitVideo();
gwd.SetBackground((GXColor){ 255, 255, 255, 255 });
// Initialise Wiimote
WPAD_Init();
for(;;)
{
WPAD_ScanPads();
if(WPAD_ButtonsDown(WPAD_CHAN_0)&WPAD_BUTTON_HOME)
break;
gwd.Flush();
}
return 0;
}
Lesson 3: Loading and printing images.
Description: a simple program that loads an image from SD card and prints it to the screen, see Lesson3 for more information.
#include <stdio.h>
#include <stdlib.h>
#include <gccore.h>
#include <wiiuse/wpad.h>
#include <fat.h>
#include <wiisprite.h>
using namespace wsp;
GameWindow gwd; // Initializes and renders our scene.
Sprite sprite; // The drawable object we can modify.
Image image; // Holds our image/texture from the SD Card.
int main(int argc, char **argv) {
// Initialize filesystem to load from SD Card
fatInitDefault();
gwd.InitVideo();
LayerManager manager(1);
if(image.LoadImage("libwiisprite.png") != IMG_LOAD_ERROR_NONE)exit(0);
sprite.SetImage(&image);
sprite.SetPosition(0, 0);
manager.Append(&sprite); // Gets drawn the closest.
WPAD_Init();
WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR);
while(1) {
WPAD_ScanPads();
u32 pressed = WPAD_ButtonsHeld(WPAD_CHAN_0);
// Draw everything what's in the manager.
manager.Draw(0, 0);
gwd.Flush();
}
manager.Draw(0, 0);
gwd.Flush();
return 0;
}
Lesson 4: Basic Image Manipulation
Description: Shows some examples of manipulation images with some of the basic public functions in Libwiisprite, this was taken from sprite.cpp in the Libwiisprite examples release. This assumes you have two images on the SD card called libwiisprite.png and libwiisprite2.png..
#include <stdio.h>
#include <stdlib.h>
#include <gccore.h>
#include <wiiuse/wpad.h>
#include <fat.h>
#include <wiisprite.h>
using namespace wsp;
GameWindow gwd; // Initializes and renders our scene.
Sprite sprite; // The drawable object we can modify.
Sprite sprite2; // Another drawable object we can modify.
Quad quad; // A drawable rectangle for fading in and out.
Image image; // Holds our image/texture from the SD Card.
Image image2; // Holds our buffer image/texture.
bool calc_fade(u8 fade);
u8 fadedata = 0xff;
int main(int argc, char **argv) {
fatInitDefault();
gwd.InitVideo();
LayerManager manager(3);
if(image.LoadImage("libwiisprite.png") != IMG_LOAD_ERROR_NONE)exit(0);
if(image2.LoadImage("libwiisprite2.png") != IMG_LOAD_ERROR_NONE)exit(0);
sprite.SetImage(&image);
sprite2.SetImage(&image2);
sprite.SetPosition(0, 0);
sprite2.SetRefPixelPositioning(REFPIXEL_POS_PIXEL);
sprite2.SetPosition(320, 240);
quad.SetPosition(-40, -40);
quad.SetWidth(800);
quad.SetHeight(600);
manager.Append(&quad);
manager.Append(&sprite);
manager.Append(&sprite2);
WPAD_Init();
WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR);
u8 fading = 1;
while(1) {
WPAD_ScanPads();
u32 pressed = WPAD_ButtonsHeld(WPAD_CHAN_0);
if(pressed & WPAD_BUTTON_HOME)fading = 2;
if(calc_fade(fading))break;
if(fadedata == 0x00)fading = 0;
if(pressed & WPAD_BUTTON_MINUS)
sprite.SetZoom(sprite.GetZoom()-0.1f);
if(pressed & WPAD_BUTTON_PLUS)
sprite.SetZoom(sprite.GetZoom()+0.1f);
if(pressed & WPAD_BUTTON_A && sprite.GetTransparency() < 0xff-4)
sprite.SetTransparency(sprite.GetTransparency()+5);
if(pressed & WPAD_BUTTON_B && sprite.GetTransparency() > 4){
sprite.SetTransparency(sprite.GetTransparency()-5);
}
if(pressed & WPAD_BUTTON_UP)
sprite2.SetStretchHeight(sprite2.GetStretchHeight()+0.1f);
if(pressed & WPAD_BUTTON_DOWN)
sprite2.SetStretchHeight(sprite2.GetStretchHeight()-0.1f);
if(pressed & WPAD_BUTTON_RIGHT)
sprite2.SetStretchWidth(sprite2.GetStretchWidth()+0.1f);
if(pressed & WPAD_BUTTON_LEFT)
sprite2.SetStretchWidth(sprite2.GetStretchWidth()-0.1f);
ir_t ir;
WPAD_IR(WPAD_CHAN_0, &ir);
sprite.SetPosition(ir.sx-WSP_POINTER_CORRECTION_X, ir.sy-WSP_POINTER_CORRECTION_Y);
sprite.Move(-((f32)sprite.GetWidth()/2), -((f32)sprite.GetHeight()/2));
sprite.SetRotation(ir.angle/2);
manager.Draw(0, 0);
gwd.Flush();
}
manager.Draw(0, 0);
gwd.Flush();
return 0;
}
bool calc_fade(u8 fade){
if(fade == 1){ // Fading in
if(fadedata < 0x10)fadedata = 0x10;
fadedata -= 0x10;
}else if(fade == 2){ //Fading out
if(0xef < fadedata)fadedata = 0xef;
fadedata += 0x10;
}
quad.SetFillColor((GXColor){0x00, 0x00, 0x00, fadedata});
if(fade == 2 && fadedata == 0xff)return true;
return false;
}
Lesson 5: Layer Management.
Description: A small program that shows how to use function in the LayerManager class. By then end of the series of calls, Quad is at location 0 and sprite is at 1.
#include <stdio.h>
#include <stdlib.h>
#include <gccore.h>
#include <wiiuse/wpad.h>
#include <fat.h>
#include <wiisprite.h>
using namespace wsp;
GameWindow gwd; // Initializes and renders our scene.
Sprite sprite; // The drawable object we can modify.
Quad quad; // drawable quad object
Image image; // Holds our image/texture from the SD Card.
int main(int argc, char **argv) {
fatInitDefault();
gwd.InitVideo();
LayerManager manager(2);
if(image.LoadImage("libwiisprite.png") != IMG_LOAD_ERROR_NONE)exit(0);
sprite.SetImage(&image);
sprite.SetPosition(0, 0);
quad.SetPosition(-40, -40);
quad.SetWidth(800);
quad.SetHeight(600);
//action starts here
manager.Append(&sprite);
manager.Append(&quad);
u32 sizeOfList = manager.GetSize();
manager.RemoveAll();
manager.Append(&sprite);
manager.Insert(&quad, 0);
// and ends here
WPAD_Init();
WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR);
while(1) {
WPAD_ScanPads();
u32 pressed = WPAD_ButtonsHeld(WPAD_CHAN_0);
// Draw everything what's in the manager.
manager.Draw(0, 0);
gwd.Flush();
}
manager.Draw(0, 0);
gwd.Flush();
return 0;
}
Lesson 6: Quad.
Description: Shows examples of how you might call functions in the quad class as well as how to create one.
#include <stdio.h>
#include <stdlib.h>
#include <gccore.h>
#include <wiiuse/wpad.h>
#include <fat.h>
#include <wiisprite.h>
using namespace wsp;
GameWindow gwd; // Initializes and renders our scene.
Quad quad; // drawable quad object
Quad quad2; // another quad object
int main(int argc, char **argv) {
gwd.InitVideo();
LayerManager manager(2);
quad.SetPosition(-40, -40);
quad.SetWidth(800);
quad.SetHeight(600);
quad2.SetPosition (200, 200);
quad2.Setwidth(50);
quad2.SetHeight(50);
quad2.SetBorder(true);
quad2.SetBorderWidth(10);
quad2.SetBorderColor((GXColor) {0xFF, 0xFF, 0xFF, 0xFF});
quad2.SetFillColor((GXColor) {0x00, 0x00, 0x00, 0x00});
manager.Append(&quad);
manager.Append(&quad2);
WPAD_Init();
WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR);
while(1) {
WPAD_ScanPads();
u32 pressed = WPAD_ButtonsHeld(WPAD_CHAN_0);
// Draw everything what's in the manager.
manager.Draw(0, 0);
gwd.Flush();
}
manager.Draw(0, 0);
gwd.Flush();
return 0;
}
Lesson 7: Basic Animation
None Yet, if you have a sample to submit for this section email me at phlex.wii@gmail.com
Lesson 8: Collision Detection
Description: Shows how to test for collision between various objects, does not contain an example for node based collision detection (yet).
#include <stdio.h>
#include <stdlib.h>
#include <gccore.h>
#include <wiiuse/wpad.h>
#include <fat.h>
#include <wiisprite.h>
using namespace wsp;
GameWindow gwd; // Initializes and renders our scene.
Sprite sprite; // The drawable object we can modify.
Sprite sprite2; // another sprite to check collision against.
Image image; // Holds our image/texture from the SD Card.
Image image2; // hold the other image/tecture from SD card.
Rectangle rect; // rectangle object as an example.
Quad quad; //quad object for rect.
struct player {
u32 xpos, ypos
} Player;
void checkCollision(u32 oldX, u32 oldY);
int main(int argc, char **argv) {
fatInitDefault();
gwd.InitVideo();
LayerManager manager(3);
if(image.LoadImage("libwiisprite.png") != IMG_LOAD_ERROR_NONE)exit(0);
if(image.LoadImage("libwiisprite2.png") != IMG_LOAD_ERROR_NONE)exit(0);
sprite.SetImage(&image);
sprite.SetPosition(Player.xpos, Player.ypos);
sprite2.SetImage(&image2);
sprite2.SetPosition(200,200);
manager.Append(&sprite);
manager.Append(&Rectangle);
rect.width = 20; rect.height = 20;
rect.x = 50; rect.y = 50;
quad.SetRectangle(&rect);
WPAD_Init();
WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR);
while(1) {
u32 oldX = Player.xpos, oldY = Player.ypos;
WPAD_ScanPads();
u32 pressed = WPAD_ButtonsHeld(WPAD_CHAN_0);
if(pressed & WPAD_BUTTON_UP)
Player.ypos -= 1;
if(pressed & WPAD_BUTTON_DOWN)
Player.ypos += 1;
if(pressed & WPAD_BUTTON_LEFT)
Player.xpos -= 1;
if(pressed & WPAD_BUTTON_RIGHT)
Player.xpos += 1;
sprite.SetPosition(Player.xpos, Player.ypos);
checkCollision();
sprite.SetPosition(Player.xpos, Player.ypos);
manager.Draw(0, 0);
gwd.Flush();
}
manager.Draw(0, 0);
gwd.Flush();
return 0;
}
void checkCollision(u32 oldX, u32 oldY)
{
if (sprite.CollidesWith(&sprite2)) {
Player.x = oldX;
Player.y = oldY;
}
if (sprite.CollidesWith(&quad)) {
Player.x = oldX;
Player.y = oldY;
}
}
Lesson 9: Tiled Layers.
None Yet, if you have a sample to submit for this section email me at phlex.wii@gmail.com
Lesson 10: Pixel Referencing and Offset.
None Yet, if you have a sample to submit for this section email me at phlex.wii@gmail.com
Credits
(WiiPlex can put this in when he can ;))
- WiiPhlex
For helping putting the guide up on the Wiki; specifically the images but other parts too.
- LOLDSFAN