Delphi 经典游戏程序设计40例 的学习 例37 在迷宫中追赶对手

unit R37; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls; type TRei37 = class(TForm) Button1: TButton; Timer1: TTimer; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure Timer1Timer(Sender: TObject); procedure FormPaint(Sender: TObject); private { Private declarations } procedure WtMove; procedure RdMove; procedure Ncheck(X1,Y1,Dr: Byte); procedure Gnext(var X1: Byte;var Y1: Byte;Dr: Byte); procedure DiMaze; public { Public declarations } end; const Xmax = 28; //迷宫的宽度-1 Ymax = 20; //迷宫的高度-1 Mwidth = (Xmax + 1) * 16 + 32; Mheight = (Ymax + 1) * 16 + 32; var Rei37: TRei37; MakeBmap: TBitmap; St,x,y,Wtime: Byte; WX,WY,WD: Byte; //白点的坐标,方向 RX,RY,RD: Byte; //红点的坐标,方向 See : Byte; //0-3 看得到白点的方向,255看不到 Mem : Byte; // 0追赶中,1白点转弯时,255平常的时候 PX,PY,PD: Byte; // 追赶时,白点转弯后的坐标,方向 RectD: TRect; Dmap: array[0..3] of Byte; //求出DINF[] 准备的数据 字节数组,一维,长度4 Dinf: array[0..4] of Byte; //能够移动的方向编号 //迷宫数据数组 Mdata: array[0..Xmax,0..Ymax] of Byte = ( (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), (0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0), (0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0), (0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0), (0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0), (0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0), (0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0), (0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0), (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), (0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0), (0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0), (0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0), (0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0), (0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0), (0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0), (0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0), (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), (0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0), (0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0), (0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0), (0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0), (0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0), (0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0), (0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0), (0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0), (0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0), (0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0), (0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0), (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) ); implementation {$R *.dfm} procedure TRei37.FormCreate(Sender: TObject); begin Rei37.Canvas.CopyMode := cmSrcCopy; MakeBmap := TBitmap.Create; MakeBmap.Height := Mheight; MakeBmap.Width := Mwidth; St := 1; Randomize; end; procedure TRei37.WtMove; //移动白点 begin with Rei37 do Canvas.Brush.Color := clBlack; //擦除原坐标白点 Canvas.Ellipse(WX * 16 + 19,WY * 16 + 19,WX * 16 + 29,WY * 16 + 29); Ncheck(WX,WY,WD); //检查白点能够前往的位置 if (Dinf[0] = 1) or (Dinf[0] = 2) then //优先直行? WD := Dinf[1] else WD := Dinf[1 + Random(Dinf[0] - 1)]; //如果3,4个方向则随即选择方向? Gnext(WX,WY,WD); //按指定方向改变白点坐标 Canvas.Brush.Color := clWhite; //绘制新坐标白点 Canvas.Ellipse(WX * 16 + 19,WY * 16 + 19,WX * 16 + 29,WY * 16 + 29); end; procedure TRei37.RdMove; //移动红点 var n : Byte; begin with Rei37 do Canvas.Brush.Color := clBlack; //擦除原红点 Canvas.Ellipse(RX * 16 + 19,RY * 16 + 19,RX * 16 + 29,RY * 16 + 29); Ncheck(RX,RY,RD); //检查红点能够前往的位置 if (WY = RY) and (WX > RX) then //在同Y轴上,且白点在右 begin See := 0; //0-3 看得到白点的方向0,255看不到 for n := RX + 1 to WX do if Mdata[n,RY] <> 0 then //检查白红点间有墙 See := 255; end else if (WX = RX) and (WY < RY) then //在同X轴上,且白点在上 begin See := 1; //看得到白点的方向1 for n := RY -1 downto wy do if Mdata[RX,n] <> 0 then See := 255; end else if (WY = RY) and (WX < RX) then //在同Y轴上,且白点在左 begin See := 2; //看得到白点的方向2 for n := RX -1 downto WX do if Mdata[n,RY] <> 0 then See := 255; end else if (WX = RX) and (WY > RY) then //在同X轴上,且白点在下 begin See := 3; //看得到白点的方向3 for n := RY + 1 to WY do if Mdata[RX,n] <> 0 then See := 255; end; if See < 4 then begin if (RD = See) or (Dinf[0] > 2) or (Dinf[1] <> RD) then begin //红点同向或迷宫3出口,或第一选择出口不是红点选择 RD := See; //红点方向同 Mem := 0; // 0追赶中,1白点转弯时,255平常的时候 end; //进入追赶状态 See := 255; //否则看不到? end else if Mem = 0 then //追赶状态下进入白点转弯状态 begin PX := WX; PY := WY; PD := WD; Mem := 1; end else if Mem = 1 then //白点转弯状态下进入追丢目标状态 begin if (RX = PX) or (RY = PY) then //如果红点在原白点X或Y直线上 begin RD := PD; //选择白点原转弯的方向 Mem := 255; //进入追丢目标状态 end; end else if Dinf[0] <= 2 then RD := Dinf[1] //如2方向优先选择右转? else RD := Dinf[1 + Random(Dinf[0] - 1)]; //3方向及以上红点随即选择方向 Gnext(RX,RY,RD); // //按指定方向改变红点坐标 Canvas.Brush.Color := clRed; //刷新红点 Canvas.Ellipse(RX * 16 + 19,RY * 16 + 19,RX * 16 + 29,RY * 16 + 29); end; procedure TRei37.Ncheck(X1,Y1,Dr: Byte); var //检查能够前往的位置 n: Byte; begin if X1 < Xmax then //取得右,X1+1方向数据 Dmap[0] := Mdata[X1 + 1,Y1] //一维数组,二维数组,元素相同,而对下标值进行计算 else //边界判断 Dmap[0] := 1; if Y1 > 0 then //取得上,数据,及边界判断 Dmap[1] := Mdata[X1,Y1 - 1] else Dmap[1] := 1; if X1 > 0 then //取得左数据,及边界判断 Dmap[2] := Mdata[X1 - 1,Y1] else Dmap[2] := 1; if Y1 < Ymax then //取得下数据,及边界判断 Dmap[3] := Mdata[X1,Y1 + 1] else Dmap[3] := 1; n := 1; if Dmap[Dr] = 0 then //指定方向能够通过 begin Dinf[n] := Dr; n := n + 1; //能通过的方向+1 end; if Dmap[(Dr + 1) and 3] = 0 then //指定方向逆时针位可通过,左侧 begin Dinf[n] := (Dr + 1) and 3; n := n + 1; end; if Dmap[(Dr -1) and 3] = 0 then //指定方向顺时针位可通过,右侧 begin Dinf[n] := (Dr - 1) and 3; n := n + 1; end; if Dmap[(Dr + 2) and 3] = 0 then //指定方向的反方向可通过,后侧 begin Dinf[n] := (Dr + 2) and 3; n := n + 1; end; Dinf[0] := n - 1; //得到可以通过的方向数, end; procedure TRei37.Gnext(var X1: Byte;var Y1: Byte;Dr: Byte); //按各个方向依次改变坐标 begin case Dr of 0: X1 := X1 + 1; //右 1: Y1 := Y1 - 1; //上 2: X1 := X1 - 1; //左 3: Y1 := Y1 + 1; // 下 end; end; procedure TRei37.DiMaze; //显示迷宫 var x,y : Byte; begin RectD := Rect(0,0,Mwidth,Mheight); MakeBmap.Canvas.Brush.Color := clOlive; MakeBmap.Canvas.FillRect(RectD); MakeBmap.Canvas.Brush.Color := clBlack; for x := 0 to Xmax do for y := 0 to Ymax do if Mdata[x,y] <> 1 then begin RectD := Rect(x * 16 + 16,y * 16 + 16,x * 16 + 32,y * 16 + 32); MakeBmap.Canvas.FillRect(RectD); end; Rei37.Canvas.Draw(0,0,MakeBmap); end; procedure TRei37.Button1Click(Sender: TObject); begin St := 2; with Rei37 do Canvas.Brush.Color := clBlack; Canvas.Ellipse(WX * 16 + 19,WY * 16 + 19,WX * 16 + 29,WY * 16 + 29); Canvas.Ellipse(RX * 16 + 19,RY * 16 + 19,RX * 16 + 29,RY * 16 + 29); end; procedure TRei37.FormClose(Sender: TObject; var Action: TCloseAction); begin MakeBmap.Free; end; procedure TRei37.Timer1Timer(Sender: TObject); begin case St of 0: begin Wtime := Wtime xor 1; //异或翻转 设置开关 if (WX = RX) and (WY = RY) then //判断捕捉到 begin with Rei37 do //红白闪烁 if Wtime = 0 then Canvas.Brush.Color := clRed else Canvas.Brush.Color := clWhite; Canvas.Ellipse(WX * 16 + 19,WY * 16 + 19,WX * 16 + 29,WY * 16 + 29); end else begin WtMove; //白点移动 if (WX <> RX) or (WY <> RY) then //这里为什么要判断? RdMove; //红点移动 end; end; 1: begin DiMaze; //绘出迷宫 St := 2; end; 2: begin //重置 St := 0; See := 255; Mem := 255; repeat WX := Random(Xmax + 1); WY := Random(Ymax + 1); WD := Random(4); until Mdata[WX,WY] = 0; //白点必须随机设置在走道内 repeat RX := Random(Xmax + 1); RY := Random(Ymax + 1); RD := Random(4); until (Mdata[RX,RY] = 0) and (Abs(WX - RX) > 8) and (Abs(WY - RY) > 6); end; //红点随机在走道内,并保持和白点的距离 end; end; procedure TRei37.FormPaint(Sender: TObject); begin Rei37.Canvas.Draw(0,0,MakeBmap); end; end.
1,迷宫的实现,一个二维的数组,下标 作为 一个可以运算的序数,可以当作 红白点 的X,Y 的值来计算
其元素值 ,作为 墙和通道,1,0,当然作为一个BYTE 类型 数,可以有更多的表示,
例如天空,草地,大树,石头,箱子,可以移动的物体等等,256种
或者多个二维数组,实现 多层。
2,IF THEN ELSE IF THEN ELSE ELSE 。。。的多层使用,
条件的判断,实现什么逻辑?
3,迷宫数据转换成可以行进的方向的判断