In memory of Ben “bushing” Byer, who passed away on Monday, February 8th, 2016.

Changes

Jump to navigation Jump to search
13,066 bytes added ,  10:06, 27 August 2008
Line 806: Line 806:  
- [[user:WiiPhlex|WiiPhlex]]
 
- [[user:WiiPhlex|WiiPhlex]]
   −
== Lesson 6: Quad. ==
+
== 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.
 
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.
Line 899: Line 899:  
Parameters:
 
Parameters:
 
width The new border width of the quad.</source>
 
width The new border width of the quad.</source>
 +
 +
== 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:
 +
 +
<sourcelang = "cpp">
 +
GameWindow gwd;
 +
Sprite Frame1, Frame2, Frame3, Frame4;
 +
Image image1, image2, image3, image4;
 +
Quad backGroundQuad; 
 +
</source>
 +
 +
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:
 +
 +
<source lang = "cpp">
 +
// 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);
 +
</source>
 +
 +
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:
 +
 +
<source lang = "cpp">int array[] = { &Frame1, &Frame2, Frame3, Frame4 };</source>
 +
 +
Now we create a function that checks each loop to see if it’s time to change to the next frame:
 +
 +
<source lang = "cpp">
 +
bool IsTimeForNextFrame()
 +
{
 +
      static int count = 0;
 +
      count = count + 1;
 +
      if (count > 10000)
 +
      {
 +
              count = 0;
 +
              return TRUE;
 +
      }
 +
      else
 +
        return FALSE;
 +
}
 +
</source>
 +
 +
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:
 +
 +
<source lang = "cpp">
 +
Static frameNum = 0;
 +
frameNum += 1;
 +
if (frameNum == 4 )
 +
  frameNum = 0;
 +
</source>
 +
 +
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):
 +
 +
<source lang = "cpp">
 +
Sprite RightFrame1, RightFrame2, RightFrame3, RightFrame4;
 +
Sprite LeftFrame1, LeftFrame2, LeftFrame3, LeftFrame4;
 +
Image r1, r2, r3, r4, l1, l2, l3, l4;
 +
</source>
 +
 +
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).
 +
 +
<source lang = "cpp">
 +
struct Player {
 +
      int x = 100;
 +
      int y = 400;
 +
      int animateImage = 0;
 +
      int time = 1;
 +
 +
    Sprite direction[] = right[];
 +
     
 +
      Sprite image = direction[animateImage]
 +
}
 +
</source>
 +
 +
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:
 +
 +
<source lang = "cpp">Player. image.SetPosition(Player.x, Player.y);</source>
 +
 +
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:
 +
 +
<source lang = "cpp">
 +
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()
 +
}
 +
</source>
 +
 +
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:
 +
 +
<source lang = "cpp">
 +
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;
 +
              }
 +
}
 +
</source>
 +
 +
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:
 +
 +
<source lang = "cpp">
 +
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);
 +
}
 +
</source>
 +
 +
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.
 +
 +
<source lang = "cpp">
 +
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.
 +
</source>
 +
 +
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.
 +
 +
<source lang = "cpp">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.
 +
</source>
 +
 +
 +
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.
 +
 +
<source lang = "cpp">
 +
u32 wsp::Sprite::GetRawFrameCount ( ) const
 +
Gets how many frames there are at all.
 +
</source>
 +
 +
Simple enough function, I don’t bother explaining what’s already written.
 +
 +
<source lang = "cpp">
 +
u32 wsp::Sprite::GetFrame ( ) const
 +
Gets the current frame of the sprite.
 +
Returns:
 +
The frame this sprite is at.
 +
</source>
 +
 +
This will be the element of the array passed to SetFrameSequence(). And that’s about it for this lesson, till next time...
33

edits

Navigation menu