The GMSprite Object
A GMSprite is an animated object. It contains one or more bitmap images. You can teach it how to move. It animates itself. It can do some pretty cool stuff.
You can think of a sprite as a bitmap that moves around the screen. It remembers its own location. A sprite contains one or more bitmap images. If more than one bitmap is used, the bitmaps are treated as the frames in animating the sprite, and the sprite keeps track of the order of its own frames.
You can associate your GMSprite with an object called a GMBehavior. A GMBehavior can tell the sprite how to move or behave. You can write your own GMBehavior objects to define how your sprites should move and behave.
GMSprite Functions
Creating the GMSprite object
| Draw | Move
| SetPosition/SetFrame
GetX/GetY/CenterX,CenterY,Radius,GetFrame | SetDelay | FrameDirection
Rotate/SetRotation/GetRotation/Scale/SetScale/GetScale
Data Properties
SetData/GetData | Type/SetType/ResetType
Behaviors, Bitmaps, and Collisions
Behavior | NewBehavior | ChangeBitmap
Collided | SetRadius | CollisionFlags/SetCollisionFlags/ResetCollisionFlags
Sample Programs
Running Puppy
| Puppy Sprite with Behavior
(requires critters.zip)
The GMSprite has two constructors. The first lets you create the sprite from a bitmap file. The file can contain one or more images. For multiple images, the bitmap is sliced into to the individual images in the same way as with the GMBitmapList object. The individual images become the frames used in animating your sprite. Open some of the sample BMP files used below in an image editor to see how they look.
The second constructor lets you create a GMSprite from another GMSprite that you've already created. The advantage of doing this is that if you have many sprites that use the same image, the image is loaded only once into memory. If you use the first constructor to load each new sprite from the same image file, duplicate copies of the same image are loaded into memory.
Here is the first variation of the constructor:
GMSprite(GMMachine &Machine, const char* Filename
[, unsigned int TransparentColor, int width,
int height, int howmany,
int DataValues,
GMBehavior* pBehavior])
The first parameter is the name of the GMMachine object, which is Machine if you've followed all the examples.
The second parameter is the name of a BMP bitmap file.
The rest of the parameters are optional. TransparentColor is the color you designate in your bitmap that will NOT be drawn. The background will show through wherever this color appears. (Without a transparent color, your sprite would always appear as a rectangle.) The default TransparentColor is black (0). You can use the RGB function to use other colors for transparency.
If width, height, and howmany are not given, the bitmap file is assumed to contain only one image. The sprite will use only that one frame and hence not animate internally (although it still moves around the screen). If there are multiple frames stored in the bitmap file, width, height, and howmany tell the GMSprite how to slice up the bitmap. All frames must have the same width and height (in pixels), and howmany tells the number of frames to create.
If you want to use the DataValues and pBehavior parameters but you have only one frame in the bitmap, use the default values of 0,0,0 for width, height, and howmany. That instructs GMSprite not to slice up anything and to use the actual width and height from the BMP file.
The DataValues parameter is optional and defaults to 0. Each GMSprite can be created to save any number of integer values about itself. If you want to store any additional information about your sprites, you don't have to use outside storage. You can set and retrieve values that are held internally within the GMSprite. Use your imagination, but these can be values that tell energy levels, damage points, strength, armor, or anything you want to store about the sprite. The DataValues parameter is used to create an internal array of integers for the sprite, and the functions SetData and GetData let you set and retrieve those values.
The last parameter, pBehavior, is also optional. A GMBehavior object can be created to define how your sprite moves when you call the GMSprite's Move function. The Move function can also return values defined by your GMBehavior object that can tell your program about changes or the status of your sprite's behavior. Complete documentation for the GMBehavior object is in its own section. One of the samples below uses a behavior (GMBehaviorBounce) that is already created for you.
The second form of the GMSprite constructor is this:
GMSprite(const GMSprite & sprite [, int DataValues, GMBehavior* pBehavior])
This form simply uses the same bitmap and frame(s) as the GMSprite listed in the parameter list. The advantage to re-using a bitmap that's already assigned to another sprite is that the bitmap is only loaded once into memory. Be careful that you don't delete the original sprite while still using the copies, though. The copies all point to the original sprite's bitmap, and if the original sprite is deleted so is its bitmap!
void Draw()
void Draw(int x, int y)
This is much like GMBitmap's Draw. It just draws the sprite's bitmap in place. For a multiframe sprite, Draw uses the current frame without changing it. Use SetFrame to determine the "current" frame. You can use the SetPosition function to set the sprite's x,y location and then call Draw without any parameters. Or you can use x,y values in the call to Draw, which will then also perform the equivalent of SetPosition.
int Move()
int Move(int x, int y)
Move is a fancy version of Draw. Move automatically cycles the frames in a multiframe sprite. If x,y are given, it sets the sprite's position to that location. When the x,y coordinate is left off, if the sprite has a GMBehavior the behavior is used to generate the new position!
The return value for this function is whatever is returned by the GMBehavior's Move function, if a behavior is used. If a behavior is not used, or if an x,y coordinate is provided (bypassing the behavior), the return value is zero. This return value is a way for the GMBehavior to signal to your program that something has happened in the behavior (bounce? direction change? completed a cycle?). You can write your program to look for and react to specific return values from your behaviors.
void SetPosition(int x, int y)
void SetFrame(int frame)
If you prefer to control the position and frame number of your sprite within your program rather than with a "behavior", the SetPosition function sets the sprite's (x,y) coordinate, and SetFrame controls the frame number that will be displayed next.
These return the current x and y coordinates of the GMSprite.
int CenterX()
int CenterY()
int Radius()
These return the computed center of the sprite, which is sometimes more useful in determining position for interaction with other program elements. The Radius value is either computed as an approximation, or it is assigned with the SetRadius function. SetRadius and its uses are described below in the section about collision detection.
int GetFrame()
This returns the current frame number.
This sets a counter delay for changing frames of an animated multiframe sprite. "Delay" is the number of display cycles (calls to the Move function) that every frame will be shown before the frame is changed to the next one in sequence. Usually you want to switch frames less frequently than 30 cycles per second, unless you've done some marvelously-detailed animation! (30 display cycles per second is a good target speed for animation, and that is the default speed of the GMMachine's FlipTimed function.)
This delay value is only used by the Move function.
FrameDirection is an integer property of the GMSprite, used for multiframe sprites. The default value is 1, meaning that each time a new frame is needed, 1 is added to the frame number. For a 5-frame sprite, the default sequence is 1, 2, 3, 4, 5, 1, 2, 3,... If you change the FrameDirection property to -1, you reverse the sequence: 1, 5, 4, 3, 2, 1, 5, 4,... A value of 0 keeps the sprite at its current frame. (0 is added each time, giving no change). You can also use larger values. A FrameDirection of 2 would give: 1, 3, 5, 1, 3, 5, 1, 3,...
void Rotate(double degrees)
void SetRotation(double degrees)
double GetRotation()
void Scale(double factor)
void SetScale(double scale)
double GetScale()
These set the drawing parameters for rotating and scaling the sprite. The Rotate function will rotate the sprite by the given number of degrees from its most recent state. The SetRotation function will rotate the sprite the given number of degrees from its original bitmap orientation.
For example:
sprite.Rotate(30);
// assume this is first use of Rotate/SetRotation with this sprite
sprite.Draw();
// the sprite is rotated 30 degrees from its original state
sprite.Rotate(20);
// rotate the sprite 20 more degrees from its previous state
sprite.Draw();
// the sprite is now rotated a total of 50 degrees from its original state
sprite.SetRotation(40);
sprite.Draw();
// the sprite is rotated 40 degrees from its original state
sprite.SetRotation(60);
sprite.Draw();
// the sprite is rotated 60 degrees from its original state
GetRotation returns the current number of degrees of rotation of the sprite. The return value may be less than 0 or greater than 360.
Similar to Rotate, the Scale function makes the sprite appear larger or smaller by the factor given. Scale(2) will double the size of the sprite. If you use Scale(2) a second time, it doubles the size again making it four times larger than the original. You can also use fractional values to reduce the size of the sprite. Scale(0.5) makes the sprite half the size of its previous setting.
SetScale will scale the sprite by the factor given from its original size. This is similar to SetRotation vs. Rotate.
GetScale returns the current scaling factor that is being applied to the sprite.
void SetData(int which, int what)
int GetData(int which)
The constructor function lets you create an array of data values that will stay associated with this object. If you say you want 5 data values in the constructor, that gives you 5 integer storage spots numbered 0, 1, 2, 3, and 4. They are all automatically initialized to 0.
To set one of these values, use the SetData function. For example, to set storage spot 0 to the value 100, use the command:
mysprite.SetData(0,100);
To retrieve what's in storage spot 0, use the command:
value = mysprite.GetData(0);
void SetType(unsigned long t)
void ResetType(unsigned long t)
BOOL Type(unsigned long t)
These functions let you classify your sprites. Each one can remember what "type" of sprite it is. If you have an array of GMSprites, or if you use a GMSpriteList, when something happens to a particular sprite you can ask its type before deciding how to proceed.
The "type" is a 32-bit integer, and you can use the above functions to set, reset, and test each of the 32 bits. You should use powers of 2 for each of the types you define: 1, 2, 4, 8, 16, 32, etc. Type 1 might be "good guy". Type 2 might be "bad guy". Type 4 might be "green". Type 8 might be "blue". You set a GMSprite to be a "blue good guy" with the following:
sprite.SetType(1); sprite.SetType(8);
You could also use:
sprite.SetType(9); // 9 is 1 (good guy) plus 8 (blue)
You can test whether a sprite is blue with the following:
if (sprite.Type(8))
Note that you cannot use one test for a "blue good guy" with the following:
if (sprite.Type(9)) // WRONG!
You have to test each bit individually:
if (sprite.Type(1) && sprite.Type(8)) // RIGHT
ResetType turns off a bit. Suppose a sprite changes from "good guy" to "bad guy". You could use the following:
sprite.ResetType(1); // Turn off the "good guy" bit sprite.SetType(2); // Turn on the "bad guy" bit
This returns a pointer to the sprite's GMBehavior. You can write your GMBehaviors so that some of the traits can be modified. This is how you get to the behavior of a specific sprite. See the separate GMBehavior documentation for more about creating and using behaviors.
void NewBehavior(GMBehavior* pBehave)
This lets you assign a new GMBehavior to a sprite. The old GMBehavior is deleted, and the Init function for the new GMBehavior is called automatically. In general, each GMSprite should have its own GMBehavior, if one is used. You may have some very strange results if two GMSprites share the same instance of a GMBehavior.
void ChangeBitmap(const GMSprite &anotherSprite)
This lets you change the sprite's bitmap to that of another sprite. Everything about this sprite maintains its status, except the image used to display the sprite changes.
This function and the second constructor function both share bitmap information in memory with another sprite. A good strategy for using these might be to create the "master sprites" that hold the original bitmaps separately and perhaps not use them for actual display in your program. That way you won't accidentally delete the original copy of the image from memory.
An example where you could get into trouble with this function is if you created sprite A from a file with an image of a car. Then you create sprite B from sprite Ausing the second constructor option , so that B is also a car, but sharing A's bitmap. You create third sprite C from a file image of a truck. Then you decide to use ChangeBitmap to change A so it shares the truck image that C loaded into memory. Problem: A's car image is now gone, but B was sharing it!
GMCollision
Collided(GMSprite* pSprite[, int how, int radar, int dx, int dy])
GMCollision Collided(GMSprite& sprite[, int how, int radar, int
dx, int dy])
This function tests for a collision between this GMSprite and the GMSprite sent as a parameter. The return value is a GMCollision object. See the GMCollision documentation for full details and examples of this object. In simplest form, the GMCollision object evaluates to True or False if used in a condition, so you can write instructions like:
if (sprite1.Collided(sprite2))
The how parameter lets you choose between two collision methods. The default value of 0 tests to see if the bitmap rectangles overlap. If they overlap, a collision is returned.
If you set the how parameter to 1, the GMSprites are treated as circular, and the collision test checks the distance between the centers of the two sprites. If the distance is less than the combined radii of the sprites, a collision is "detected". When you create a GMSprite, a rough radius is computed (it has to be "rough" since the sprite is rectangular!). You can set the radius more precisely with the SetRadius function.
The radar parameter extends the reach of the collision detection. The radar value is the number of pixels beyond the rectangle or radius to look for a "collision". This provides a method for looking beyond the GMSprite to see if another sprite is nearby or if a collision is imminent. In that sense, it indeed lets collision detection act like a radar to see nearby objects. Further inspection of the returned GMCollision object tells you the direction of nearby objects detected by the "radar". The default value of radar is 0.
The dx and dy values let you offset the collision detection by a given number of pixels in the x and y directions. This lets you look ahead to see if a move in the given direction will cause a collision. You can prevent collisions by using these parameters with collision detection prior to a move, and then cancel the move if the returned GMCollision value is True. The defaults for dx and dy are 0.
The collision flags for the two sprites must have at least one matching pair of CollisionFlag bits set. For example, if they both have their collision flags set to 1, they can collide. If "sprite1" has its collision flag set to 1, and "sprite2" has its collision flag set to 2, they cannot collide.
A sprite with none of its collision flags set (CollisionFlags = 0) will not collide with anything.
int Collided(GMSpriteList* pSpriteList, GMCollisionReport
&report[, int how, int radar, int dx, int dy] )
int Collided(GMSpriteList& spritelist, GMCollisionReport
&report[, int how, int radar, int dx, int dy] )
This compares one GMSprite to all the sprites in a GMSpriteList. Collision detection between this sprite and each GMSprite in the GMSpriteList uses the same Collided function described above for a single GMSprite. The use of the parameters how, radar, dx, and dy are the same, as is the use of the CollisionFlags settings.
The integer that is returned by this function tells how many collisions were detected. A return value of 0 (or False) means that there was no collision. A return value of 2 means that this sprite collided with two sprites in the GMSpriteList.
A GMCollisionReport object is sent to this function as a reference variable. This function puts all the details of the exact collisions in the GMCollisionReport object. See the GMCollision documentation for a full description and examples.
Note that the GMCollisionReport object is created with a maximum number of GMCollisions that it can hold. By default the maximum is 16, but you can specify more or less when you create the GMCollisionReport object. If the number of actual collisions exceeds the capacity of the GMCollisionReport object, only the first collisions (up to the maximum) are returned.
This function will NOT return a collision between a GMSprite and itself, so there is no problem if the GMSprite calling this function is also in the GMSpriteList.
This sets the radius that is used when computing collisions using the circle method.
void SetCollisionFlags(unsigned long t)
void ResetCollisionFlags(unsigned long t)
unsigned long CollisionFlags
The SetCollisionFlags and ResetCollisionFlags functions work the same as the SetType and ResetType functions. Collisions are only detected if the two sprites being compared have at least one CollisionFlag set in common. (The CollisionFlags are "ANDed". If the result is non-zero, collision checking proceeds.) The CollisionFlags property is public, so you can also inspect and set its value directly. The default value of CollisionFlags is 1, so any two GMSprites will collide by default. Use ResetCollisionFlags(1) to prevent a sprite from colliding with anything.