Delphi 经典游戏程序设计40例 的学习 例17 碰撞检查和事后处理

 

1,碰撞检查实际还是坐标的检测

2,角色 记录的设置

3,一个动画的实现,没有看的很明白?

4,程序框架类似,也是在TIME 中实现

5,几个函数对角色记录的 计算赋值,最后 画出这些角色,复合图案?复合图样?

6,程序没有对点阵图FREE,

7,碰撞检查放在后面似乎关系不大,显示也好像正常。

unit R17;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TpatDt = record        //记录类型的名称
    Used : Byte;         //角色的状态
    Sban : Byte;         //复合图案的编号
    Xpos : Integer;
    Ypos : Integer;
    Smov : ShortInt;     //显示行动内容的编号
    Scon : Byte;         //计数器
  end;


  TRei17 = class(TForm)
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);

  private
    { Private declarations }
    procedure HitCk;
    procedure MBalls;
    procedure MCanon;
    procedure MStars;
    procedure ChrDi(Xsiz,Ysiz :Byte;Dpon :Word;X1,Y1 :Integer;Bmap :TBitmap);
    procedure PatDi(Pnum : Byte;X1,Y1 :Integer;Bmap : TBitmap);
  public
    { Public declarations }
  end;

const
  Yoko = 37;
  Tate = 27;
  DYoko = Yoko * 16;
  DTate = Tate * 16;
  PtFull = 16;
  MaxSp = 14;        //使用的复合图样总数

var
  Rei17: TRei17;
  //载入,去除模板,绘制用点阵图
  LoadBmap,XpatBmap,MakeBmap : TBitmap;
  RectL,RectM,RectD : TRect;
  PX,PY : Byte;
  Sc : Word;
  X,Y : Integer;

  //角色数组
  ChPon : array[0..10] of  TpatDt;

  //复合图样数组 14
  SpSiz : array[0..(MaxSp * 2 -1 )] of Byte = (
    1,1, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, 1,1, 1,1, 1,1, 1,1);
  SpPon : array[0..(MaxSp -1 )] of Word;
  SpDat : array[0..40] of Byte = (
    0,
    76, 77, 92, 93,
    28, 29, 30, 31,
    34, 35, 50, 51,
    36, 37, 52, 53,
    38, 39, 54, 55,
    40, 41, 56, 57,
    42, 43, 58, 59,
    44, 45, 60, 61,
    46, 47, 62, 63,
    19,
    20,
    21,
    22);
  


implementation

{$R *.dfm}

procedure TRei17.FormCreate(Sender: TObject);
var
  n,Cn : Byte;

begin
  LoadBmap := TBitmap.Create;
  LoadBmap.LoadFromFile(GetCurrentDir + '\Pat_Sample.bmp');

  XpatBmap := TBitmap.Create;
  XpatBmap.Width := 256;
  XpatBmap .Height := 256;
  RectL := Rect(0,0,256,256);
  XpatBmap.Canvas.CopyMode := cmSrcCopy;
  XpatBmap.Canvas.CopyRect(RectL,LoadBmap.Canvas,RectL);
  XpatBmap.Canvas.Brush.Color := clBlack;
  XpatBmap.Canvas.BrushCopy(RectL,LoadBmap,RectL,clWhite);
  XpatBmap.Canvas.CopyMode := cmMergePaint;
  XpatBmap.Canvas.CopyRect(RectL,LoadBmap.Canvas,RectL);

  //零件贴图指标数组
  Sc := 0;
  for n := 0 to (MaxSp -1) do
  begin
    SpPon[n] := Sc;
    Sc := Sc + SpSiz[n * 2] * SpSiz[n * 2 + 1];
  end;

  //绘制点阵图初始
  MakeBmap := TBitmap.Create;
  MakeBmap.Width := DYoko + 32;
  MakeBmap.Height := DTate + 32;

  //角色用数组初始
  Randomize;

  //0,炮台
  ChPon[0].Used := 1;                     //1,使用中
  ChPon[0].Sban := 1;                    //炮台复合图案编号1
  ChPon[0].Xpos := DYoko div 2 - 16;    //X图像中间
  ChPon[0].Ypos := DTate - 32;          // Y图像底部
  ChPon[0].Smov := 4;                   //炮台X移动速度
  ChPon[0].Scon := 30;                  //发射间隔计数器

  // 1-4 人面球
  for Cn := 1 to 4 do
  begin
    ChPon[Cn].Used := 0;
    ChPon[Cn].Scon :=Random(10) + 10;       //出现时机计数器
  end;
  //5-10 星星
  for Cn := 5 to 10 do
    ChPon[Cn].Used := 0;

end;

//碰撞检测
procedure TRei17.HitCk;
var
  Cn,n :Byte;
begin
  for Cn := 1 to 4 do   //1-4 人面球
    if ChPon[Cn].Used = 2 then   //人面球状态非无敌
      for n := 5 to 10 do        //5-10 星星
        if ChPon[n].Used = 1 then    // 星星存在
        begin
          X := ChPon[Cn].Xpos - ChPon[n].Xpos;
          Y := ChPon[Cn].Ypos - ChPon[n].Ypos;
          //碰撞坐标范围测定
          if ( X >= -28 ) and (X <= 12) and (Y >= -28) and (Y <= 12) then
          begin
            ChPon[Cn].Used := 255;    //改变人面球状态为255
            ChPon[n].Used  := 0;     // 改变星星状态为0
          end;
        end;
end;

//人面球的移动和出现
procedure TRei17.MBalls;
var
  Cn : Byte;
begin
  for Cn := 1 to 4 do
  begin
    ChPon[Cn].Scon := ChPon[Cn].Scon + 1;  //人面球出现时机计数 ,存在时间计数
    case ChPon[Cn].Used of
      0 :begin
        if (ChPon[Cn].Scon > 30) and (Random(100) < 15) then   //出现条件进入状态1
        begin
          ChPon[Cn].Used := 1;
          ChPon[Cn].Sban := 2;
          ChPon[Cn].Xpos := (Cn -1) * 160 + 15 + Random(50);    //设置出现的初始坐标
          ChPon[Cn].Ypos := -31;
        end;
      end;

      1:begin                    //状态降落
        ChPon[Cn].Ypos := ChPon[Cn].Ypos + 2;
        ChPon[Cn].Sban := ChPon[Cn].Sban xor 2; //改变图样实现闪烁?XOR 0 OR 2
        if ChPon[Cn].Ypos > 100 then     //降落到100进入状态2
        begin
          ChPon[Cn].Used := 2;
          ChPon[Cn].Sban := 2;
          ChPon[Cn].Scon := 0;          //清零,用来计数存在时间
        end;
      end;

      2:begin                       //状态静止
        if ChPon[Cn].Scon = 255 then   //存在时间条件进入状态3
          ChPon[Cn].Used := 3;
      end;

      3:begin                           // 状态3 ,上升
        ChPon[Cn].Ypos := ChPon[Cn].Ypos -4;
        ChPon[Cn].Sban := ChPon[Cn].Sban xor 2;
        if  ChPon[Cn].Ypos < -31 then    //该人面球清零
          begin
            ChPon[Cn].Used := 0;
            ChPon[Cn].Scon := 0;

          end;
      end;

      255:begin           //碰撞状态  , 爆炸中
        if ChPon[Cn].Sban = 2 then
        begin
          ChPon[Cn].Sban := 3;  //图样3
          ChPon[Cn].Scon := 0;
          ChPon[Cn].Smov := 0;
        end
        else begin                 //如何实现爆炸的动画显示?
          ChPon[Cn].Sban := ChPon[Cn].Sban + 1;      //爆炸图样 +1,
          if (ChPon[Cn].Sban = 7)and(ChPon[Cn].Smov <= 2) then
          begin
            ChPon[Cn].Sban := 3;
            ChPon[Cn].Smov := ChPon[Cn].Smov + 1;         //爆炸显示次数
          end
          else if ChPon[Cn].Sban = 10 then                //图样10?
          begin
            ChPon[Cn].Used  := 0;
            ChPon[Cn].Scon := 0;
          end;
        end;
      end;
    end;
  end;
end;

//炮台移动和星星发射
procedure TRei17.MCanon;
var
  Cn : Byte;
begin
  ChPon[0].Xpos := ChPon[0].Xpos + ChPon[0].Smov;   //炮台来回移动
  if (ChPon[0].Xpos < 0) or (ChPon[0].Xpos > DYoko - 32) then
  begin
    ChPon[0].Smov := - ChPon[0].Smov;
    ChPon[0].Xpos :=  ChPon[0].Xpos + ChPon[0].Smov;

  end;

  ChPon[0].Scon := ChPon[0].Scon + 1;    //发射星星条件
  if (ChPon[0].Scon > 15) and (Random(100) < 35) then
  begin
    Cn := 5;
    while (Cn < 11) and (ChPon[Cn].Used = 1) do    //找到可以用的星星?
      Cn := Cn + 1;
    if Cn < 11 then          //发射星星
    begin
      ChPon[Cn].Used := 1;
      ChPon[Cn].Xpos := ChPon[0].Xpos + 8;
      ChPon[Cn].Ypos := DTate -45;
      ChPon[Cn].Smov := 10 + Random(5);
      ChPon[0].Scon := 0;         // 发射星星后炮台发射计数器清零
    end;

  end;
end;


procedure TRei17.MStars;
var
  Cn : Byte;

begin
  for Cn := 5 to 10 do
    if ChPon[Cn].Used = 1then
    begin
      ChPon[Cn].Scon := ChPon[Cn].Scon + 1 ;
       //图案编号计数器?
      // 它好像没有赋过初值,默认0 ,会不断增大?0-256循环?
      ChPon[Cn].Sban := 10 + ChPon[Cn].Scon and 3; //星星也有3种图案? 在旋转?
      ChPon[Cn].Ypos := ChPon[Cn].Ypos - ChPOn[Cn].Smov;
      if ChPon[Cn].Ypos < -15 then
        ChPon[Cn].Used := 0;
    end;
end;

procedure TRei17.ChrDi(Xsiz,Ysiz:Byte;Dpon:Word;X1,Y1:Integer;Bmap:TBitmap);
var
  CDX,CDY :Byte;
begin
  for CDY := 0 to (Ysiz - 1) do
    for CDX := 0 to (Xsiz -1 ) do
    begin
      if (X1 + CDX * 16 >= 0 ) and  (X1 + CDX * 16 <= DYoko + 16) and
         (Y1 + CDY * 16 >= 0 ) and (Y1 + CDY * 16 <= DTate + 16 ) then
        PatDi(SpDat[Dpon],X1 + CDX * 16,Y1 + CDY * 16,Bmap);
      Dpon := Dpon + 1;
    end;

end;

procedure TRei17.PatDi(Pnum:Byte;X1,Y1:Integer;Bmap:TBitmap);
begin
  PX  := (Pnum and $F) * 16;
  PY := Pnum and $F0 ;
  RectL := Rect(PX,PY,PX + 16,PY + 16);
  RectD := Rect(X1,Y1,X1 + 16,Y1 + 16);

  if Pnum <> 0 then
   if Pnum >= PtFull  then

    begin
      Bmap.Canvas.CopyMode := cmSrcPaint;
      Bmap.Canvas.CopyRect(RectD,XpatBmap.Canvas,RectL);
      Bmap.Canvas.CopyMode := cmSrcAnd;
      Bmap.Canvas.CopyRect(RectD,LoadBmap.Canvas,RectL);
    end
   else
    begin
      Bmap.Canvas.CopyMode := cmSrcCopy;
      Bmap.Canvas.CopyRect(RectD,LoadBmap.Canvas,RectL);
    end;


end;

procedure TRei17.Timer1Timer(Sender: TObject);
var
  Cn : Byte;
begin
  HitCk;
  MBalls;
  MCanon;
  MStars;

  RectM := Rect(16,16,DYoko + 16,DTate + 16);
  MakeBmap.Canvas.Brush.Color := clBlack;
  MakeBmap.Canvas.FillRect(RectM);
  Rei17.Canvas.CopyMode := cmSrcCopy;
  for Cn := 10 downto 0 do
    if (ChPon[Cn].Used <> 0) and (ChPon[Cn].Sban <> 0 ) then
    begin   //图案的格式在这里得到了方便的利用
      ChrDi(SpSiz[ChPon[Cn].Sban * 2],SpSiz[ChPon[Cn].Sban * 2 + 1],
        SpPon[ChPon[Cn].Sban],ChPon[Cn].Xpos + 16,ChPon[Cn].Ypos + 16,MakeBmap);

    end;
  RectD := Rect(0,0,DYoko,DTate);
  Rei17.Canvas.CopyRect(RectD,MakeBmap.Canvas,RectM);
  

end;

end.

 

posted @ 2022-07-21 11:41  D7mir  阅读(100)  评论(0)    收藏  举报