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
Listing 13-2: The Delphi Blocks mouse thread unit
    unit MouseThreadU;

    interface

    uses

      Classes, Controls, Windows, SyncObjs;

    type

      TMouseThread = class(TThread)

      private

        { Private declarations }

      protected

        procedure Execute; override;

      end;

      {this will hold mouse data for click events}

      TMouseData = class

      public

        XPos, YPos: Integer;

        Button: TMouseButton;

        constructor Create(X, Y: Integer; MButton: TMouseButton);

      end;

    var

      CurX, CurY: Integer;

      MouseClickList: TList;

      FCritSec: TCriticalSection;

      FMouseEvents: TWOHandleArray;

      ShowMouse: Boolean;

    const

      CURSORWIDTH = 32;       // we have a 32 X 32 pixel cursor

      CURSORHEIGHT = 32;

      NUMFRAMES = 8;          // with 8 frames of animation

    implementation

    uses DInput, DelphiBlocksU, DDraw;

    {this creates and initializes one mouse data object for recording

     click events}

    constructor TMouseData.Create(X, Y: Integer; MButton: TMouseButton);

    begin

      XPos := X;

      YPos := Y;

      Button := MButton;

    end;

    { TMouseThread }

    procedure TMouseThread.Execute;

    var

      EventNum: Integer;

      BufferEmpty: Boolean;

      NumElements: DWORD;

      DeviceData: TDIDeviceObjectData;

      DataResult: HRESULT;

    begin

      {while the thread has not terminated...}

      while not Terminated do

      begin

        {pause this thread until either a mouse event or a quit event has fired}

        EventNum := WaitForMultipleObjects(2, @FMouseEvents, FALSE, INFINITE);

        {if the quit event fired...}

        if EventNum-WAIT_OBJECT_0 = QUITEVENT then

        begin

          {terminate the thread and exit}

          Terminate;

          Break;

        end;

        {enter the critical section. this prevents the main thread from accessing

         variables used within this block of code until the critical section

         is exited}

        FCritSec.Enter;

        {until the input buffer has been emptied...}

        BufferEmpty := FALSE;

        while not BufferEmpty do

        begin

          {indicate that we wish to retrieve only one element}

          NumElements := 1;

          {retrieve one input data element}

          DataResult := FMouseDevice.GetDeviceData(SizeOf(TDIDeviceObjectData),

                                                   @DeviceData, NumElements, 0);

          {if we did in fact retrieve data...}

          if (DataResult = DI_OK) and (NumElements = 1) then

          begin

            {determine what the data is}

            case DeviceData.dwOfs of

              {for horizontal or vertical mouse movements, record the new data}

              DIMOFS_X        : CurX := CurX + DeviceData.dwData;

              DIMOFS_Y        : CurY := CurY + DeviceData.dwData;

              {for all button presses (that is, a mouse button down only, as

               opposed to a mouse button up), add a click event to the list

               (mapping all mouse buttons to a mouse button left click event)}

              DIMOFS_BUTTON0,

              DIMOFS_BUTTON1,

              DIMOFS_BUTTON2,

              DIMOFS_BUTTON3  : if (DeviceData.dwData and $80) = $80 then

                                  MouseClickList.Add(TMouseData.Create(CurX, CurY,

                                                     mbLeft));

            end;

          end

          else

            {otherwise, if nothing was retrieved, we’ve emptied the buffer}

            BufferEmpty := TRUE;

        end;

        {if the mouse cursor is to be shown...}

        if ShowMouse then

        begin

          {clip the mouse cursor to the screen}

          if CurX < 0 then

            CurX := 0;

          if CurX > DXWIDTH-CURSORWIDTH then

             CurX := DXWIDTH-CURSORWIDTH-1;

          if CurY < 0 then

            CurY := 0;

          if CurY > DXHEIGHT-CURSORHEIGHT then

             CurY := DXHEIGHT-CURSORHEIGHT-1;

        end

        else

        begin

          {...otherwise, we’re only showing the paddle, so we only need to

           check the horizontal position of the mouse cursor}

          if CurX < 5 then

            CurX := 5;

          if CurX > DXWIDTH - 92 then

            CurX := DXWIDTH - 92;

        end;

        {finally, we must leave the critical section so that the main thread

         can have access to the mouse cursor location variables}

        FCritSec.Leave;

      end;

    end;

    initialization

      {initially, we want to show the mouse cursor}

      ShowMouse := TRUE;

    end.
### Summary In this chapter, we discussed how graphics, user input, and sound and music programming techniques come together to create a complete game application. We examined how each part of a game is implemented, including techniques for tracking several sprites as well as using DirectSound and Windows multimedia functions simultaneously. We also looked at various ways to enhance and improve the Delphi Blocks game. When using these techniques to create your own games, it is important to keep these points in mind: • The state-driven architecture is useful for many styles of games and is easy to implement. More complex games may require an equally more complex architecture, but the concepts are similar. • Always implement the most natural form of user input for the type of game being developed. For Delphi Blocks, this was the mouse, but for other games, it might be the joystick or keyboard. While not absolutely necessary, it is good programming practice to give the user a choice of input devices. • Sound and music always enhance a game. Sound for Delphi Blocks was implemented using DirectSound in order to allow for easier modification. However, music was implemented using Windows multimedia functions in order to show how the two can coexist gracefully. This should demonstrate how you can use whatever method is appropriate for your gaming application. • The simple 2-D graphics in this game use straightforward techniques for implementing the game animation. These techniques are acceptably fast, but could be optimized. However, bear in mind that optimization has a diminishing margin of returns, so only optimize those parts that truly need it. • While not a commercial quality game, this case study could easily be extended and molded into one within a few weeks. Remember, Delphi can do anything that C can do; you just have to have the knowledge and patience.
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.