home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-03-13 | 8.7 KB | 339 lines | [TEXT/MMCC] |
- // SpriteTools
- // Routines to be called from the engine and from SpriteHandlers
-
-
- #include "SpriteTools.h"
-
- /*
- MyNewGWorld: Creates a GWorld
- LoadFaceFromCicn: Loads a face
- PlotFace: Draws a face
-
- NewSprite: Creates a sprite
- DisposeSprite: Disposes a sprite
-
- KeepOnScreen: Performs border checks for a sprite
- RectSeparate: Moves two sprites apart
-
- */
-
-
- /*Global variables*/
-
- /* The window pointer */
- WindowPtr myWindow;
-
- /* A global pointer is the root of the entity list */
- SpritePtr gSpriteList = nil;
-
- /* GWorlds for the animation and background buffers */
- GrafPtr gOffScreen, gBackScreen;
-
-
-
- /*MyNewGWorld: Glue to NewGWorld*/
- /*I declare offscreenGWorld as GrafPtr to save us a bunch of typecasts later (in CopyBits).*/
- /*Most parameters to NewGWorld omitted - NewGWorld is smart enough to make the defaults useable.*/
-
- #include <QDOffScreen.h>
-
- void MyNewGWorld(GrafPtr *offscreenGWorld, Rect *boundsRect)
- {
- GDHandle saveGD;
- GWorldPtr savePort;
-
- GetGWorld(&savePort, &saveGD);
-
- if ( noErr != NewGWorld((GWorldPtr *)offscreenGWorld, 0, boundsRect, nil, nil, pixelsLocked) )
- DoError;
- /*We lock the offscreen pixmap so we can CopyBits and PlotCIcon to it.*/
- if ( LockPixels((*(CGrafPtr *)offscreenGWorld)->portPixMap) )
- ;
- /*Note: We should unlock it (UnlockPixels) when not animating, to avoid memory fragmentation,*/
- /*but you can bother with that later if it's a problem.*/
- SetGWorld(savePort, saveGD);
- }; /*MyNewGWorld*/
-
-
-
- GrafPtr LoadFaceFromCicn(short cicnId)
- {
- GrafPtr offscreenGWorld;
- CIconHandle theCicn;
- GDHandle saveGD;
- GWorldPtr savePort;
-
- GetGWorld(&savePort, &saveGD);
- theCicn = GetCIcon(cicnId);
- MyNewGWorld(&offscreenGWorld, &(**theCicn).iconMask.bounds);
- if ( offscreenGWorld != nil )
- {
- SetGWorld((GWorldPtr)offscreenGWorld, nil);
- PlotCIcon(&(**theCicn).iconMask.bounds, theCicn);
-
- /*I use the clipRgn for storing the mask region. This may seem dangerous,
- but when we aren't drawing in the GWorld anyway, it won't matter.*/
- if ( offscreenGWorld == nil )
- offscreenGWorld->clipRgn = NewRgn ();
- if ( noErr != BitMapToRegion(offscreenGWorld->clipRgn, &(**theCicn).iconMask) )/**/
- offscreenGWorld->clipRgn = nil;/*or DisposeRgn?*/
-
- DisposeCIcon(theCicn);
- }
- SetGWorld(savePort, saveGD);
- return offscreenGWorld;
- } /*LoadFaceFromCicn*/
-
-
- static RgnHandle gTmpRgn = nil;
-
- void PlotFace(GrafPtr theCicn, GrafPtr destPort, Point where)
- {
- GDHandle saveGD;
- GWorldPtr savePort;
- Rect bounds;
- RGBColor saveForeColor, saveBackColor;
-
- GetGWorld(&savePort, &saveGD);
- bounds = theCicn->portRect;
- OffsetRect(&bounds, where.h - bounds.left, where.v - bounds.top);
-
- if ( gTmpRgn == nil )
- gTmpRgn = NewRgn (); /*For top speed, we make this global, and create it only once!*/
- CopyRgn(theCicn->clipRgn, gTmpRgn);
- OffsetRgn(gTmpRgn, where.h, where.v);
- SetPort(destPort); /*I assume that the device is correctly set.*/
- GetForeColor(&saveForeColor);
- GetBackColor(&saveBackColor);
- ForeColor(blackColor);
- BackColor(whiteColor);
- CopyBits(&theCicn->portBits, &destPort->portBits, &theCicn->portRect, &bounds, srcCopy, gTmpRgn);
- RGBForeColor(&saveForeColor);
- RGBBackColor(&saveBackColor);
- SetGWorld(savePort, saveGD);
- } /*PlotFace*/
-
-
-
-
- /*************************************/
- /* Routines for sprite list handling */
- /*************************************/
-
-
- /* NewSprite allocates space for a new entity and puts it in the entity list */
-
- SpritePtr NewSprite()
- {
- SpritePtr who;
-
- who = (SpritePtr) NewPtr(sizeof(SpriteRecord));
- if (who == nil) return nil;
- if (gSpriteList != nil)
- {
- gSpriteList->prev = who;
- }
- who->next = gSpriteList;
- who->prev = nil;
- gSpriteList = who;
- return who;
- } /*NewSprite*/
-
-
- /* DisposeSprite removes an entity from the list and disposes it. */
-
- void DisposeSprite(SpritePtr who)
- {
- if (who == nil) return;
- if (who->next != nil)
- who->next->prev = who->prev;
- if (who->prev != nil)
- who->prev->next = who->next;
- if (who == gSpriteList)
- gSpriteList = who->next;
- DisposePtr((Ptr)who);
- } /*DisposeSprite*/
-
-
- /*** End of sprite handling routines ***/
-
-
- /* KeepOnScreen makes border checks to keep the sprite within the window.
- on a border hit, the speed is negated in order to make the sprite bounce.
- KeepOnScreen returns true if a border was hit. */
-
- Boolean KeepOnScreen(SpritePtr theSprite)
- {
- Boolean returnValue = false;
-
- if (theSprite->position.h < 0)
- {
- theSprite->position.h = 0;
- theSprite->speed.h = abs(theSprite->speed.h);
- returnValue = true;
- }
- if (theSprite->position.v < 0)
- {
- theSprite->position.v = 0;
- theSprite->speed.v = abs(theSprite->speed.v);
- returnValue = true;
- }
- if (theSprite->position.h > gOffScreen->portRect.right - theSprite->face->portRect.right)
- {
- theSprite->position.h = gOffScreen->portRect.right - theSprite->face->portRect.right;
- theSprite->speed.h = -abs(theSprite->speed.h);
- returnValue = true;
- }
- if (theSprite->position.v > gOffScreen->portRect.bottom - theSprite->face->portRect.bottom)
- {
- theSprite->position.v = gOffScreen->portRect.bottom - theSprite->face->portRect.bottom;
- theSprite->speed.v = -abs(theSprite->speed.v);
- returnValue = true;
- }
-
- return returnValue;
- } /*KeepOnScreen*/
-
-
- #ifdef _hasfixedpoint
- /*Same as above, but also modifies the fixedPointPosition field*/
- Boolean KeepOnScreenFixed(SpritePtr theSprite)
- {
- Boolean returnValue = false;
-
- if (theSprite->position.h < 0)
- {
- theSprite->position.h = 0;
- theSprite->fixedPointPosition.h = 0;
- theSprite->speed.h = abs(theSprite->speed.h);
- returnValue = true;
- }
- if (theSprite->position.v < 0)
- {
- theSprite->position.v = 0;
- theSprite->fixedPointPosition.v = 0;
- theSprite->speed.v = abs(theSprite->speed.v);
- returnValue = true;
- }
- if (theSprite->position.h > gOffScreen->portRect.right - theSprite->face->portRect.right)
- {
- theSprite->position.h = gOffScreen->portRect.right - theSprite->face->portRect.right;
- theSprite->fixedPointPosition.h = theSprite->position.h << 4;
- theSprite->speed.h = -abs(theSprite->speed.h);
- returnValue = true;
- }
- if (theSprite->position.v > gOffScreen->portRect.bottom - theSprite->face->portRect.bottom)
- {
- theSprite->position.v = gOffScreen->portRect.bottom - theSprite->face->portRect.bottom;
- theSprite->fixedPointPosition.v = theSprite->position.v << 4;
- theSprite->speed.v = -abs(theSprite->speed.v);
- returnValue = true;
- }
-
- return returnValue;
- } /*KeepOnScreenFixed*/
- #endif
-
-
- /* Moves two sprites apart, to separate them with respect to their bounding boxes. */
-
- short RectSeparate(SpritePtr theSprite, SpritePtr anotherSprite)
- {
- short distance[4], shortest, shortestDistance, i;
- Rect bounds1, bounds2;
-
- bounds1 = theSprite->face->portRect;
- OffsetRect(&bounds1, theSprite->position.h, theSprite->position.v);
-
- bounds2 = anotherSprite->face->portRect;
- OffsetRect(&bounds2, anotherSprite->position.h, anotherSprite->position.v);
-
- /*Calculate the distance to separate the sprites in every direction*/
- distance[0] = bounds2.top - bounds1.bottom; //up
- distance[1] = bounds2.bottom - bounds1.top; //down
- distance[2] = bounds2.right - bounds1.left; //right
- distance[3] = bounds2.left - bounds1.right; //left
-
- /*Find the shortest distance*/
- shortest = 0;
- shortestDistance = abs(distance[0]);
- for (i=1; i<4; i++)
- {
- if (abs(distance[i]) < shortestDistance)
- {
- shortest = i;
- shortestDistance = abs(distance[i]);
- }
- }
-
- /*Move the sprite in the appropriate direction*/
- switch (shortest)
- {
- case 0:
- case 1:
- theSprite->position.v += distance[shortest]; break;
- case 2:
- case 3:
- theSprite->position.h += distance[shortest]; break;
- }
- return shortest;
- } /*RectSeparate*/
-
-
- /* Random number from 0 to range-1 */
-
- short Rand(short range)
- {
- short roll;
-
- roll = Random();
- return (abs(roll) % range);
- } /*Rand*/
-
-
-
- /* Collision test using regions! */
-
- Boolean RegionHit(SpritePtr theSprite, SpritePtr anotherSprite)
- {
- RgnHandle faceRegion1, faceRegion2;
- Boolean result;
-
- faceRegion1 = NewRgn();
- faceRegion2 = NewRgn();
-
- CopyRgn(theSprite->face->clipRgn, faceRegion1);
- OffsetRgn(faceRegion1, theSprite->position.h, theSprite->position.v);
-
- CopyRgn(anotherSprite->face->clipRgn, faceRegion2);
- OffsetRgn(faceRegion2, anotherSprite->position.h, anotherSprite->position.v);
-
- SectRgn(faceRegion1, faceRegion2, faceRegion1);
- result = !EmptyRgn(faceRegion1);
-
- DisposeRgn(faceRegion1);
- DisposeRgn(faceRegion2);
-
- return result;
- } /*RegionHit*/
-
-
- /* Split a vector v into a component p parallel to another vector d,
- and a compionent n that is perpendicular to d. Useful for realistic
- collision handling! */
-
- void SplitVector(Point v, Point d, Point *p, Point *n)
- {
- long length2, dotProduct;
-
- length2 = d.h * d.h + d.v * d.v; /*Squared length of "d"*/
-
- dotProduct = v.h * d.h + v.v * d.v; /*Scalar product*/
-
- (*p).h = d.h * dotProduct / length2;
- (*p).v = d.v * dotProduct / length2;
- (*n).h = v.h - (*p).h;
- (*n).v = v.v - (*p).v;
- } /* SplitVector */
-
-