⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unit1.pas

📁 Directx游戏制作开发包DGCBETA6
💻 PAS
📖 第 1 页 / 共 3 页
字号:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  DGCMap, DGCILib, DGC, mmsystem, ExtCtrls, DGCSnd, dgcslib, dsound;

const
  MISSILES  = 9;     // Number of missiles that can be moving at one time
  FIRE_RATE = 15;    // The rate at which the missiles are fired
  EXPLODE_RATE = 3;  // Timing for the explosions for the car

type
  TMissile = record      //This holds info for each missile/explosion
    Free     : Boolean;    //Indicates in use or not
    XPos     : Integer;    //XPos on the screen
    YPos     : Integer;    //YPos on the screen
    YSpeed   : Integer;    //Used to keep moving with the map
    Cell     : Integer;    //current cell for missile animation
    Explode  : Boolean;    //use info for explosion
    ExpCell  : Integer;    //current cell for explosion animation
    AnimSpeed: Integer;    //Speed of the animation (wait # frames)
    AnimInc  : Integer;    //The number of frames passed since last update
  end;

  TForm1 = class(TForm)
    DGCScreen1: TDGCScreen;
    DGCImageLib1: TDGCImageLib;
    DGCMapLib1: TDGCMapLib;
    DGCImageLib2: TDGCImageLib;
    Timer1: TTimer;
    DGCSoundLib1: TDGCSoundLib;
    DGCAudio1: TDGCAudio;
    procedure DGCScreen1Flip(Sender: TObject);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
    procedure Timer1Timer(Sender: TObject);
    procedure DGCAudio1Initialize(Sender: TObject);
    procedure DGCScreen1Initialize(Sender: TObject);

  private
    { Private declarations }
    YPos      : Integer;   // Y Position of the race map
    PX        : Integer;   // Car's Horizontal position
    Speed     : Integer;   // Car's speed
    Accel     : Integer;   // Crude acceleration counter
    CarAnim   : Integer;   // Car animation frame
    AnimDir   : Integer;   // Which way to move the car anim index
    AnimTick  : Integer;   // number of frames since last update (for car)
    Score     : array[0..6] of byte;  // holds the score
    LapTime   : array[0..3] of byte;  // holds the lap time
    MissCnt   : array[0..1] of byte;  // holds the number of missiles
    Shield    : Integer;              // shield strength

    Missile   : Array[0..Missiles] of TMissile; // holds missile data
    Fired     : Integer;  //A missile was just fired!
    FirePause : Integer;  //amount of time since last missile fired
    OkToFire  : Boolean;  //It's now OK to fire a missile (timing)
    ExpPause  : Integer;  //amount of time between expolsions (car)
    OkToExp   : Boolean;  //It's now ok to do the next explosion
    Explosions: integer;  //Number of explosions that have occured (car)
    ExpScreen : TDGCSurface; // a custom surface to grab the screen before car explosions

    //These next 2 arrays are used to create a copy of the sound effect so that
    //the same sound can be played multiple times at once.
    MissileSnd: array[0..MISSILES] of IDirectSoundBuffer;
    ExplodeSnd: array[0..MISSILES] of IDirectSoundBuffer;

    //This array holds the map details so that we can restore it after a race
    MapHold   : Array[0..599, 0..14] of byte;

    //For these procedures, look at the actual procedure to get a better description
    //of what that procedure does.

    procedure CheckKeyboard;                       //Gets keyboard input during race
    procedure AnimateCar;                          //Updates the car sprite
    procedure UpdateTrack;                         //Updates the track position
    procedure CheckTile(X,Y : Integer);            //Checks for a tile ahead/behind car
    procedure DisplayScore;                        //Draws the score to the screen
    procedure AddToScore(a,b,c,d,e,f,g : integer); //Adds points to the score
    procedure DisplayShield;                       //Draws the shied info to the screen
    procedure DisplayTime;                         //Draws the time info to the screen
    procedure AddToTime(a,b,c,d : integer);        //Adds the time
    procedure FireMissile;                         //Launch a missile
    procedure UpdateMissiles;                      //Update fired missiles
    procedure DisplayMissiles;                     //Draws missile info on the screen
    procedure AddToMissiles(a,b : Integer);        //Increases number of missiles
    procedure SubtractMissile;                     //Decreases number of missiles
    procedure ShowIntro;                           //Shows the opening screen
    procedure ExplodeCar;                          //Explodes the car!
    procedure DrawCarExplosion;                    //Draws the explosions for the car

  public
    { Public declarations }
  end;

var
  Form1     : TForm1;
  //These values are used for the "Frequency" for the car engine --
  //The sound frequency is picked by the speed of the car
  HumFreq   : Array[0..3] of Integer = (11000,19500,26300,33100);
  ShowTitle : Boolean = True;   // Showing the title stuff ?
  ShowHelp  : Boolean = False;  // Showing Help Screen?
  Quit      : Boolean = False;  // User hit escape during intro
  GameOver  : Boolean = False;  // Car exploded - game over!

implementation

{$R *.DFM}

procedure TForm1.DGCScreen1Flip(Sender: TObject);
begin
   If ShowTitle then ShowIntro;   //This is here for a clean exit when the user quits
   If GameOver  then //If shields are gone then destroy car and exit the main game
   begin
      ExplodeCar;    // draw the explosion
      Exit;          // quit this round
   end;

   CheckKeyboard;    //Checks for "game" keys (CTRL & Cursor)
   UpdateTrack;      //Updates the track position
   AnimateCar;       //Animates the car

   DGCScreen1.DrawMap(DGCScreen1.Back,0,0,0,40,YPos,false); // Draw map to screen

   UpdateMissiles;   //Show any fired missiles

   DGCScreen1.Back.Draw(PX,160,DGCScreen1.Images[CarAnim],True); // Draw Car

   // The next 4 things just display the score, sheild, time, and available missiles
   DisplayScore;
   DisplayShield;
   DisplayTime;
   DisplayMissiles;
end;

procedure TForm1.ExplodeCar;
var
   pause : Integer;
begin
   If Quit then Exit; // If the user has opted to quit the game, exit from here!
   Explosions := 0;   //reset the number of explosions shown
   pause := 0;        //reset the pause count
   DGCScreen1.CreateSurface(ExpScreen,320,240); // create a surface to hold current screen
   DGCScreen1.Back.Erase(0); // erase the background of the game screen
   DGCScreen1.DrawMap(DGCScreen1.Back,0,0,0,40,YPos,false); // draw the map in the last position
   DisplayScore; // the next couple of things display the regular info
   DisplayShield;
   DisplayTime;
   DisplayMissiles;
   ExpScreen.Draw(0,0,DGCScreen1.Back,False);  //copy the rebuit screen to the final surface

   //We'll draw 50 explosions and wait a few frames to let the explosions finish before exiting
   while (Explosions <= 50) and (Pause < 60) do
   begin
      Application.ProcessMessages; // allow normal system stuff !! A MUST!
      DGCScreen1.Back.Erase(0); // clear the background
      DGCScreen1.Back.Draw(0,0,ExpScreen,False); // refresh the background
      DrawCarExplosion; // Draw the explosions
      If Explosions >= 50 then Inc(Pause);  //if we have reach the allowable number of
                                            //explosions, pause a few frames to finish anims
      DGCScreen1.Flip; //flip the buffers -- this also do the vsync timing (directX thing)
   end;

   Shield := 100;      //reset shields
   ShowTitle := True;  //game over, now show the into again
   ExpScreen.Free;     //free the temp surface
end;

procedure TForm1.DrawCarExplosion;
var
   loop : integer;
begin
   //This loop will reset the OkToExp flag every so often so that the explosions don't all
   //go at one time -- better visual!
   If not OkToExp then   //if waiting
   begin
     Inc(ExpPause);      //increase the explosion pause counter
     If ExpPause >= EXPLODE_RATE then  //if the pause amount is > than the wait amount
     begin                             //then reset the flag & counter
        ExpPause := 0;
        OkToExp := True;
     end;
   end;

   for loop := 0 to MISSILES do  //go through all the missiles
   begin
      //If the missile is not used and it is ok to fire a missile and less than 50
      //missiles have been fired, then set up a new explostion
      //NOTE: The same array (for missiles) is being used for the car explosions
      If (Missile[loop].Free) and (OkToExp) and (Explosions < 50) then
      begin
         Missile[Loop].Free := False;       //this entry is now being used!
         Inc(Explosions);                   //Increase the number of explosions fired!
         Missile[Loop].Explode   := True;   //set the animation type
         Missile[Loop].ExpCell   := 3;      //starting image number
         Missile[Loop].AnimInc   := 0;      //init timing counter
         Missile[Loop].AnimSpeed := 5;      //how fast to do exp anim
         Missile[Loop].XPos      := (PX - 20)  + Random(45);  //position the explosion
         Missile[Loop].YPos      := 140 + Random(45);         //position the explosion
         ExplodeSnd[Loop].SetCurrentPosition(0);              //reset sound fx position
         ExplodeSnd[Loop].Play(0,0,0);                        //play the sound fx
         OkToExp := False;                                    //now we have to wait a few!
      end;

      If not Missile[Loop].Free then   // if missile (explosion) is being used
      begin
         //Draw the current explosion animation frame
         DGCScreen1.Back.Draw(Missile[Loop].XPos, Missile[Loop].YPos,
                    DGCScreen1.Images[Missile[Loop].ExpCell],True);

         Inc(Missile[Loop].AnimInc);  //increase timing counter
         If Missile[Loop].AnimInc > Missile[Loop].AnimSpeed then //time for next frame?
         begin
            Inc(Missile[Loop].ExpCell);  //increase anim cell
            Missile[Loop].AnimInc := 0;  //reset timing counter
            If Missile[Loop].ExpCell > 7 then //end of anim
            begin
               Missile[Loop].Free := True;  //free the array element for use
               ExplodeSnd[Loop].Stop;       //stop the sound!
            end;
         end;
      end;
   end;
end;

procedure TForm1.DisplayMissiles;
begin
   //This routine displays the missile graphic at the bottom of the screen along
   //with the number of available missiles.

   //NOTE: The SCORE, TIME, & MISSILE counters are all handled manually -- this
   //      is a lot faster than trying to convert the numbers to strings, checking
   //      for certain values, then drawing the appropriate image.

   //Draw the missile image
   DGCScreen1.Back.Draw(056,224,DGCScreen1.Images[25],True);
   //Draw the ":"
   DGCScreen1.Back.Draw(070,227,DGCScreen1.Images[20],True);
   //Draw the first digit
   DGCSCreen1.Back.Draw(077,227,DGCScreen1.Images[MissCnt[0]+10],True);
   //Draw the second digit
   DGCScreen1.Back.Draw(084,227,DGCScreen1.Images[MissCnt[1]+10],True);
end;

procedure TForm1.UpdateMissiles;
var
   loop : Integer;
   Tile : TDGCMapPos;

begin
   If Fired < 0 then exit;  //If no missiles fired, might as well exit this routine!

   //This little block handles some timing for firing missiles. If we didn't time how
   //often the missiles could be fired then they would all fire pretty much at the
   //same time -- which may be good in another game, but not so in this demo.
   If not OkToFire then    //If it's not time to fire another missile
   begin
     Inc(FirePause);       //increase the firing pause counter
     If FirePause >= FIRE_RATE then //if it passes the firing rate constant
     begin                          //reset the flag so that another missile can
        FirePause := 0;             //be fired
        OkToFire := True;
     end;
   end;

   //process all missiles!
   for loop := 0 to MISSILES do
   begin
      If not Missile[loop].Free then // if missile is in use
      begin
         //get the current tile under the tip of the missile
         Tile := DGCScreen1.GetTileDrawn(Missile[Loop].XPos,Missile[Loop].YPos);

         If Tile.Tile = 4 then   // Is the tile a 'ROCK' ?
         begin
            Missile[Loop].Explode   := True;  // set up the rock explosion stuff
            Missile[Loop].ExpCell   := 3;
            Missile[Loop].AnimInc   := 0;
            Missile[Loop].AnimSpeed := 5;
         end;

         //If the current missile is not in the explode state, move it up the screen
         If not Missile[Loop].Explode then
         begin
           Inc(Missile[Loop].YPos,Missile[Loop].YSpeed); // move the missile
           //If the car is moving backwards, you need to accomidate the missile's location
           If Speed < 0 then Inc(Missile[Loop].YPos, Speed);
           //If missile is off the top of the screen then free the missile array element for use
           If Missile[loop].YPos < 0 then Missile[Loop].Free := True;
           //increase the animation timing counter
           Inc(Missile[Loop].AnimInc);
           If Missile[Loop].AnimInc > Missile[Loop].AnimSpeed then //can update anim?
           begin
              //The missile only has 2 frame, image 8 & 9 -- toggle between the two
              If Missile[Loop].Cell = 8 Then Missile[Loop].Cell := 9 else
                                             Missile[Loop].Cell := 8;
              Missile[Loop].AnimInc := 0; //reset the timing counter
           end;
           //Draw the current animation cell to the screen
           DGCScreen1.Back.Draw(Missile[Loop].XPos, Missile[Loop].YPos,
                      DGCScreen1.Images[Missile[Loop].Cell],True);
         end
         else // do the rock explosion!
         begin
           //Is this the first cell of the animation explostion sequence?
           If (Missile[Loop].ExpCell = 3) and (Missile[Loop].AnimInc = 0) then
           begin
              DGCScreen1.SetMapTile(0,Tile.MapX,Tile.MapY,5);  //remove the rock
              AddToScore(0,0,0,0,0,1,0);                       //add points

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -