首页 > 编程语言 >Delphi 经典游戏程序设计40例 的学习 例36 不可思议的房间和迷宫

Delphi 经典游戏程序设计40例 的学习 例36 不可思议的房间和迷宫

时间:2022-11-06 16:55:43浏览次数:35  
标签:Box 10 begin end Delphi Random 36 40 Tline

 

 

 

unit R36;

interface

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

type
  TRoom = record       //房间记录类型
    Used : Byte;
    Xpos : Byte;       //区块位置
    Ypos : Byte;
    Xsiz : Byte;       //区块大小
    Ysiz : Byte;
    UX : Byte;         //上侧出入口位置
    UY : Byte;
    DX : Byte;         //下侧
    DY : Byte;
    LX : Byte;         //左侧
    LY : Byte;
    RX : Byte;         //右侧
    RY : Byte;
  end;


  TRei36 = 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);
  private
    { Private declarations }
    procedure MkRoom;
    procedure MkMaze;
    procedure Tline(a,b:Byte);
    procedure Lway;
    procedure Mway;
    procedure Rway;
    procedure DiMaze;
  public
    { Public declarations }
  end;
const
  Mwidth = 50 * 10 + 20;     //迷宫宽度
  Mheight = 30 * 10 + 20;    //迷宫高度
var
  Rei36: TRei36;
  MakeBmap : TBitmap;
  RectD : TRect;
  St,m,max : Byte;

  Mdata : array[0..49,0..29] of Byte;      //迷宫数组50*30点
  Box : array[0..14] of TRoom;             //房间数组 15房间 ,记录数组类型
  
implementation

{$R *.dfm}

procedure TRei36.FormCreate(Sender: TObject);
begin
  Rei36.Canvas.CopyMode := cmSrcCopy;
  MakeBmap := TBitmap.Create;
  MakeBmap.Width := Mwidth;
  MakeBmap.Height := Mheight;

  St := 1;       //初始迷宫制作指令
  Randomize;

end;

procedure TRei36.MkRoom;       //制作房间参数
var
  n : byte;
begin
  for n := 0 to 14 do
    Box[n].Used := 0;     //房间清零
  max := 5 + Random(5);   //最大5+4个房间?
  m := 0;
  repeat
    n := Random(15);
    if (Odd(n) = False) and (Box[n].Used = 0) then     //保证偶数块有房间3个
    begin
      Box[n].Used := 1;
      m := m + 1;
    end;
  until m = 4;

  repeat                             //随机房间数量到MAX
    n := Random(15);
    if (n <> 7) and (Box[n].Used = 0) then
    begin
      Box[n].Used := 1;
      m := m + 1;
    end;
  until m > max;

  for n := 0 to 14 do
    with Box[n] do
    begin
      if Used = 1 then
      begin                //设置房间大小,最小4+0+0=4,最大4+2+3=9
        Xsiz := 4 + ((n + 1) mod 2) * 2 + Random(4);   //这里为什么要引入n?
        Ysiz := 4 + ((n + 1) mod 2) * 2 + Random(4);   //实际是为了控制奇区4-7,偶区6-9
      end
      else begin          //非房间大小
        Xsiz := 4;
        Ysiz := 4;
      end;
      //设置房间位置,注意非房间也有位置的。放中间
      Xpos := (n mod 5) * 10 + (10 - Xsiz) div 2; //5列,取余得到X块
      Ypos := (n div 5) * 10 + (10 - Ysiz) div 2; //取商得到Y块

      if Used = 1 then
      begin
        UX := Xpos + 1 + Random(Xsiz - 2);   //上出口
        UY := Ypos;
        DX := Xpos + 1 + Random(Xsiz - 2);   //下出口
        DY := Ypos + Ysiz - 1;
        LX := Xpos;                          //左出口
        LY := Ypos + 1 + Random(Ysiz - 2);
        RX := Xpos + Xsiz - 1;               //右出口
        RY := Ypos + 1 + Random(Ysiz - 2);
      end
      else begin
        UX := Xpos;
        UY := Ypos;
        DX := UX;
        DY := UY;
        LX := UX;
        LY := UY;
        RX := UX;
        RY := UY;
      end;
    end;

    for n := 0 to 3 do           //左右间隙小于3则修改成直连  ?
      if Box[n + 1].LX - Box[n].RX <= 3 then
      begin
        Box[n].RY := 4 + Random(2);
        Box[n + 1].LY := Box[n].RY;
      end;
    for n:= 5 to 8 do
      if Box[n + 1].LX - Box[n].RX <= 3 then
      begin
        Box[n].RY := 14 + Random(2);
        Box[n + 1].LY := Box[n].RY;
      end;

    for n := 10 to 13 do
      if Box[n + 1].LX - Box[n].RX <= 3 then
      begin
        Box[n].RY := 24 + Random(2);
        Box[n + 1].LY := Box[n].RY;
      end;

    for n := 0 to 4 do              //上下间隙间隙小于3则修改成直连
    begin
      if Box[n + 5].UY - Box[n].DY <= 3 then
      begin
        Box[n].DX := 4 + Random(2) + n * 10;
        Box[n + 5].UX := Box[n].DX;
      end;
      if Box[n + 10].UY - Box[n + 5].DY <= 3 then
      begin
        Box[n + 5].DX := 4 + Random(2) + n * 10;
        Box[n + 10].UX := Box[n].DX;
      end;
    end;

end;


procedure TRei36.MkMaze;
var
  x,y,n : Byte;
begin
  for x := 0 to 49 do
    for y := 0 to 29 do
      Mdata[x,y] := 1;    //全设置为墙
  for n := 0 to 14 do
    if Box[n].Used = 1 then
      for x := Box[n].LX to Box[n].RX do
        for y := Box[n].UY to Box[n].DY do
          Mdata[x,y] := 2;   //设置为房间
  Lway;
  Mway;
  Rway;

end;


procedure TRei36.Tline(a,b:Byte);  //制作通道
var
  nn,mx,my : Byte;
begin
  if (b-a) = 1 then        //房间相邻
  begin     //横向连接
    mx := Box[b].LX - (Box[b].LX - Box[a].Xpos - Box[a].Xsiz + 2) div 2; //取得一个中间点
    for nn := Box[a].RX to mx do
      Mdata[nn,Box[a].RY] := Mdata[nn,Box[a].RY] and 2; //通道穿过房间还是10B,穿过墙则是00B
    for nn := mx to Box[b].LX do
      Mdata[nn,Box[b].LY] := Mdata[nn,Box[b].LY] and 2;

    if Box[a].RY > Box[b].LY then        //从中间点开始连接
      for nn := Box[b].LY to Box[a].RY do
        Mdata[mx,nn] := Mdata[mx,nn] and 2
    else if Box[a].RY < Box[b].LY  then  //这里为什么要重复判断?
      for nn := Box[a].RY to Box[b].LY  do
        Mdata[mx,nn] := Mdata[mx,nn] and 2;
  end
  else begin     //不相邻则纵向连接?
    my := Box[b].UY - (Box[b].UY - Box[a].Ypos- Box[a].Ysiz + 2) div 2;
    for nn := Box[a].DY  to my do
      Mdata[Box[a].DX,nn] := Mdata[Box[a].DX,nn] and 2;
    for nn := my to Box[b].UY do
      Mdata[Box[b].UX,nn] := Mdata[Box[b].UX,nn] and 2;
    if Box[a].DX > Box[b].UX then
      for nn := Box[b].UX to Box[a].DX do
        Mdata[nn,my] := Mdata[nn,my] and 2
    else  if Box[a].DX < Box[b].UX then
      for nn := Box[a].DX to Box[b].UX do
        Mdata[nn,my] := Mdata[nn,my] and 2;
  end;

end;


procedure TRei36.Lway;         //0 1 5 6 10 11 左侧房间连接规则
begin
  if Random(2) = 0 then
  begin
    Tline(0,1);
    Tline(0,5);
    Tline(1,6);
    if (Box[5].Used and Box[6].Used = 0) or (Random(2) = 0) then
      Tline(5,6);
    if Box[10].Used = 1 then
    begin
      Tline(5,10);
      if Random(2) = 0 then
        Tline(10,11)
      else
        Tline(6,11);

    end
    else if Random(2) =0 then
    begin
      Tline(5,10);
      Tline(10,11);
    end
    else
      Tline(6,11);

  end
  else begin
    Tline(10,11);
    Tline(5,10);
    Tline(6,11);
    if (Box[5].Used and Box[6].Used = 0) or (Random(2) = 0) then
      Tline(5,6);
    if Box[0].Used = 1 then
    begin
      Tline(0,5);
      if Random(2) = 0 then
        Tline(0,1)
      else
        Tline(1,6);
    end
    else if  Random(2) = 0 then
    begin
      Tline(0,5);
      Tline(0,1);

    end
    else
      Tline(1,6);
  end;
end;


procedure TRei36.Mway;   //1 2 3 11 12 13 的中侧房间连接规则
begin
  case Random(4) of
    0: begin
      Tline(1,2);
      Tline(2,3);
      Tline(11,12);
      if Random(2) = 0 then
        Tline(12,13);
    end;
    1: begin
      Tline(1,2);
      Tline(2,3);
      Tline(12,13);
      if Random(2) = 0 then
        Tline(11,12);
    end;
    2: begin
      Tline(11,12);
      Tline(12,13);
      Tline(1,2);
      if Random(2) = 0 then
        Tline(2,3);
    end;
    3: begin
      Tline(11,12);
      Tline(12,13);
      Tline(2,3);
      if Random(2) = 0 then
       Tline(1,2);
    end;
  end;
end;


procedure TRei36.Rway;   // 3 4 8 9 13 14  右侧房间连接规则
begin
  if Random(2) = 0 then        // 随机
  begin
    Tline(3,4);     //将3,4 3,8 4,9 房间连接起来
    Tline(3,8);
    Tline(4,9);
    if (Box[8].Used and Box[9].Used = 0) or (Random(2) = 0) then
      Tline(8,9);   //当8与9的其中之一不是房间时,以随机数将8,9连接起来
    if Box[14].Used = 1 then     //若14是房间
    begin
      Tline(9,14);              //连接9,14
      if Random(2) = 0 then     //再将13,14 或 8,13连接
        Tline(13,14)
      else
        Tline(8,13);
    end
    else if Random(2) = 0 then   //14不是房间
    begin                        // 连接9,14 13 14 或 8,13
      Tline(9,14);
      Tline(13,14);
    end
    else
      Tline(8,13);
  end
  else begin                 //随机另一规则
    Tline(13,14);
    Tline(8,13);
    Tline(9,14);
    if (Box[8].Used and Box[9].Used = 0) or (Random(2) = 0) then
      Tline(8,9);
    if Box[4].Used = 1 then
    begin
      Tline(4,9);
      if Random(2) = 0 then
        Tline(3,4)
      else
        Tline(3,8);
    end
    else if  Random(2) = 0 then
    begin
      Tline(3,4);
      Tline(4,9);
    end
    else
      Tline(3,8);
  end;

end;
procedure TRei36.DiMaze;      //在制作画板上以10*10 的块显示Mdata数组
var
  x,y : Byte;
begin
  for x := 0 to 49 do
    for y := 0 to 29 do
      begin
        case Mdata[x,y] of
          0: MakeBmap.Canvas.Brush.Color := clBlack;
          1: MakeBmap.Canvas.Brush.Color := clOlive;
          2: MakeBmap.Canvas.Brush.Color := clNavy;
        end;
        RectD := Rect(x * 10 + 10,y * 10 + 10,x * 10 + 20,y * 10 + 20);
       // RectD := Rect(x + 10,y + 10,x + 10 + 1,y + 10 + 1); //缩小比例
        MakeBmap.Canvas.FillRect(RectD);
      end;
end;

procedure TRei36.Button1Click(Sender: TObject);
begin
  St := 2;
end;

procedure TRei36.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  MakeBmap.Free;
end;

procedure TRei36.Timer1Timer(Sender: TObject);
begin
  case St of
    1: begin          //绘制外框
      RectD := Rect(0,0,Mwidth,Mheight);
      MakeBmap.Canvas.Brush.Color := clOlive;
      MakeBmap.Canvas.FillRect(RectD);
      RectD := Rect(10,10,Mwidth - 20,Mheight - 20);
      MakeBmap.Canvas.Brush.Color := clBlack;
      MakeBmap.Canvas.FillRect(RectD);
      Rei36.Canvas.Draw(0,0,MakeBmap);
      St := 2;
    end;
    2: begin       //制作新的迷宫显示出来,按钮控制
      MkRoom;      //制作房间参数
      MkMaze;
      DiMaze;
      Rei36.Canvas.Draw(0,0,MakeBmap);
      St := 0;
    end;

  end;
end;

end.

 

1,迷宫,一个二维的数组,对它进行0,1,2 的写入,里面有几个过程,或者叫做类的方法

    写入 墙1 ,房间 2,通道0的数据

2,一个数组元素代表一个点,最后是用一个10* 10 像素的方块表示出来,做了下用1 * 1 的方块表现出来

3,程序结构大致是 设定好迷宫大小 50 × 30,分成 15个块

  这15个块 有一定规则随机生成5-9 个房间,生成房间数据

4,按照左,中,右侧,有一定规则,对其侧房间进行通道连接

5,感觉就是人为规则的实现,其中是有限限度随机变化?

6,必须看书本上的图示来理解,然后自己手绘出来有助于理解

 

标签:Box,10,begin,end,Delphi,Random,36,40,Tline
From: https://www.cnblogs.com/D7mir/p/16862998.html

相关文章