MoofWars/TSpriteCollection.cp

/*
    File:       TSpriteCollection.cp
 
    Contains:   This class represents a group of related Sprites.  For example, all of the
                shots fired by a sprite.  In general, the various things that happen to
                sprites (moving, drawing, hit testing) all happen to a whole group at a time.
 
    Written by: Timothy Carroll 
 
    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
                
                1/23/97     Timothy Carroll Added include for Moofwars.h so that MrC will compile
                
                8/15/96     Timothy Carroll Initial Release
                
 
*/
 
 
#include "Moofwars.h"
#include "TSpriteCollection.h"
 
TSpriteCollection::TSpriteCollection(void)
{
    fSpriteListHead = NULL;
}
 
TSpriteCollection::~TSpriteCollection(void)
{
    TSprite *currentSprite, *nextSprite;
 
    nextSprite = fSpriteListHead;
    
    while (nextSprite != NULL)
    {
        currentSprite = nextSprite;
        nextSprite = currentSprite->fNextSprite;
        
        // When we delete a group, we make all of the sprites invisible.  This kills a warning
        // in the sprite code.
        currentSprite->SetVisibility(kInvisible);
        delete currentSprite;
    }
    
}
 
void TSpriteCollection::AddSprite (TSprite *theSprite)
{
    if (fSpriteListHead == NULL)
        fSpriteListHead = theSprite;
    else
    {   
        theSprite->fNextSprite = fSpriteListHead;
        fSpriteListHead->fPrevSprite = theSprite;
        theSprite->fPrevSprite = NULL;
        fSpriteListHead = theSprite;
    }
}
 
void TSpriteCollection::RemoveSprite (TSprite *theSprite)
{   
    TSprite *prevSprite, *nextSprite;
    
    prevSprite = theSprite->fPrevSprite;
    nextSprite = theSprite->fNextSprite;
    
    if (prevSprite == NULL)
        fSpriteListHead = nextSprite;
    else
        prevSprite->fNextSprite = nextSprite;
        
    if (nextSprite != NULL)
        nextSprite->fPrevSprite=prevSprite;
}
 
void TSpriteCollection::ProcessSpriteGroup (void)
{
    TSprite *currentSprite, *nextSprite;
 
    nextSprite = fSpriteListHead;
    
    // Just a comment about the structure of these loops.  We get the next
    // sprite before we call process sprite because process sprite can delete
    // the sprite which would throw our iterator off completely.
    
    // We're using the same structure in all of the other loops as well. However,
    // any routine that is disallowed from destroying a sprite (for example, 
    // drawing and erasing should probably never actually destroy a sprite), then
    // we can use a simpler structure:
    
    /*
    currentSprite = fSpriteListHead;
    while (currentSprite != NULL)
    {
        currentSprite->foo();
        currentSprite = currentSprite->fNextSprite;
    }
    */
    while (nextSprite != NULL)
    {
        currentSprite = nextSprite;
        nextSprite = currentSprite->fNextSprite;
        currentSprite->ProcessSprite();
    }
}
 
 
// HitTest routine currently uses some of the inner knowledge of how TSprite works.
// So if TSprite is modified, this routine may need to be altered.  This is an ugly
// routine, and I only do it here to cache some information.  I need to test and see
// if these optimizations are doing anything.
 
void TSpriteCollection::HitTest (TSpriteCollection *targetGroup)
{
    TSprite *currentTarget, *nextTarget, *currentSprite, *nextSprite;
    TGraphic *targetGraphic, *spriteGraphic;
    SInt32 targV, targH, spriteV, spriteH;
    
    nextTarget = targetGroup->fSpriteListHead;
    nextSprite = this->fSpriteListHead;
    
    // quick short circuit
    if (nextTarget == NULL || nextSprite == NULL)
        return;
    
    while (nextTarget != NULL)
    {
        currentTarget = nextTarget;
        nextTarget = currentTarget->fNextSprite;
 
        if (currentTarget->GetVisibility () == kInvisible)
            continue;
            
        targH = (currentTarget->fCoordX >> 16) - currentTarget->fXOffset;
        targV = (currentTarget->fCoordY >> 16) - currentTarget->fYOffset;
        targetGraphic = currentTarget->fSpriteImages->GetTGraphic(currentTarget->fFace);
        
        nextSprite = this->fSpriteListHead;
        while (nextSprite != NULL)
        {
            currentSprite = nextSprite;
            nextSprite = currentSprite->fNextSprite;
 
            if (currentSprite->GetVisibility () == kInvisible)
                continue;
            
            spriteH = (currentSprite->fCoordX >> 16) - currentSprite->fXOffset;
            spriteV = (currentSprite->fCoordY >> 16) - currentSprite->fYOffset;
            spriteGraphic = currentSprite->fSpriteImages->GetTGraphic(currentSprite->fFace);
            
            if (TGraphic::Intersect (targetGraphic, spriteGraphic, targV,targH,spriteV,spriteH))
            {
                currentTarget->Collision(currentSprite);
                currentSprite->Collision(currentTarget);
            }
        }
    }
}   
 
void TSpriteCollection::DrawSpriteGroup (void)
{
    TSprite *currentSprite, *nextSprite;
 
    nextSprite = fSpriteListHead;
    
    while (nextSprite != NULL)
    {
        currentSprite = nextSprite;
        nextSprite = currentSprite->fNextSprite;
        currentSprite->DrawSprite();
    }
 
}