If this page looks like garbage then you need one of these browsers...Please sign my programmer's page guestbook. |
Setting up member data and functionsOkay, now that the basics of C++ programming have been covered we can now begin to apply it to our sprite class. (If you are still fuzzy on C++, don't worry. You will see that creating classes are as easy as creating a struct and a bunch of functions.) So first, let's look at our member data again.
enum Boolean {false, true}; class Sprite { int startXoff, startYoff; // Offset copying position int lenXcopy, lenYcopy; // Actual dimensions to copy char far *displayMem; // Buffer sprite is modifying protected: int X, Y; // Sprite's current location int lastX, lastY; // Sprite's last location int width, height; // Sprite's dimensions int minX, minY; // Minimum limits int maxX, maxY; // Maximum limits int currFrame; // current frame in animation int noOfFrames; // total number of frames in animation char far **frames; // array of sprite images for animation char far *background; // background stored for dirty rectangle Boolean imgDynamic; // declares if images are static or dynamic Boolean visible; // flags if Sprite is or isn't visible int initOk; // flags if all went well during construction Boolean backTransparent; // opaque or transparent background public: // Public variables int status; // Sprite status, varies by game rules int animThreshold; // animation threshold, varies int moveThreshold; // move threshold, varies int clock; // sprite's clock }; At first glance, it may seem confusing a bit, but if you removed the keywords public: and protected: and replaced class with struct you will see the all familiar struct that we have been using so far. Okay, time out, I know that classes by default make their data private and that you can use the keyword public: to directly access the data members of a class (like a struct), but what does protected: do? That keyword works like private: with one exception, inheritence. Notice that this class has no variable for otherData like the struct did. That variable was put in the struct for future expansion, if the struct required additional data, it could create another variable (of any type needed) and set the otherData pointer to point to it. That way, we could expand the capabilities of sprites without having to re-write everything. That type of expansion is not clean, however, we would need to keep up with the pointer to this extra information as well as know exactly what type of variables this pointer points to. C++ has a better method for expansion, inheritance. All we need to do now is create another class that inherits the properties of this class and add more of it's own that it needs. The purpose of the protected: keyword is to allow classes that inherit this class to have direct access to the data without making it available publicly. (The private variables are inaccessible to any class that inherits this one.) Creating a USEFUL classDid I forget something here? Ah yes, functions! Without them our class would be totally useless. So let's create some member functions. Since we created a function that would initialize our sprites the first time (with structs and functions) let's do it again. If we are clever, we can write it so that C++ will automatically call this function whenever we create an instance of this class. This takes a little thinking, hmmm, let's start with our original function. int InitSprite(struct Sprite *thisSpr, int w, int h, int numFrames, int dynamic, int drtyRect) { int i, retVal = 1; if (w > 0) { thisSpr->width = w; if (h > 0) thisSpr->height = h; } thisSpr->imgDynamic = dynamic; if (numFrames > 0) { thisSpr->frames=(char far **)malloc(numFrames*sizeof(char far *)); if (thisSpr->frames != NULL) { thisSpr->noOfFrames = numFrames; for (i=0; i<numFrames; i++) if (dynamic && w > 0 && h > 0) { thisSpr->frames[i]=(char far *)farmalloc(w*h*sizeof(char)); if (thisSpr->frames[i] == NULL) retVal = 0; } else thisSpr->frames[i] = NULL; } else retVal = 0; } else thisSpr->frames = NULL; if (drtyRect) { thisSpr->background = (char far *)farmalloc(w * h * sizeof(char)); if (thisSpr->background == NULL && w && h) retVal = 0; thisSpr->backTransparent = 1; } else thisSpr->background = NULL; thisSpr->maxX = ScreenWidth - 1; thisSpr->maxY = ScreenHeight - 1; thisSpr->lenXcopy = thisSpr->width; thisSpr->lenYcopy = thisSpr->height; thisSpr->displayMem = videoMem; thisSpr->X = thisSpr->Y = thisSpr->lastX = thisSpr->lastY = thisSpr->minX = thisSpr->minY = thisSpr->startXoff = thisSpr->startYoff = thisSpr->currFrame = thisSpr->status = thisSpr->visible = thisSpr->clock = thisSpr->animThreshold = thisSpr->moveThreshold = 0; thisSpr->otherData = NULL; return retVal; } All the text in bold will have to be removed and all the text in italics will have to be changed in order to adapt this function into the class. Rather than go through all the rigormarole of what exactly all this is and why we need to do it, let's go ahead and present the clean code, ready to incorporate into our sprite.
Sprite::Sprite(int w, int h, int numFrames, Boolean Dynamic, Boolean DrtyRect) { int i; // width = w, if (w > 0), otherwise, width = 0 width = (w > 0) ? w : 0; // height = h, if (h>0 && width>0), otherwise, height=0 height = (width > 0 && h > 0) ? h : 0; initOk = true; // So far so good imgDynamic = Dynamic; if (numFrames > 0) { // Allocate an array of far pointers frames = (char far **)malloc(numFrames * sizeof(char far *)); if (frames == NULL) { // Something went wrong noOfFrames = 0; initOk = false; } else { noOfFrames = numFrames; // For each far pointer, allocate memory to hold an image for (i=0; i<noOfFrames; i++) if (imgDynamic && width && height) { frames[i]=(char far *)farcalloc(width * height, sizeof(char)); if (frames[i] == NULL) initOk = false; } else frames[i] = NULL; } } else { frames = NULL; noOfFrames = 0; } // If using dirty rectangles, allocate memory for background image if (DrtyRect && width && height) { background = (char far *)farcalloc(width * height, sizeof(char)); if (background == NULL) initOk = false; backTransparent = true; } else { background = NULL; backTransparent = false; } // Initialize the rest of our member variables X = Y = lastX = lastY = 0; minX = minY = 0; maxX = ScreenWidth - 1; maxY = ScreenHeight - 1; startXoff = startYoff = 0; lenXcopy = width; lenYcopy = height; currFrame = 0; visible = false; status = animThreshold = moveThreshold = clock = 0; displayMem = videoMem; } This is the function I use, you may recognize quite a few differences beyond what I originally suggested. This function has been tested and retested for bugs hence why the function appears different, but overall, it's the same ordeal. Of course, we have to declare the function within the class declaration in order to make it part of the class, so let's do so now. |
Constructors and destructors should always be declared public. However, not all member functions need to be declared public. |
class Sprite { int startXoff, startYoff; // Offset copying position int lenXcopy, lenYcopy; // Actual dimensions to copy char far *displayMem; // Buffer sprite is modifying . . . // snip . . . public: // Public variables int status; // Sprite status, varies by game rules int animThreshold; // animation threshold, varies int moveThreshold; // move threshold, varies int clock; // sprite's clock // Member function declarations Sprite(int w=0, int h=0, int numFrames=0, Boolean Dynamic=true, Boolean DrtyRect=true); }; Okay, at a first glance you will find quite a few changes in both the declaration and with the function. Let's begin with the declaration. First notice that the function has the same name as the class, Sprite. Whenever a function has the same name of the class it is declared in, that functions becomes what is known as a constructor. Constructors are called automatically whenever an instance of (variable from) a class is created, all you need to do is specify the parameters. You may also notice that the function declaration parameters have assignment operators beside them. These specify default values for the parameters if you omit them. Hmmm, do we need to go through this function and explain each line? We did explain it's "sister" function InitSprite in the structs and functions section. The only main difference between this function and the other is the following:
Send your questions, comments, or ideas to: wilkeg@gamewood.net This page hosted by
Get your own Free Home Page |