//Sets which rectangular area to pick gfx from inside the 'PICT' resources
void SetTheRects(){
SetRect(&batCarRect, 0, 0, 64, 40);
SetRect(&batCarMaskRect, 0, 0, 64, 40);
SetRect(&bigPictureRect, 0, 0, 512, 342);
SetRect(&batCarIsAtRect, 200, 200, 240, 240);
batCarWasAtRect = batCarIsAtRect;
batCarComboRect = batCarIsAtRect;
//Individual gfx faces and masks
SetRect(&batCarSprite[0].face, 0, 0, 32, 40);
SetRect(&batCarSprite[0].mask, 32, 0, 64, 40);
}
Here's the function where I think the crash (again, only under System 6) occurs.
Here's the full source code where main is located:
#include "Misc.h"
#include "Offscreen.h"
#include "Sprites.h"
/*
* SmoothAnim2019 - December 2nd 2019 by Michael Juneau
* Attempt at creating smooth animation with a sprite which does not destroy the background
* by using 4 grafPorts: the screen, a pristine background backup, a sprite and its mask.
* Based on Chapter 0 of "Tricks of the Mac Game Programming Gurus
*/
/********************* defines ***/
#define rBatCarID 128 //'PICT' ID# of the batcar
#define rBatCarMaskID 128 //'PICT' ID# of the batcar mask
#define rBackgroundID 129 //'PICT' ID# of the street background
#define kPutInFront (WindowPtr)-1L
#define kWaitTicks 3L // Sets the delay in Ticks between frames. Try 3. Try 2. Try 0.
/********************* typedef tSpriteType ***/
typedef struct{
Rect face;
Rect mask;
} tSpriteType;
/********************* Global Variables ***/
Rect bigPictureRect, //Rectangle of the refreshing window area
batCarRect, //batCar
batCarMaskRect, //batCar mask
batCarIsAtRect, //current location of batcar
batCarWasAtRect, //old location of batcar
batCarComboRect; //current and old locations, union of
GrafPtr workPort, //pointer to offscreen working gfx assembling area
facesPort, //copy of characters gfx
maskPort, //copy of masks gfx
backgroundPort, //copy of background (street)
mainWindow; //copy of main window
tSpriteType batCarSprite[1]; //struct containing the rects of the batcar and it mask,
//currently ONE frame
long targetTick;
int carSpeed = 10;
/********************* Function Prototypes ***/
void InitBorderlessAndPort(void);
void OpenMainWindow(void);
void SetTheRects(void);
void SetThePorts(void);
void CleanUpAndLeave(void);
void GameLoop(void);
void DriveBatCar(void);
void DoDelay(void);
void ShowBatCar(void);
/********************* Function definitions ***/
void InitBorderlessAndPort(){
InitMacStuff(); //Inits the &qd.thePort grafPort (ie screen bits) and a bunch of managers
HideMyMenuBar();
mainWindow = MacPlusArea(gray,white,false); //takes a full screen in 512x342 if on a compact mac; otherwise, centers it
}
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.
}
//Sets which rectangular area to pick gfx from inside the 'PICT' resources
void SetTheRects(){
SetRect(&batCarRect, 0, 0, 64, 40);
SetRect(&batCarMaskRect, 0, 0, 64, 40);
SetRect(&bigPictureRect, 0, 0, 512, 342);
SetRect(&batCarIsAtRect, 200, 200, 240, 240);
batCarWasAtRect = batCarIsAtRect;
batCarComboRect = batCarIsAtRect;
//Individual gfx faces and masks
SetRect(&batCarSprite[0].face, 0, 0, 32, 40);
SetRect(&batCarSprite[0].mask, 32, 0, 64, 40);
}
void SetThePorts(void){
//Create BitMap for batcar gfx
CreateOffScreenBitMapLite (&batCarRect, &facesPort);
LoadGraphicLite (rBatCarID);
//Create BitMap for batcar mask gfx
CreateOffScreenBitMapLite (&batCarMaskRect, &maskPort);
LoadGraphicLite (rBatCarMaskID);
// Create BitMap for background picture.
CreateOffScreenBitMapLite (&bigPictureRect, &backgroundPort);
LoadGraphicLite(rBackgroundID);
// Create BitMap for off-screen assembly of images.
CreateOffScreenBitMapLite (&bigPictureRect, &workPort);
//OpenMainWindow(); //doesn't seem to be necessary; cut.
//{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);
}
void CleanUpAndLeave(){
DisposeWindow(mainWindow);
ShowMyMenuBar();
}
void DriveBatCar(){
batCarWasAtRect = batCarIsAtRect;
OffsetRect(&batCarIsAtRect, 0, -carSpeed);
if(batCarIsAtRect.bottom < 0){
batCarIsAtRect.top = 342;
batCarIsAtRect.bottom = 382;
}
ShowBatCar();
DoDelay();
}
void ShowBatCar (void) // Do the animation and make it appear on the screen.
{
CopyMask(&((GrafPtr)facesPort)->portBits,
&((GrafPtr)maskPort)->portBits,
&((GrafPtr)workPort)->portBits,
&batCarSprite[0].face,
&batCarSprite[0].mask,
&batCarIsAtRect);
UnionRect(&batCarWasAtRect, &batCarIsAtRect, &batCarComboRect);
CopyBits(&((GrafPtr)workPort)->portBits,
&(((GrafPtr)mainWindow)->portBits),
&batCarComboRect, &batCarComboRect, srcCopy, mainWindow->visRgn);
CopyBits(&((GrafPtr)backgroundPort)->portBits,
&(((GrafPtr)workPort)->portBits),
&batCarIsAtRect, &batCarIsAtRect, srcCopy, mainWindow->visRgn);
}
void DoDelay (void)
{
do
{
}
while (TickCount() < targetTick); // Loop until TickCount() catches up.
targetTick = TickCount() + kWaitTicks;
}
void GameLoop(){
while(!Button()){
DriveBatCar();
}
while(Button()){
}
while(!Button()){
}
}
/********************** Main Function ****/
void main(void){
InitBorderlessAndPort();
SetTheRects();
//SetThePorts();
//GameLoop();
CleanUpAndLeave();
}
Here's how I force a 512x342 graphic area even with macs that are newer than a compact Mac:
Code:
/*------ Hide Menu bar
1) HideMyMenuBar(); Explicit use
2) ShowMyMenuBar(); Explicit use
----------*/
void HideMyMenuBar(void)
{
Rect rcMBar;
short *setMBarHeight;
setMBarHeight=(short *)0x0BAA;
if ( gs_hrgnMBar == 0L) {
gs_dyMBar = GetMBarHeight();
*setMBarHeight=0;
rcMBar = qd.screenBits.bounds;
rcMBar.bottom = rcMBar.top + gs_dyMBar;
gs_hrgnMBar = NewRgn();
RectRgn( gs_hrgnMBar, &rcMBar );
UnionRgn( GetGrayRgn(), gs_hrgnMBar, GetGrayRgn() );
PaintOne(nil,gs_hrgnMBar);
}
}
void ShowMyMenuBar(void)
{
short *setMBarHeight;
setMBarHeight=(short *)0x0BAA;
if( gs_hrgnMBar) {
*setMBarHeight=gs_dyMBar;
DiffRgn(GetGrayRgn(), gs_hrgnMBar, GetGrayRgn());
DisposeRgn(gs_hrgnMBar);
gs_hrgnMBar=0L;
}
}
/*------- End of Hide Menu Bar -------*/
/*--------- Ranged Random -----------*/
unsigned short rangeRandom( unsigned short min, unsigned short max )
/* the function will calculate the correct max and min values */
{
long range;
long randomNumber;
range = MAX(min,max) - MIN(min,max) + 1;
randomNumber=Random();
randomNumber=ABS(randomNumber);
return( (randomNumber * range)/kRandomUpperLimit+min);
}
/*--------- End of Ranged Random -----------*/
/* Mac Plus Area - creates a 512x342 screen centered in the middle, with correct
Clip region. If the screen is larger than that, makes a border with borderPat as its
pattern. */
GrafPtr MacPlusArea(Pattern borderPat, Pattern middlePat,Boolean wantMenus)
{
WindowPtr window;
Rect r;
r=qd.screenBits.bounds;
r.top=kMenuBarHeight;
if(kScreenWidth <=512 && kScreenHeight <=342)
{
WholeScreen(middlePat,wantMenus);
}
else
{
if(wantMenus) window=NewWindow(nil,&r,nil,true,plainDBox,kMoveToFront,false,0);
else window=NewWindow(nil,&(qd.screenBits.bounds),nil,true,plainDBox,kMoveToFront,false,0);
SetPort(window);
FillRect(&(window->portRect), borderPat);
if(wantMenus) {
PortSize(512,362);
MovePortTo((kScreenWidth-512)/2,(kScreenHeight-342-kMenuBarHeight)/2);
}
else {
MovePortTo((kScreenWidth-512)/2,(kScreenHeight-342)/2);
PortSize(512,342);
}
ClipRect(&(window->portRect));
CLS(middlePat,wantMenus);
}
CopyRgn(window->clipRgn, window->visRgn);
return (GrafPtr)window;
}
/*--------- CLS ---------------*/
void CLS(Pattern thePat, Boolean wantMenus)
{
Rect r;
WindowPtr window;
GetPort(&window);
r=window->portRect;
r.top=kMenuBarHeight;
if(wantMenus) FillRect(&r,thePat);
else FillRect(&(window->portRect),thePat);
}
/*--------- End of CLS --------*/
/* WholeScreen - Will create a screen-sized featureless window filled with the pattern
of your choice. You are responsible to deal with any previous windows and ports
NOTE: use DisposeWindow to get rid of it */
void WholeScreen(Pattern thePat, Boolean wantMenus)
{
WindowPtr window;
Rect r;
r=qd.screenBits.bounds;
r.top=kMenuBarHeight;
if(wantMenus) window=NewWindow(nil,&r,nil,true,plainDBox,kMoveToFront,false,0);
else window=NewWindow(nil,&(qd.screenBits.bounds),nil,true,plainDBox,kMoveToFront,false,0);
SetPort(window);
FillRect(&(window->portRect), thePat);
}
short OldLoadFile(SFTypeList myTypes)
{
SFReply reply; //GetFile reply
short openResult=0; //trails file number
long count; //used to read the data
Point where={50,50};//SFGetFile dialog location
SFGetFile(where,"\pSelect a file",0L,1,myTypes,0L,&reply);
if(reply.good) FSOpen(reply.fName,reply.vRefNum,&openResult);
return openResult;
}
int GetScreenWidth(void)
{
return qd.screenBits.bounds.right-qd.screenBits.bounds.left;
}
int GetScreenHeight(void)
{
return qd.screenBits.bounds.bottom-qd.screenBits.bounds.top;
}