Search Tips Advanced Search |
| Delphi Graphics and Game Programming Exposed with DirectX 7.0 by John Ayres Wordware Publishing, Inc. ISBN: 1556226373 Pub Date: 12/01/99
Search this book:
Previous | Table of Contents | Next
#### Pixel Overlap Comparison The bounding box method of collision detection can easily be extended to provide very accurate pixel level collision detection. Basically, a standard bounding box collision detection is performed. It is necessary that the bounding boxes of the sprites be the same dimensions as the sprite images (actually, they could be different, but the resulting offset math makes the pixel offset determinations cumbersome). Once a collision has occurred, it is necessary to determine the exact rectangular intersection area, which is conveniently reported by the IntersectRect function. The coordinates of the upper left corner of the rectangle are subtracted from the coordinates of the upper left corner of each of the sprite image positions. This will give a starting offset of the intersection rectangle relative to the sprites. From this starting offset within the sprite images, a simple embedded loop is used to walk through the pixels in each sprite image, comparing the colors of the pixels in the relative position of each sprite as determined by the intersection rectangle. If any non-transparent pixels match up, then the sprites overlap and a collision has occurred, as illustrated below. Figure 6-8: Pixel level collision detection This algorithm provides very accurate collision detection. Due to its nature, we must directly access the surface memory as we covered above. This is a slow collision detection technique, but it could possibly be optimized using assembly language. However, for small numbers of sprites, the performance penalty is minimal. The following example demonstrates pixel-accurate collision detection. Listing 6-6: Collision detection at the pixel level
    procedure TfrmDXAppMain.DrawSurfaces;

    var

      Intersection, Area: TRect;

      iCount: Integer;

      Sprite1SurfaceDesc,

      Sprite2SurfaceDesc: TDDSurfaceDesc2;

      Sprite1Mem, Sprite2Mem: PBytePtr;

      iRow, iCol: Integer;

      SrfcDC: HDC;

      Hit: Boolean;

      {this function moves and draws a sprite}

      procedure MoveSprite(var Sprite: TSprite);

      var

        SrfcDC: HDC;

        TempCanvas: TCanvas;

      begin

         .

         .

         .

      end;

    begin

      {erase the previous animation frame}

      FBackBuffer.BltFast(0, 0, FBackground, Rect(0, 0, DXWIDTH, DXHEIGHT),

                          DDBLTFAST_NOCOLORKEY or DDBLTFAST_WAIT);

      {move and draw the sprites}

      for iCount := 0 to 1 do

        MoveSprite(Sprites[iCount]);

      {retrieve the intersection of the sprite’s bounding boxes. if there is

       indeed an intersection, compare the pixels in intersecting areas of each

       sprite. if the AND of any two pixels is greater than 0 (our transparent

       pixel value is 0, so two overlapped image pixels will return a value

       greater than 0), then there was indeed a pixel level collision.}

      if IntersectRect(Intersection, Sprites[0].Boundary, Sprites[1].Boundary) then

      begin

        {at this point, the bounding boxes have collided, so we need to prepare to

         access the sprite surfaces. we will lock the entire surface of each

         sprite}

        Sprite1SurfaceDesc.dwSize := SizeOf(TDDSurfaceDesc2);

        DXCheck(FShip1.Lock(nil, Sprite1SurfaceDesc,

                            DDLOCK_WAIT or DDLOCK_SURFACEMEMORYPTR, 0));

        {initialize the byte array to the intersected

         rectangular area of the sprite}

        Sprite1Mem := PBytePtr(Sprite1SurfaceDesc.lpSurface);

        Sprite1Mem := Pointer(Longint(Sprite1Mem)+

                              ((Intersection.Top-Sprites[0].FYPos)*

                              Sprite1SurfaceDesc.lPitch+

                              (Intersection.Left-Sprites[0].FXPos)));

        {lock the other sprite’s surface}

        Sprite2SurfaceDesc.dwSize := SizeOf(TDDSurfaceDesc2);

        DXCheck(FShip2.Lock(nil, Sprite2SurfaceDesc,

                DDLOCK_WAIT or DDLOCK_SURFACEMEMORYPTR, 0));

        {and initialize the other byte array to the intersected

         rectangular area of the sprite}

        Sprite2Mem := PBytePtr(Sprite2SurfaceDesc.lpSurface);

        Sprite2Mem := Pointer(Longint(Sprite2Mem)+

                              ((Intersection.Top-Sprites[1].FYPos)*

                              Sprite2SurfaceDesc.lPitch+

                              (Intersection.Left-Sprites[1].FXPos)));

        {begin determining if a collision has taken place.}

        Hit := FALSE;

        for iRow := 0 to (Intersection.Bottom-Intersection.Top)-1 do

          for iCol := 0 to (Intersection.Right-Intersection.Left)-1 do

            {if the pixels in the intersected rectangular areas of

             both sprites is something other than a transparent

             pixel, a collision has occurred}

            if Sprite1Mem^[iRow*Sprite1SurfaceDesc.lPitch+iCol] and

               Sprite2Mem^[iRow*Sprite2SurfaceDesc.lPitch+iCol] > 0 then

              Hit := TRUE;

        {visually indicate any collisions}

        FBackBuffer.GetDC(SrfcDC);

        try

          if Hit then

            TextOut(SrfcDC, 10, 460, ‘Collision!’, Length(‘Collision!’));

        finally

          FBackBuffer.ReleaseDC(SrfcDC);

        end;

        {we no longer need access to surfaces, so unlock them}

        FShip1.Unlock(nil);

        FShip2.Unlock(nil);

      end;

    end;
### Animation Issues Apart from getting sprites to move and animate, game developers are confronted with dozens of sprite-based issues, depending on the type of game. Complex sprites may have hundreds of animation frames, segregated into different actions, all of which must be triggered at the appropriate time by the game state. Collision detection may be a big issue, made even worse by large amounts of sprites that can move around in a virtual world several times the size of the screen. These and other animation issues are sure to appear as you develop your Delphi game masterpiece. There are a few animation issues that are fairly common among different games, and generally have straightforward resolutions. You’ve probably noticed that our previous sprite examples demonstrating animation ran incredibly fast, so fast that the animation was unbelievable. This is an issue of timing. Implementing a method to slow down the animation of a sprite is very elementary, and is little more than an extension of our previous sprite movement algorithm. Another topic to consider is the concept of z-order, or depth. Some games may exhibit many sprites in which collision is infrequent or unimportant. In this instance, it is important to consider which sprites should be drawn first, as the order in which sprites are drawn will connote depth to the viewer. Those sprites that are farthest away should naturally be drawn under those sprites that are closer. Again, implementing such functionality is relatively straightforward.
| z-order: The position along the z, or third-dimensional, axis. This is an imaginary axis that runs perpendicular to the screen, and gives the illusion of depth.
#### Timing In order to slow down sprite animation, the current frame number should not be incremented each time through the game loop. Instead, it should be incremented only at specific intervals. To implement this technique, we need to add two members to our sprite object: one for the current interval measurement and one for a threshold amount. When this current interval measurement exceeds the threshold, we can increment the frame counter. Technically, we could set the threshold amount to an integer value, and then increment the current interval measurement each time through the game loop. However, this would make the speed of the sprite animation contingent on the speed of the game. A more efficient method would be to base the speed of animation on an elapsed time amount. This would constrain the animation to a specific rate that would be constant on all machines.
Previous | Table of Contents | Next

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.