Delphi 经典游戏程序设计40例 的学习 例20 对应于大画面的大闪电

unit R20; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls; type TRei20 = class(TForm) Timer1: TTimer; procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure Timer1Timer(Sender: TObject); private { Private declarations } procedure PatDi(Pnum : Byte;X1,Y1 :Integer;Bmap : TBitmap); procedure Thunder(X1,Y1,X2,Y2:Integer; Col,Ran:Byte;Bmap : TBitmap); public { Public declarations } end; const Yoko = 37; Tate = 27; DYoko = Yoko * 16; DTate = Tate * 16; PtFull = 16; var Rei20: TRei20; LoadBmap,XpatBmap,BackBmap,MakeBmap : TBitmap; RectL,RectB,RectM,RectD : TRect; PX,PY,TC : Byte; RS : LongInt; //虚拟随机数的SEED 值? Tree : array[0..200] of Integer; //转折点存储数组,格式0索引,X1,Y1;X2,Y2; implementation {$R *.dfm} procedure TRei20.FormCreate(Sender: TObject); var X,Y : Byte; begin Rei20.Height := 480; Rei20.Width := 640; LoadBmap := TBitmap.Create; LoadBmap.LoadFromFile(GetCurrentDir + '\Pat_Sample.bmp'); XpatBmap := TBitmap.Create; XpatBmap.Height := 256; XpatBmap.Width := 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); BackBmap := TBitmap.Create; BackBmap.Height := DTate; BackBmap.Width := DYoko; for Y := 0 to (Tate -1 ) do for X := 0 to (Yoko - 1) do begin if Y <= 25 then PatDi(2,X * 16,Y * 16,BackBmap) else PatDi(7,X * 16,Y * 16,BackBmap); if Y = 25 then PatDi(16,X * 16,Y * 16,BackBmap); end; MakeBmap := TBitmap.Create; MakeBmap.Height := DTate + 32; MakeBmap.Width := DYoko + 32; //随机数初始化 Randomize; end; // x1,y1,x2,y2 闪电区域,col 闪电颜色0黄色1白色 ,ran 是否重现闪电0 新,1重现 procedure TRei20.Thunder(X1,Y1,X2,Y2:Integer; Col,Ran:Byte;Bmap : TBitmap); const Tmax = 12; // 最大分支数 ? var Xadd,TX,TY :Integer; Yadd,Tran,Tn,Mc :Byte; begin //制作闪电 Tree[0] := 0; Bmap.Canvas.Pen.Width := 2; case Col of 0: Bmap.Canvas.Pen.Color := clYellow; 1: Bmap.Canvas.Pen.Color := clWhite; end; if Ran = 0 then //ran 是否重现闪电0 新,1重现 RS := RandSeed else RandSeed := RS; for Tn := 0 to Tmax do //最大分支? begin Yadd := 12 + Random(20); if Tree[0] = 0 then begin TY := Y1; TX := X1 + 50 + Random(X2 - X1 - 100); end else begin Tran := Random(Tree[0]) + 1; //为什么随机找一个存储的坐标? TX := Tree[Tran * 2 -1]; TY := Tree[Tran * 2]; end; if TX < X1 + ( X2- X1 ) div 3 then Xadd := 16 + Random(16 - Tn) else if TX > x2 - (X2 - X1) div 3 then Xadd := -16 - Random(16 - Tn ) else Xadd := 16 + Tn - Random(33 + Tn * 2); Bmap.Canvas.MoveTo(TX,TY); // 设置好了线段的起点 TX,TY Mc := 0 ; //符合条件就不断的画线? while(TX + Xadd - 16 > X1 ) and (TX + Xadd + 16 <= X2 ) and (TY + Yadd <= Y2) and (Random(Tmax - Tn + 1) + 4 > Mc ) do begin Mc := Mc + 1; TY := TY + Yadd; TX := TX + Xadd - 16 + Random(33); Bmap.Canvas.LineTo(TX,TY); //存储一个合适的 坐标点? 这里为什么还要判断 TX,TY? if {(TX > X1 + 50) and (TX < X2 - 50) and (TY < Y2 - 100 ) and } (Tree[0] < 100) then begin Tree[0] := Tree[0] + 1; Tree[Tree[0] * 2 -1] := TX; Tree[Tree[0] * 2] := TY; end; end; end; end; procedure TRei20.FormClose(Sender: TObject; var Action: TCloseAction); begin LoadBmap.Free; XpatBmap.Free; MakeBmap.Free; BackBmap.Free; end; procedure TRei20.Timer1Timer(Sender: TObject); begin 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); TC := ( TC + 1 ) and 31; case TC of 0 : Thunder(10 + 16,16,582 + 16,400 + 16,1,0,MakeBmap); 1 : Thunder(10 + 16,16,582 + 16,400 + 16,0,1,MakeBmap); 2 : Thunder(10 + 16,16,582 + 16,400 + 16,1,1,MakeBmap); 7 : Thunder(10 + 16,16,582 + 16,400 + 16,1,1,MakeBmap); 8 : Thunder(10 + 16,16,582 + 16,400 + 16,1,1,MakeBmap); 9 : Thunder(10 + 16,16,582 + 16,400 + 16,1,0,MakeBmap); end; //这里自动缩放大小了 Rei20.Canvas.CopyMode := cmSrcCopy; RectD := Rect(0,0,ClientWidth,ClientHeight); Rei20.Canvas.CopyRect(RectD,MakeBmap.Canvas,RectM); end; procedure TRei20.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; end.
还是没有看明白闪电按照什么算法画出来的,
程序结构是TIME中调用闪电函数,在窗口显示出来
闪电函数负责画线