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.
MoofWars/TCommandTimer.cp
/* |
File: TCommandTimer.cp |
Contains: The command section accomplishes two things for the game -- first, providing |
a standard clock to which all actions can be synchonized, and second, grabbing |
the state of the keyboard to pass along to those game parts that need it. |
This code implements a time manager task that periodically grabs the state of |
the keyboard. It stores these in a buffer where the main application task can |
retrieve it. |
We create a buffer for two seconds worth of commands, although in practice we'll |
almost never need more than about a 1/10 of a second. |
Eventually, this code will also probably need to deal with networking tasks. |
Written by: |
Copyright: Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
7/2/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
8/7/98 Timothy Carroll Moved code over from VBL to time manager task. |
1/26/97 Timothy Carroll Now explicitly includes MoofWars.h |
8/15/96 Timothy Carroll Initial Release |
*/ |
#include <Errors.h> |
#include <Timer.h> |
#include "AppConditionals.h" |
#include "Error Macros.h" |
#include "TCommandTimer.h" |
#if !TARGET_RT_MAC_CFM |
#error This code is not useable on classic 68K architectures. |
#endif |
struct CommandTimerData |
{ |
TMTask fTimer; |
Boolean fRunning; |
SInt16 fFramesPerSecond; |
SInt16 fBufferSize; |
TInputState *fCommandBuffer; |
// these hold our current locations in the buffer |
SInt16 fInCommandIndex; |
SInt16 fOutCommandIndex; |
TimerUPP fCommandTimerUPP; |
SInt32 timerDelay; |
} *CommandTimerPtr; |
// The actual timer task that gets called to retrieve inputs. |
void CommandTimer (TMTaskPtr recPtr); |
TCommandTimer::TCommandTimer (void) |
{ |
timerData = NULL; |
} |
TCommandTimer::~TCommandTimer (void) |
{ |
if (timerData == NULL) |
return; |
if (timerData->fRunning) |
this->AcceptCommands(false); |
if (timerData->fCommandTimerUPP != NULL) |
DisposeRoutineDescriptor (timerData->fCommandTimerUPP); |
if (timerData->fCommandBuffer != NULL) |
DisposePtr ((Ptr) timerData->fCommandBuffer); |
DisposePtr ((Ptr) timerData); |
timerData = NULL; |
} |
OSStatus TCommandTimer::Initialize (SInt16 framesDesired) |
{ |
OSStatus theErr = noErr; |
#if qDebugging |
if (timerData != NULL) |
SIGNAL_ERROR("\pError: TCommandTimer may only be initialized once"); |
#endif |
// Allocate all the data structures |
timerData = (CommandTimerData *) NewPtrClear (sizeof (CommandTimerData)); |
theErr = MemError(); |
FAIL_OSERR (theErr, "\pError: Failed to allocate CommandTimerData") |
timerData->fFramesPerSecond = framesDesired; |
timerData->fBufferSize = 2 * timerData->fFramesPerSecond; |
if (framesDesired == 0) // Special case -- we're not actually using a timer! |
goto cleanup; |
timerData->fCommandBuffer = (TInputState *) NewPtrClear (sizeof (TInputState) * timerData->fBufferSize); |
theErr = MemError(); |
FAIL_OSERR (theErr, "\pError: Failed to allocate commands buffer") |
timerData->fCommandTimerUPP = NewTimerProc (CommandTimer); |
if (timerData->fCommandTimerUPP == NULL) |
SIGNAL_ERROR ("\pError: Unable to allocate the timer UPP") |
// Set up the time manager data. We don't actually install the task until we activate the timer. |
timerData->fTimer.tmAddr = timerData->fCommandTimerUPP; |
//timerData->timerDelay = - (1000000/timerData->fFramesPerSecond); // amount of time per frame in microseconds |
timerData->timerDelay = 1000/timerData->fFramesPerSecond; |
goto cleanup; |
error: |
if (theErr == noErr) |
theErr = paramErr; |
// everything else is cleaned up by the regular destructor. |
cleanup: |
return theErr; |
} |
Boolean TCommandTimer::IsAcceptingCommands (void) |
{ |
#if qDebugging |
if (timerData == NULL) |
SIGNAL_ERROR("\pError: TCommandTimer must be initialized!"); |
#endif |
if (timerData->fFramesPerSecond == 0) |
return true; |
return timerData->fRunning; |
error: |
return false; |
} |
void TCommandTimer::AcceptCommands (Boolean commands) |
{ |
#if qDebugging |
if (timerData == NULL) |
SIGNAL_ERROR("\pError: TCommandTimer must be initialized!"); |
#endif |
if (timerData->fFramesPerSecond == 0) |
{ |
return; |
} |
if (timerData->fRunning == commands) |
return; |
if (commands) |
{ |
timerData->fRunning = true; |
// tn1063 documents that we need to clear these fields to make sure nothing wacky happens. |
timerData->fTimer.qLink = NULL; |
timerData->fTimer.tmReserved = 0; |
InsXTime ((QElemPtr) &timerData->fTimer); |
PrimeTime ((QElemPtr) &timerData->fTimer, timerData->timerDelay); |
} |
else |
{ |
timerData->fRunning = false; |
RmvTime((QElemPtr) &timerData->fTimer); |
} |
error: |
return; |
} |
void TCommandTimer::FlushCommands(void) |
{ |
#if qDebugging |
if (timerData == NULL) |
SIGNAL_ERROR("\pError: TCommandTimer must be initialized!"); |
if (timerData->fRunning) |
SIGNAL_ERROR ("\pError: TCommandTimer must not be accepting commands"); |
#endif |
if (timerData->fFramesPerSecond == 0) |
{ |
return; |
} |
timerData-> fInCommandIndex = timerData->fOutCommandIndex = 0; |
error: |
return; |
} |
Boolean TCommandTimer::IsCommandWaiting (void) |
{ |
#if qDebugging |
if (timerData == NULL) |
SIGNAL_ERROR("\pError: TCommandTimer must be initialized!"); |
#endif |
if (timerData->fFramesPerSecond == 0) |
{ |
return true; |
} |
if (timerData->fInCommandIndex != timerData->fOutCommandIndex) |
return true; |
error: |
return false; |
} |
Boolean TCommandTimer::RetrieveCommand (TInputState *command) |
{ |
Boolean peek; |
if (timerData->fFramesPerSecond == 0) |
{ |
GetKeys (command->keys); |
return true; |
} |
peek = this->PeekCommand (command); |
if (peek) |
timerData->fOutCommandIndex = (timerData->fOutCommandIndex +1) % (timerData->fBufferSize); |
return peek; |
} |
Boolean TCommandTimer::PeekCommand (TInputState *command) |
{ |
SInt16 index; |
#if qDebugging |
if (timerData == NULL) |
SIGNAL_ERROR("\pError: TCommandTimer must be initialized!"); |
#endif |
if (timerData->fFramesPerSecond == 0) |
{ |
GetKeys (command->keys); |
return true; |
} |
if (timerData->fInCommandIndex == timerData->fOutCommandIndex) |
return false; |
index = (timerData->fOutCommandIndex +1) % (timerData->fBufferSize); |
*command = (timerData->fCommandBuffer)[index]; |
return true; |
error: |
return false; |
} |
void CommandTimer (TMTaskPtr recPtr) |
{ |
CommandTimerData *timerData = (CommandTimerData *) recPtr; |
SInt16 index; |
if (!timerData->fRunning) |
return; |
index = (timerData->fInCommandIndex+1) % timerData->fBufferSize; |
if (index != timerData->fOutCommandIndex) |
{ |
timerData->fInCommandIndex = index; |
GetKeys (((timerData->fCommandBuffer)[index]).keys); |
} |
// Reset the timer |
PrimeTime((QElemPtr) &timerData->fTimer, timerData->timerDelay); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-10-14