home *** CD-ROM | disk | FTP | other *** search
-
- #import <gamekit/gamekit.h>
-
- @interface GKStage(private)
- - _add:adds remove:removes with:theList; // helper for -doAddsAndRemoves
- @end
-
- @implementation GKStage
-
- - init
- {
- id ret = [super init];
- int i;
- for (i=0; i<=GK_ACTOR_TYPES; i++) {
- actors[i] = [[List alloc] init];
- addActors[i] = [[List alloc] init];
- removeActors[i] = [[List alloc] init];
- }
- collisionGroups = [[List alloc] init];
- addCollisionGroups = [[List alloc] init];
- removeCollisionGroups = [[List alloc] init];
- stageManager = nil;
- return ret;
- }
-
- - makeDirtPileForBuffer:(int)anInt
- { // you can use anInt to tweak each DirtPile differently to get better speed
- if (!anInt) return nil; // no DirtPile at level zero...
- return [[[DirtPile alloc] init] setAllDirty];
- }
-
- - setBufferType:(int)anInt to:aBuffer
- {
- if ((anInt < 0) || (anInt > GK_BUFFER_TYPES)) return nil;
- drawingBuffers[anInt] = aBuffer;
- if (!anInt) return self; // no dirtpile #0...
- if (!dirtPiles[anInt])
- dirtPiles[anInt] = [self makeDirtPileForBuffer:anInt];
- return self;
- }
-
- - dirtPileType:(int)anInt
- {
- if ((anInt < 0) || (anInt > GK_BUFFER_TYPES)) return nil;
- return dirtPiles[anInt];
- }
-
- - bufferType:(int)anInt
- {
- if ((anInt < 0) || (anInt > GK_BUFFER_TYPES)) return nil;
- return drawingBuffers[anInt];
- }
-
- - setStageManager:aManager { stageManager = aManager; return self; }
- - stageManager { return stageManager; }
-
- - actorListForType:(int)type
- {
- return actors[type];
- }
-
- - addActor:anActor ofType:(int)type
- { // hold on to it; we can't add while we're in the middle of a frame
- // since it may affect the List object during a sweep of its contents
- if ((type >= 0) && (type <= GK_ACTOR_TYPES))
- [addActors[type] addObject:anActor];
- return self;
- }
-
- - removeActor:anActor ofType:(int)type
- { // hold on to it; we can't remove while we're in the middle of a frame
- // since it may affect the List object during a sweep of its contents
- if ((type >= 0) && (type <= GK_ACTOR_TYPES))
- [removeActors[type] addObject:anActor];
- return self;
- }
-
- - addCollisionGroup:aGroup
- {
- [addCollisionGroups addObject:aGroup];
- return self;
- }
-
- - removeCollisionGroup:aGroup
- {
- [removeCollisionGroups addObject:aGroup];
- return self;
- }
-
- - collisionGroups { return collisionGroups; }
- - findCollisionGroupWithTag:(int)anInt;
- {
- int i;
- for (i=0; i<[collisionGroups count]; i++) {
- id group = [collisionGroups objectAt:i];
- if ([group tag] == anInt) return group;
- }
- return nil;
- }
-
- - _add:adds remove:removes with:theList level:(int)level
- {
- int j;
- for (j=0; j<[adds count]; j++) {
- id objectToAdd = [adds objectAt:j];
- if (level >= 0) {
- if ([objectToAdd respondsTo:@selector(setDrawingLevel:)])
- [objectToAdd setDrawingLevel:level];
- if ([objectToAdd respondsTo:@selector(setStage:)])
- [objectToAdd setStage:self];
- }
- [theList addObject:objectToAdd];
- }
- for (j=0; j<[removes count]; j++) {
- id anActor = [removes objectAt:j];
- [theList removeObject:anActor];
- [stageManager addDeadActor:anActor];
- // if not using a manager, free the object...
- if (!stageManager) [anActor free];
- }
- return self;
- }
-
- - doAddsAndRemoves
- { // _now_ it can take effect (actors at all levels and collision groups
- int i;
- for (i=0; i<=GK_ACTOR_TYPES; i++) {
- [self _add:addActors[i] remove:removeActors[i] with:actors[i] level:i];
- }
- [self _add:addCollisionGroups remove:removeCollisionGroups
- with:collisionGroups level:(-1)];
- return self;
- }
-
- - doOneFrame
- {
- [self calculateMoves];
- [self calculateCollisions];
- if ([self doRender]) [self render];
- [self doAddsAndRemoves];
- return self;
- }
-
- - (BOOL)doRender { return YES; }
-
- - calculateMoves
- {
- int i;
- for (i=0; i<=GK_ACTOR_TYPES; i++) {
- [actors[i] makeObjectsPerform:@selector(move:) with:self];
- }
- return self;
- }
-
- - calculateCollisions
- {
- [collisionGroups makeObjectsPerform:@selector(calculateCollisions:)
- with:self];
- return self;
- }
-
- - render
- {
- register int i, j, k, t, lastLevel = 0; // lastLevel is the number of the
- // next lower buffer level. If a buffer doesn't exists, this allows us
- // to skip it and use the next lowest (existing) buffer level.
- // The actors will only move if the GameView is in the normal state
- // and unpaused. They can still advance the render state machine, though.
- BOOL shouldMove = ((![drawingBuffers[GK_SCREEN_BUFFER] isPaused]) &&
- ([drawingBuffers[GK_SCREEN_BUFFER] realGameState] == NORMALSTATE));
- NXPoint offset;
- [drawingBuffers[GK_SCREEN_BUFFER] getOffset:&offset];
- // Loop through each buffer, allowing changes to propagate from
- // the lowest to the highest buffer
- for (i=1; i<GK_BUFFER_TYPES; i++) {
- // Make sure that this buffer level exists; if not, we skip to the
- // next level and push all actors in this level up to the next level.
- if (drawingBuffers[i]) {
- id thisDirtPile = nil;
- // find the DirtPile for the next highest level. (If a level
- // doesn't have a buffer, we need to effectively skip it.)
- for (k=i+1; k<GK_BUFFER_TYPES; k++) { // if on last buffer,
- // (top level) loop is skipped, and so thisDirtPile = nil
- if (dirtPiles[k]) {
- thisDirtPile = dirtPiles[k];
- break;
- } }
- [drawingBuffers[i] lockFocus];
- for (k=lastLevel+1; k<=i; k++) { // loop makes sure that any
- // actors on a level w/o a buffer still get drawn and erased,
- // but in the next higher buffer level.
-
- // erase everything on this level by marking it dirty in
- // the DirtPile for this level: each actor sends it's
- // most recently drawn bounding box to the DirtPile.
- [actors[k] makeObjectsPerform:@selector(eraseInDirtPile:)
- with:dirtPiles[i]];
- }
- // Now, copy everything from the level below up to this level,
- // using the DirtPile for efficiency. This makes all erasing
- // happen at once.
- [dirtPiles[i] sendDirtTo:thisDirtPile]; // next level needs to
- // know of all changes on lower levels.
- [dirtPiles[i] doRedraw:drawingBuffers[lastLevel]]; // go back
- // to the most recent buffer
- for (k=lastLevel+1; k<=i; k++) { // loop makes sure that any
- // actors that are in a level w/o a buffer still get drawn,
- // but in the next highest buffer level.
-
- // Next draw anything that gets drawn at this level (any actors
- // that are here.
- t = [actors[k] count]; // faster than a message call each
- // time thru the loop; requires that the list not change
- // during the render, however!!!
- for (j=0; j<t; j++) { // loop ourselves to be
- // sure objects are called from #0 to highest; allows user
- // to add actors in the order they are expected to be drawn
- // (or sort the actors' drawing order)
- [[actors[k] objectAt:j] renderAt:&offset
- move:shouldMove withDirtPile:thisDirtPile];
- } }
- [drawingBuffers[i] unlockFocus];
- lastLevel = i;
- } }
- return self;
- }
-
- @end
-