Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
GameSource/TankSprite.c
#include "ZAMProtos.h" |
#include "TankSprite.h" |
#include "GameSounds.h" |
#include "SpriteFrameRates.h" |
spriteLayerPtr gTankLayer[kNumTankSprites]; |
frameSetPtr gTankFrameSetList[kNumDirections]; |
spritePtr gTankSprites[kNumTankSprites]; |
tankInfoRec gTankInfo[kNumTankSprites]; |
xthing gTankSynchTask; |
xthing gTankIncidentalSoundTask; |
#define kSlopTolerance 6 |
long gDeadTime; |
void CheckTankDead(void) |
/* |
This is called in the main loop to kill all sounds and play the you lose sound. |
*/ |
{ |
tankInfoRec *ti; |
if(gDead == true) { |
PlaySndAsynchChannelNow(kYouLose, kMusicChan, kHighPriority+20); |
gDead = false; |
} |
} |
void TankColissionHandler( spritePtr tank, spritePtr obj, Rect *colArea) |
/* |
The sprite manager calls this when a missile hits a tank. |
This makes sure the hit was a good hit, and decrements the tank hit counter |
*/ |
{ |
tankInfoRec *ti; |
if( (RECT_WD(*colArea) >= kCollThresh) && (RECT_HT(*colArea) >= kCollThresh) ) { |
ti = (tankInfoRec*)tank->refCon; |
ti->damage++; |
if(ti->damage > 8) { |
obj->spriteFlags |= kRemoteKilled; |
ti->damage = 0; |
} else |
PlaySndAsynchChannel(kBadFireSnd, kFlightChan, kStdPriority); |
} |
} |
void SynchronizeTank( gamePtr game, fixPt *loc, short direction, short speed) |
/* |
This is where the remote tank is updated from the AppleEvent |
*/ |
{ |
spritePtr tank; |
tankInfoRec *ti; |
Boolean reAdjustNeeded = false; |
tank = gTankSprites[game->remoteTankIndex]; |
if(abs((loc->h - tank->loc.h)) > kSlopTolerance) { |
reAdjustNeeded = true; |
} else if(abs((loc->v - tank->loc.v)) > kSlopTolerance) { |
reAdjustNeeded = true; |
} |
if(reAdjustNeeded) { |
tank->remoteLoc = *loc; |
tank->moveTask.taskFlag = true; |
} |
ti = (tankInfoRec *)tank->refCon; |
if(ti->speed != speed) { |
SetTankSpeed(tank, speed); |
} |
if(ti->dir != direction) { |
ti->dir = direction; |
SetSpriteFrameSet(tank,gTankFrameSetList[ti->dir]); |
tank->spriteFlags |= kNeedsToBeDrawn | kNeedsToBeErased; |
tank->ownerLayer->layerFlags |= kLayerDirty; |
if( ti->speed != 0) { |
DirectionToVelocity( ti->dir, &tank->vel); |
if(ti->speed != 0) { |
DirectionToVelocity(ti->dir, &tank->vel); |
if(ti->speed > 1) { |
tank->vel.h = FixMul(tank->vel.h,ff(ti->speed)); |
tank->vel.v = FixMul(tank->vel.v,ff(ti->speed)); |
} |
} else { |
tank->vel.h = 0; |
tank->vel.v = 0; |
} |
} |
} |
} |
void RotateTank(spritePtr spr, short dir) |
{ |
tankInfoRec *tInfo; |
frameCellPtr pFrameCell; |
tInfo = (tankInfoRec*)spr->refCon; |
if(dir) { |
tInfo->dir += dir; |
if(tInfo->dir >= kNumDirections) |
tInfo->dir = 0; |
if(tInfo->dir < 0) |
tInfo->dir = kNumDirections -1; |
SetSpriteFrameSet(spr,gTankFrameSetList[tInfo->dir]); |
spr->spriteFlags |= kNeedsToBeDrawn | kNeedsToBeErased; |
spr->ownerLayer->layerFlags |= kLayerDirty; |
} |
} |
void SetTankSpeed(spritePtr spr, short speed) |
{ |
tankInfoRec *tInfo; |
fixPt vel; |
tInfo = (tankInfoRec*)spr->refCon; |
tInfo->speed += speed; |
if(tInfo->speed > kMaxSpeed) |
tInfo->speed = kMaxSpeed; |
if(tInfo->speed < 0) |
tInfo->speed = 0; |
if(tInfo->speed != 0) { |
DirectionToVelocity(tInfo->dir, &vel); |
spr->vel.h += vel.h; |
spr->vel.v += vel.v; |
} else { |
spr->vel.h = 0; |
spr->vel.v = 0; |
} |
} |
Boolean TankFrameTask(spritePtr spr, frameCellPtr curFrame) |
/* |
Since this is a global frame task, curFrame is set to nil |
if being called before the frame has been updated. |
curFrame will be set to -1 if being called after the frame has already |
been updated by the sprite manager. |
*/ |
{ |
short dir = 0; |
if(KeyIsDown(kRotateLeftKeyCode)) |
dir = -1; |
else if(KeyIsDown(kRotateRightKeyCode)) |
dir = 1; |
if(dir) { |
RotateTank(spr, dir); |
} |
return true; |
} |
Boolean TankMoveTask(spritePtr spr) |
{ |
char key; |
short speed = 0; |
tankInfoRec *tInfo; |
short dir= 0; |
tInfo = (tankInfoRec*)spr->refCon; |
if(KeyIsDown(kAccelerateKeyCode)) |
speed = 1; |
else if(KeyIsDown(kDecelerateKeyCode)) |
speed = -1; |
if(KeyIsDown(kFireKeyCode)) { |
FireMissile( tInfo->dir, spr->loc.h, spr->loc.v, false,0); |
} |
if(speed) { |
SetTankSpeed(spr, speed); |
} |
return true; |
} |
void LoadTankSprites(gamePtr game) |
{ |
OSErr err; |
short ref; |
short i,iconID; |
frameSetPtr missileFrameSet; |
ref = OpenResFile("\pnuTankFrames.rsrc"); |
if(err = ResError()) { |
ErrMsgCode("\pCould Not Open MissileFrames file!.",err); |
ExitToShell(); |
} |
if(err == noErr) { |
for(i = 0; i < kNumDirections; i ++) { |
if(err == noErr) { |
iconID = kTankBaseID + i; |
// err = CreateColorIconFrameSet(&gTankFrameSetList[i], iconID, kNumTankFrames); |
err = CreatePICTIconFrameSet(&gTankFrameSetList[i], iconID, kNumTankFrames); |
if(err != noErr) { |
ErrMsgCode("\pCreateColorIconFrameSet failed.",err); |
} |
if(err == noErr) |
SetFrameSetCTSeed(gTankFrameSetList[i],game->gameCTSeed); |
} |
} |
} |
CloseResFile(ref); |
for(i = 0; i < kNumTankSprites; i++) { |
err = CreateSpriteLayer(&gTankLayer[i], |
game->tween, |
game->backdrop, |
game->gameWind); |
if(err != noErr) { |
ErrMsgCode("\pCreateSpriteLayer failed!",err); |
ExitToShell(); |
} |
err = CreateEmptySprite(gTankLayer[i], |
&gTankSprites[i], /* returned sprite here */ |
kFrameTaskBeforeUpdate /* sprite flags */ |
+ kConstrainToRect, |
kTankFrameTime, /* time between frame change */ |
kTankMoveTime, /* time between movement */ |
(long)&gTankInfo[i]); |
if(err != noErr) { |
ErrMsgCode("\pCreateEmptySprite failed.",err); |
} |
if(err == noErr) { |
err = CreateEmptyFrameSet(&gTankSprites[i]->frameList,kNumTankFrames); |
if(err != noErr) { |
ErrMsgCode("\pCreateEmptyFrameSet failed.",err); |
} |
} |
if(err == noErr) { |
SetSpriteFrameSet(gTankSprites[i],gTankFrameSetList[4]); |
gTankSprites[i]->refCon = (long)&gTankInfo[i]; |
gTankInfo[i].dir = 4; |
gTankInfo[i].speed = 0; |
gTankInfo[i].game = game; |
gTankInfo[i].damage = 0; |
gTankSprites[i]->vel.h = 0; |
gTankSprites[i]->vel.v = 0; |
gTankSprites[i]->visible = true; |
gTankSprites[i]->constrainRect = game->gameArea; |
} |
} |
} |
void PlaceTankSprites(gamePtr game) |
{ |
register short localIndex; |
register short remoteIndex; |
tankInfoRec *ti; |
localIndex = game->localTankIndex; |
remoteIndex = game->remoteTankIndex; |
gTankSprites[localIndex]->frameHandler = (frameProc)TankFrameTask; |
gTankSprites[localIndex]->moveHandler = (moveProc)TankMoveTask; |
gTankSprites[localIndex]->spriteFlags |= kNeedsToBeDrawn | kNeedsToBeErased; |
gTankLayer[localIndex]->layerFlags |= kLayerDirty; |
gTankSprites[remoteIndex]->spriteFlags |= kRemoteSprite | kRemoteUpdate |
| kNeedsToBeDrawn | kNeedsToBeErased; |
gTankLayer[remoteIndex]->layerFlags |= kLayerDirty; |
if(game->localTankIndex == 0) { |
SetSpriteLoc(gTankSprites[localIndex], ff(40), ff(100)); |
SetSpriteLoc(gTankSprites[remoteIndex], ff(460), ff(100)); |
} else { |
SetSpriteLoc(gTankSprites[remoteIndex], ff(40), ff(100)); |
SetSpriteLoc(gTankSprites[localIndex], ff(460), ff(100)); |
} |
StartSpriteAction(gTankSprites[localIndex]); |
gTankSprites[remoteIndex]->collideHandler = (collisionProc)TankColissionHandler; |
#ifndef NO_NET |
StartRemoteSpriteAction(gTankSprites[game->remoteTankIndex]); |
StartXThing(&gTankSynchTask, kSynchTime, (updateProc)TankSynchTask, |
(long)gTankSprites[game->localTankIndex]); |
#endif |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14