home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-06-26 | 13.2 KB | 314 lines | [TEXT/MMCC] |
- //==============================================================================================\\
- // ----------------------------------------------------------------------------------- \\
- // HelloWorld1.c version 1.0.0 copyright © 1993…1995 Jamie McCornack, john calhoun \\
- // ----------------------------------------------------------------------------------- \\
- // Demo program for Macintosh GameWriter 1.0.0, a training program… \\
- // …for beginning Mac game programmers. MGW1 includes MGWExterns1.h, MGWUtilities1.c,… \\
- // …MGWSound1.c, MGWGraphics1.c, MGWGraphicsBWLite1.c, HelloWorld.rsrc and an assortment… \\
- // …of demo programs; projects HelloWorld1.π etc. and source code files HelloWorld1.c etc. \\
- // A tutorial is available in Tricks of the Mac Game Programming Gurus, published… \\
- // …by Hayden Books, August 1995. \\
- // \\
- // This code is offered by the copyright holders for no fee and for whatever use… \\
- // …you care to make of it, but we do hope you remember where it came from. \\
- // \\
- // Please send bug reports to MacGameDev at America Online. macgamedev@aol.com \\
- // Suggestions and observations are also appreciated. \\
- // Updates and upgrades will be available now and then from the above e-mail address. \\
- //==============================================================================================\\
-
- // This program opens a window, displays a black and white background, and at first…
- // …mouseclick, runs a clam across the screen. At second mouseclick, the clam stops,…
- // …talks, and flaps its/his/her face for 40 frames. Then the program quits.
-
-
- #include "MGWExterns1.h"
-
- #define kPutInFront (WindowPtr)-1L
- #define kWaitTicks 4L // Sets the delay in Ticks between frames. Try 3. Try 2. Try 0.
- #define kStepLength 14 // Sets the distance in pixels between sprite moves.
- #define kFrontFace 0
- #define kBlinkFace 1
- #define kEehFace 2
- #define kOohFace 3
- #define kStepRightFace 4
- #define kWalkRightFace 5
- #define kRunRightFace 6
- #define kMaxFaces 7
- // The resource constants--with 'r' prefix like Apple wants them.}
- #define rFacesID 129 // The 'PICT' ID# where the views of the clam are located.}
- #define rMasksID 130 // The 'PICT' ID# where the clam masks are located.}
- #define rBackgroundID 128 // The 'PICT' ID# where the background picture is located.}
- #define rMainWindowID 128 // The 'WIND' resource ID# for the main window.}
-
- #define rHelloSndID 3000
- #define rFootstepSndID 3001
- #define rImpactSndID 3002
- #define rDizzySndID 3003
-
- typedef struct
- {
- Rect face;
- Rect mask;
- } tSpriteType;
-
-
- Rect bigPictureRect, facesRect, masksRect, clamIsAtRect, clamWasAtRect, clamComboRect;
- GrafPtr workPort, facesPort, masksPort, backgroundPort, mainWindow;
- Boolean itWorked;
- long targetTick;
- short thisSprite, thisFaceCounter;
-
- tSpriteType sprite[kMaxFaces];
-
- extern Boolean gUserWantsSound;
-
- //============================================================== Prototypes
-
- void InitAll(void);
- void OpenMainWindow (void);
- void SetTheRects(void);
- void SetThePorts(void);
- void ShowClam (void);
- void DoDelay (void);
- void RunRight (void);
- void LipSynch (void);
-
- //============================================================== Functions
-
- //-------------------------------------------------------------- InitAll
-
- void InitAll(void)
- {
- InitToolbox();
- gUserWantsSound = TRUE;
- InitializeForSound();
- SetTheRects(); // Since some of these Rects define fields in GrafPorts, set the rects…
- SetThePorts(); // …before setting the ports.
- thisSprite = kFrontFace;
- thisFaceCounter = 0;
- targetTick = TickCount() + kWaitTicks;
- }
-
- //-------------------------------------------------------------- OpenMainWindow
-
- void OpenMainWindow (void)
- {
- mainWindow = GetNewCWindow(128, 0L, kPutInFront); // Load window from resource.
- ShowWindow((GrafPtr)mainWindow); // Now display it.
- SetPort((GrafPtr)mainWindow); // Make its port current.
- ClipRect(&bigPictureRect); // Set its clip region.
- CopyRgn(mainWindow->clipRgn, mainWindow->visRgn); // Set its visRgn.
- ForeColor(blackColor); // Set its pen color to black.
- BackColor(whiteColor); // Set background color white.
- }
-
- //-------------------------------------------------------------- SetTheRects
-
- void SetTheRects(void) // The most tedious part of programming this type of game.
- {
- SetRect(&facesRect, 0, 0, 448, 64); // Size and shape of BitMap for the sprite faces.
- SetRect(&masksRect, 0, 0, 448, 32); // Size and shape of BitMap for the sprite masks.
- SetRect(&bigPictureRect, 0, 0, 512, 322); // The shape of the picture we'll put in the main window, workPort and backgroundPort.}
- SetRect(&clamIsAtRect, 200, 244, 232, 276); // The shape (32 x 32) of the images of Clem, and the position of the first image.}
- clamWasAtRect = clamIsAtRect; // Initializing clamIsAtRect...it has to start somewhere, and this is handy.}
- clamComboRect = clamIsAtRect;
- // And now, the tedium. In this sample, all we're doing is showing the clam running across the screen to the right.}
- // However, if you use ResEdit and look at 'PICT' 129 in Sample.rsrc, you'll find 28 different views of the clam.}
- // If we wanted the clam to run left too, and walk slowly, and face the user, and blink its eyes, we'd be calling…}
- // …SetRect 56 times--one face and one mask per sprite. And if we had jumping clams and rear views of clams…}
- // …and starfish and clamdiggers and other hazards of the clam environment, we might have hundreds of rects to set.}
- SetRect(&sprite[kFrontFace].face, 320, 32, 352, 64); // The shape and position of sprite[kFrontFace].face on facesPort.portBits.
- SetRect(&sprite[kFrontFace].mask, 320, 0, 352, 32); // The shape and position of sprite[kFrontFace].mask on masksPort.portBits.
- SetRect(&sprite[kBlinkFace].face, 320, 0, 352, 32); // Note that some faces (e.g. eyes open or closed) use the same mask,…
- SetRect(&sprite[kBlinkFace].mask, 320, 0, 352, 32); // …since they have the same silhouette.}
- SetRect(&sprite[kEehFace].face, 352, 0, 384, 32); // I could write more comments here, but setting these rects…
- SetRect(&sprite[kEehFace].mask, 352, 0, 384, 32); // …is already tedious enough without a bunch of busy-work.
- SetRect(&sprite[kOohFace].face, 352, 32, 384, 64);
- SetRect(&sprite[kOohFace].mask, 352, 0, 384, 32);
- SetRect(&sprite[kStepRightFace].face, 192, 0, 224, 32);
- SetRect(&sprite[kStepRightFace].mask, 192, 0, 224, 32);
- SetRect(&sprite[kWalkRightFace].face, 224, 0, 256, 32);
- SetRect(&sprite[kWalkRightFace].mask, 224, 0, 256, 32);
- SetRect(&sprite[kRunRightFace].face, 160, 0, 192, 32); // BTW, there are plenty more clam faces and masks in the 'PICT's,…
- SetRect(&sprite[kRunRightFace].mask, 160, 0, 192, 32); // …if you feel you need rect setting practice. :-)
- }
-
- //-------------------------------------------------------------- SetThePorts
-
- void SetThePorts(void) // Create the GrafPorts and load their .portBits fields.
- {
- // Create BitMap for sprite faces.
- CreateOffScreenBitMapLite (&facesRect, &facesPort);
- LoadGraphicLite (rFacesID); // …load 'PICT' resource for the clam faces.}
-
- // Create BitMap for sprite masks.
- CreateOffScreenBitMapLite (&masksRect, &masksPort);
- LoadGraphicLite (rMasksID); // …load 'PICT' resource for the masks of the clam.}
-
- // Create BitMap for background picture.
- CreateOffScreenBitMapLite (&bigPictureRect, &backgroundPort);
- LoadGraphicLite(rBackgroundID); // …load 'PICT' resource for the background picture.}
-
- // Create BitMap for off-screen assembly of images.
- CreateOffScreenBitMapLite (&bigPictureRect, &workPort);
-
- OpenMainWindow();
-
- //{This fills the main window with the background picture, so the user can see it.
- CopyBits(&((GrafPtr)backgroundPort)->portBits,
- &((GrafPtr)mainWindow)->portBits,
- &bigPictureRect, &bigPictureRect, srcCopy, mainWindow->visRgn);
-
- // This fills the workPort.portBits with the background picture, so updates can be done quickly.
- CopyBits(&((GrafPtr)backgroundPort)->portBits,
- &((GrafPtr)workPort)->portBits,
- &bigPictureRect, &bigPictureRect, srcCopy, mainWindow->visRgn);
- }
-
- //-------------------------------------------------------------- ShowClam
-
- void ShowClam (void) // Do the animation and make it appear on the screen.
- {
- CopyMask(&((GrafPtr)facesPort)->portBits,
- &((GrafPtr)masksPort)->portBits,
- &((GrafPtr)workPort)->portBits,
- &sprite[thisSprite].face,
- &sprite[thisSprite].mask,
- &clamIsAtRect);
- // Now there is an image of a clam in the new position in workMap. If we had done this work in…
- // mainWindow, we would have seen considerable flickering. Instead, we did it offscreen, and left the…
- // previous image of the clam visible on the screen while we worked.
-
- UnionRect(&clamWasAtRect, &clamIsAtRect, &clamComboRect);
- // Find the smallest rectangle which will cover the old position of the clam and the new.
-
- CopyBits(&((GrafPtr)workPort)->portBits,
- &(((GrafPtr)mainWindow)->portBits),
- &clamComboRect, &clamComboRect, srcCopy, mainWindow->visRgn);
- // Copy the contents of comboRect from workPort->portBits to the main window. In one swell foop, the old clam…}
- //…will be erased, and the new clam overlayed onto the background picture. Wallah! Flicker-free animation!}
-
- CopyBits(&((GrafPtr)backgroundPort)->portBits,
- &(((GrafPtr)workPort)->portBits),
- &clamIsAtRect, &clamIsAtRect, srcCopy, mainWindow->visRgn);
- // Restore the workPort by covering up our clam with the background it obscures.
- // This way, workPort->portBits is identical to backgroundPort->portBits,…
- // without having to copy the entire BitMap.
- }
-
- //-------------------------------------------------------------- DoDelay
-
- // This is the companion function to the above function (LogNextTick()).
- // We do nothing but loop until TickCount() catches up with (or passes) our…
- // global variable tickNext.
-
- void DoDelay (void)
- {
- do
- {
- }
- while (TickCount() < targetTick); // Loop until TickCount() catches up.
- targetTick = TickCount() + kWaitTicks;
- }
- //-------------------------------------------------------------- RunRight
-
- void RunRight (void) //Gives a sequence of views of the clam running to the right.
- {
- switch (thisSprite) //If the current view of the clam is…
- { case (kStepRightFace): // …kStepRightFace, then set thisSprite to…
- { thisSprite = kWalkRightFace; // …kWalkRightFace, and if it is currently…
- break; }
- case (kWalkRightFace): // …kWalkFace, then set it to…
- { thisSprite = kRunRightFace; // …kRunRightFace.
- PlayASound(rFootstepSndID, kHighestSoundPriority); // Note sound priority.
- break; }
- // And if it was neither kStepRightFace nor kWalkRightFace, then thisSprite was either…
- default : // …kRunRightFace, or what it was when RunRight()…
- thisSprite = kStepRightFace; // …was called, so we set it to kStepRightFace
- }
- clamWasAtRect = clamIsAtRect; // Store the clam's current position as its last position,…
- // …we'll be erasing it next time through the loop.
- OffsetRect(&clamIsAtRect, kStepLength, 0); // Set the clam's next position--it'll be…
- // …kStepLength pixels to the right of its last position.
- if (clamIsAtRect.left > 512) // If the clam has wandered out of sight,…
- { // …set the right border of clamIsAtRect…
- clamIsAtRect.right = 0; // …to the left edge of the screen…
- clamIsAtRect.left = -32; // …and move the left border of clamIsAtRect…
- } // …as needed to maintain its 32 x 32 shape & size.
- ShowClam(); // The actual animation routine!
- DoDelay(); // Do nothing for a while. In a real game, you'll want to use time more wisely.
- }
-
- //-------------------------------------------------------------- LipSynch
-
- void LipSynch (void)
- {
- while (thisFaceCounter < 40)
- {
- thisFaceCounter = thisFaceCounter + 1;
- switch (thisFaceCounter)
- { case (2):
- { thisSprite = kEehFace;
- break; }
- case (4):
- { thisSprite = kFrontFace;
- break; }
- case (5):
- { thisSprite = kOohFace;
- break; }
- case (9):
- { thisSprite = kEehFace;
- break; }
- case (11):
- { thisSprite = kOohFace;
- break; }
- case (13):
- { thisSprite = kFrontFace;
- break; }
- case (16):
- { thisSprite = kBlinkFace;
- break; }
- case (18):
- { thisSprite = kFrontFace;
- break; }
- case (35):
- { thisSprite = kBlinkFace;
- break; }
- case (38):
- { thisSprite = kFrontFace;
- break; }
- }
- ShowClam();
- DoDelay(); // Do nothing for a while, so the lips don't flap too fast.
- }
- }
-
- //-------------------------------------------------------------- main
- //----------------------------------------------------------------------
-
- void main(void)
- {
- InitAll();
- while (!Button()) // Before the user presses the mouse button, nothing happens.
- {
- }
- while (Button()) // When the user presses the mouse button, nothing happens.
- {
- }
- while (!Button()) // When the mouse button is released, continue to…
- {
- RunRight(); // …show the clam running right (duh),…
- }
- while (Button()) // …until the button is pushed.
- { // Do nothing until the button is released.
- }
- PlayASound(rHelloSndID, kMediumSoundPriority);
- LipSynch();
- CloseDownSound();
- } // And we're done.
-
- //------------------------------------------------------------------------------------------\\
- // End HelloWorld1.c \\
- //------------------------------------------------------------------------------------------\\
-