Delphi 经典游戏程序设计40例 的学习 例22 残留图像效果

 

 

 

 

 

 

 

unit R22;

interface

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

type
  TPatDt = record
    Used : Byte;
    Sban : Byte;
    Xpos : Integer;
    Ypos : Integer;
    Smov : Byte;
    Scon : Byte;
    Dtim : Byte;                           // 拖影的间隔<8,只存储了40个历史坐标
    DlyS : array[1..40] of Byte;          //复合图样数组
    DlyX : array[1..40] of Integer;       //X 坐标用数组
    DlyY : array[1..40] of Integer;       //y 坐标用数组
  end;

  TRei22 = class(TForm)
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
    procedure MkDpat(Bmap : TBitmap; ZX : Byte);
    procedure ChMove;
    procedure ChrDz(Znum,Xsiz,Ysiz:byte;Dpon:Word;X1,Y1:Integer;Bmap:TBitmap);
    procedure PatDz(Pnum:Byte;X1,Y1:Integer;Bmap,Zmap:TBitmap);
 public
    { Public declarations }
  end;

const
  Yoko = 37;
  Tate = 27;
  DYoko = Yoko * 16;
  Dtate = Tate * 16;
  PtFull = 16;
  MaxSp = 8;               //复合图样总数
  Mdot = 3;                //移动点数

var
  Rei22: TRei22;
  LoadBmap,XpatBmap,BackBmap,MakeBmap : TBitmap;
  //笔刷,残留图像用点阵图
  BpatBmap,Z1Bmap,Z2Bmap,Z3Bmap,Z4Bmap,Z5Bmap :TBitmap;
  PX,PY : Byte;
  Sc : Word;
  RectL,RectB,RectM,RectD : TRect;
  //角色记录数组
  ChPon : array[0..3] of TPatDt;
  //复合图样的数组
  SpSiz :array[0..(MaxSp * 2 - 1)] of Byte = (
   1,1,
   2,2,
   2,2,
    2,3,
    1,1,
    1,1,
    1,1,
    1,1 );
  SpPon :array[0..(MaxSp -1)] of Word;
  SpDat :array[0..18] of Byte = (
   0,
   28,29,30,31,
   32,33,48,49,
   65,65,80,81,96,97,
   19,
   20,
   21,
   22);



implementation

{$R *.dfm}

procedure TRei22.FormCreate(Sender: TObject);
var
  x,y,n,Cn :Byte;

begin
  //载入图案库
  LoadBmap := TBitmap.Create;
  LoadBmap.LoadFromFile(GetCurrentDir + '\Pat_Sample.bmp');
  //零件贴图指标数组初始
  Sc := 0;
  for n := 0 to (MaxSp-1) do
    begin
      SpPon[n] := Sc;
      Sc := Sc + SpSiz[n * 2] * SpSiz[n * 2 + 1];
    end;
  //存储去除用点阵图
  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);
  //笔刷用点阵图
  BpatBmap := TBitmap.Create;
  BpatBmap.Width := 8;
  BpatBmap.Height := 8;
  //残留图像用点阵图
  Z1Bmap := TBitmap.Create;
  Z2Bmap := TBitmap.Create;
  Z3Bmap := TBitmap.Create;
  Z4Bmap := TBitmap.Create;
  Z5Bmap := TBitmap.Create;
  //制作残留图像点阵图
  MkDpat(Z1Bmap,3);
  MkDpat(Z2Bmap,6);
  MkDpat(Z3Bmap,8);
  MkDpat(Z4Bmap,10);
  MkDpat(Z5Bmap,12);
  //制作背景点阵图
  BackBmap := TBitmap.Create;
  BackBmap.Width := DYoko;
  BackBmap.Height := Dtate;

  for x := 0 to Yoko - 1 do
    for y := 0 to Tate - 1 do
    begin
      if ( x <= Yoko div 2 )and (y <= Tate div 2) then
        n := 1
      else if (x >= Yoko div 2) and (y <= Tate div 2) then
        n :=7
      else if (x <= Yoko div 2) and ( Y >= Tate div 2) then
        n := 13
      else
        n := 15;
      PatDz(n,x * 16,y * 16,BackBmap,LoadBmap);
    end;
  //绘制点阵图,
  MakeBmap  := TBitmap.Create;
  MakeBmap.Width := DYoko + 32;
  MakeBmap.Height := Dtate + 32;
  //角色数组初始
  ChPon[0].Used  := 1;
  ChPon[0].Sban := 1;      //独眼
  ChPon[0].Xpos := 50;
  ChPon[0].YPos := 50;
  ChPon[0].Smov := 1;
  ChPon[0].Scon := 0;
  ChPon[0].Dtim := 3;

  ChPon[1].Used  := 1;
  ChPon[1].Sban := 3;     //树人
  ChPon[1].Xpos := 395;
  ChPon[1].YPos := 350;
  ChPon[1].Smov := 5;
  ChPon[1].Scon := 0;
  ChPon[1].Dtim := 6;

  ChPon[2].Used  := 1;
  ChPon[2].Sban := 2;      //菠萝人
  ChPon[2].Xpos := 510;
  ChPon[2].YPos := 125;
  ChPon[2].Smov := 3;
  ChPon[2].Scon := 0;
  ChPon[2].Dtim := 4;

  ChPon[3].Used  := 1;
  ChPon[3].Sban := 4;         //星星
  ChPon[3].Xpos := 50;
  ChPon[3].YPos := 275;
  ChPon[3].Smov := 7;
  ChPon[3].Scon := 0;
  ChPon[3].Dtim := 6;

  for Cn := 0 to 3 do
    for n := 1 to 40 do
      with ChPon[Cn] do
      begin
        DlyS[n] := Sban; //图案编号0..3
        DlyX[n] := Xpos;
        DlyY[n] := Ypos;
      end;
end;
//制作残留图像用的图案 ,ZX 偏移 点数
procedure TRei22.MkDpat(Bmap : TBitmap; ZX : Byte);
begin
  Bmap.Width := 256;
  Bmap.Height := 256;
  BpatBmap.Canvas.CopyMode := cmSrcCopy;
  //调取特定位置图案,8*8 的大小?调取点数是随意额?
  //调取的就是随意选择的,并不是特定的图案
  RectL := Rect(ZX * 8 + 32,64,ZX * 8 + 40,72);
  RectD := Rect(0,0,8,8);
  BpatBmap.Canvas.CopyRect(RectD,LoadBmap.Canvas,RectL);
  //图案作为笔刷,
  Bmap.Canvas.Brush.Bitmap := BpatBmap;
  Bmap.Canvas.CopyMode := cmMergeCopy;
  //全刷了一遍
  RectL := Rect(0,0,256,256);
  Bmap.Canvas.CopyRect(RectL,LoadBmap.Canvas,RectL);
  //和 去除用点阵图 ,但还是用了去除模板,做外框?
  Bmap.Canvas.CopyMode := cmMergePaint;
  Bmap.Canvas.CopyRect(RectL,XpatBmap.Canvas,RectL);
  Bmap.Canvas.Brush.Bitmap := nil;

end;

procedure TRei22.ChMove;
var
  n,Cn :Byte;

begin
  for Cn := 0 to 3 do
    if ChPon[Cn].Used = 1 then
    begin
      with ChPon[Cn] do
      begin
        for n := 39  downto 1 do
        begin
          DlyS[n + 1] := DlyS[n];
          DlyX[n + 1] := DlyX[n];
          DlyY[n + 1] := DlyY[n];
        end;
        DlyS[1] := Sban;
        DlyX[1] := Xpos;
        DlyY[1] := Ypos;

        if Cn = 3 then      //3 为旋转的星星图案
          Sban := (Sban + 1) and 3 + 4;   //图案变化实现星星的旋转
        if Scon <> 0 then         //scon 表示什么?
          Scon := Scon - 1
        else begin
          case Smov of               //SMOV 表示移动的方向 ?  这个得结合图例看
            1: if Xpos < 395 then
                 Xpos := Xpos + Mdot
               else begin
                 Smov := 2;
                 Xpos := Xpos + Mdot;
                 Ypos := Ypos + Mdot;
               end;
            2: if Ypos < 125 then
               begin
                 Xpos := Xpos + Mdot;
                 Ypos := Ypos + Mdot;
               end
               else begin
                 Smov := 3;
                 Ypos := Ypos + Mdot;
               end;
            3: if Ypos < 275 then
               Ypos  := Ypos + Mdot
               else begin
                 Smov := 4;
                 Xpos := Xpos  - Mdot;
                 Ypos := Ypos + Mdot;
               end;
            4: if Ypos < 350 then
               begin
                 Xpos := Xpos - Mdot;
                 Ypos := Ypos + Mdot;
               end
               else begin
                 Smov := 5;
                 Xpos := Xpos - Mdot;
               end;
            5: if Xpos > 165 then
               Xpos := Xpos - Mdot
               else begin
                 Smov := 6;
                 Xpos := Xpos - Mdot;
                 Ypos := Ypos - mdot;

               end;
            6: if Ypos > 275 then
               begin
                 Xpos := Xpos - Mdot;
                 Ypos := Ypos - Mdot;
               end
               else begin
                 Smov := 7;
                 Ypos := Ypos - Mdot;
               end;
            7: if Ypos > 125 then
               Ypos := Ypos - Mdot
               else begin
                 Smov := 8;
                 Xpos := Xpos + Mdot;
                 Ypos := Ypos - Mdot;
               end;
            8: if Ypos > 50 then
               begin
                 Xpos := Xpos + Mdot;
                 Ypos := Ypos - Mdot;
               end
               else begin
                 Smov := 1;
                 Scon := 30;

               end;
          end;

        end;
    end;
   end;
end;

 //Znum
procedure TRei22.ChrDz(Znum,Xsiz,Ysiz:byte;Dpon:Word;X1,Y1:Integer;Bmap:TBitmap);
var
  CDX,CDY :Byte;
  ZBmap : TBitmap;
begin
  case Znum of
    0: ZBmap := LoadBmap;
    1: ZBmap := Z1Bmap;
    2: ZBmap := Z2Bmap;
    3: ZBmap := Z3Bmap;
    4: ZBmap := Z4Bmap;
    5: ZBmap := Z5Bmap;
  end;

  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
         PatDz(SpDat[Dpon],X1 + CDX * 16,Y1 + CDY * 16,Bmap,ZBmap);
      Dpon := Dpon + 1;
    end
end;




//Zmap源图,Bmap合成输出图,
procedure TRei22.PatDz(Pnum:Byte;X1,Y1:Integer;Bmap,Zmap: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,Zmap.Canvas,RectL);
    end
    else begin
      Bmap.Canvas.CopyMode := cmSrcCopy;
      Bmap.Canvas.CopyRect(RectD,Zmap.Canvas,RectL);

    end;
end;

procedure TRei22.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  LoadBmap.Free;
  XpatBmap.Free;
  BackBmap.Free;
  MakeBmap.Free;
  BpatBmap.Free;
  Z1Bmap.Free;
  Z2Bmap.Free;
  Z3Bmap.Free;
  Z4Bmap.Free;
  Z5Bmap.Free;
end;

procedure TRei22.Timer1Timer(Sender: TObject);
var
  n, Cn :Byte;
begin
  ChMove;
  MakeBmap.Canvas.CopyMode := cmSrcCopy;
  RectB := Rect(0,0,DYoko,Dtate);
  RectM := Rect(16,16,DYoko+ 16,Dtate + 16) ;
  MakeBmap.Canvas.CopyRect(RectM,BackBmap.Canvas,RectB);     //复制背景点阵图

  for Cn := 0 to 3 do
    with ChPon[Cn] do
      if (Used <> 0 ) and (Sban <> 0 ) then
      begin
        if Dtim <> 0 then
          for n := 5 downto 1 do        //5拖影
            if (DlyX[n * Dtim] <> Xpos) or (DlyY[n * Dtim] <> Ypos)   //不重叠
            then               //dtim 间隔
            ChrDz(n,SpSiz[Sban * 2],SpSiz[Sban * 2 + 1],SpPon[DlyS[n * Dtim]],
              DlyX[n * Dtim] + 16,DlyY[n* Dtim] + 16,MakeBmap);

          ChrDz(0,SpSiz[Sban * 2],SpSiz[Sban * 2 + 1],SpPon[Sban],  //主图案
            Xpos + 16,Ypos + 16,MakeBmap);

      end;
  Rei22.Canvas.CopyMode := cmSrcCopy;
  RectD := Rect(0,0,DYoko,Dtate);
  Rei22.Canvas.CopyRect(RectD,MakeBmap.Canvas,RectM);


end;

end.

 

1。角色的记录里面的元素更多了,加入了历史的角色图案和X,Y坐标,用数组来记录

2,MkDpat有点难以理解,

   应该还是对笔刷,COPYMODE ,去除用模板,图像重叠的原理,还有相应函数的掌握不够,

   需要对以前的例子进行复习。

3.利用WIHT DO 对记录里面的元素进行操作,极大的简化的程序两,

  看起来简洁多了,

  但是我从网上的一篇DELPHI7规范里面看到,最好不要用WITH进行操作?

4,路径 的逻辑复杂了,掺杂了 CASE ,if,then,else then 的条件判断,但在良好的缩进和 CNPACK 加持下,还是能够直观的看明白的。

5,贴图函数改了一点,其实是取不同的图样?

posted @ 2022-08-09 15:46  D7mir  阅读(109)  评论(0)    收藏  举报