java实现一个随机迷宫_【小白学游戏常用算法】一、随机迷宫算法

本文介绍了如何使用Java实现一个随机迷宫生成器,主要基于普利姆算法。首先,通过初始化一个全为1的二维数组来表示障碍,然后随机选择一个空格作为起点,不断遍历其未访问的相邻空格,打通墙壁,直至所有空格都被访问。最终生成的迷宫满足连通性,适合游戏地图的随机生成。
摘要由CSDN通过智能技术生成

现在的很多游戏中的地图一般采用格子的方式,虽然在表面地图上无法看到实际的格子,但是在地图的结构中专门有一个逻辑层,这个层和地图大小相等,划出很多小的格子,然后在可以通过的地方使用0表示,在有障碍的且不能通过的地方用1或者其他数字表示(如图所示)。有了这个逻辑层之后,实际上自动寻路就转换成了如何在一个二维数组中找出一条从逻辑值为0的地点移动到目标的路径。在寻路之前,我们首先要随机生成这些地图。

735eb46bc74a7597c9dfdd9019980b21.png    

f7c95a2e2155d86da2742792df94fc38.png

游戏中地图      二维数组逻辑层

本质上,地图的障碍逻辑层是由一个二维数组保存的。障碍标记在二维数组中的数据值以0或者1表示,我们首先需要做的就是随机产生这样的二维数组。当然,最简单的办法就是循环这个二维数组,然后在每一个位置随机地产生0或者1,但是这种算法产生的图形比较难看,并且不一定保证图中的任意两点可以相连通。

在随机生成的迷宫中要求任意两点,都可以找到一条路径相通,所以在图论中可以认为迷宫就是一个连通图。产生连通图的常见方法有克鲁斯卡尔和普利姆算法,这里我们以普利姆算法为例实现一下,使用普利姆算法产生的迷宫比较自然和随机。

19f74908e983e2b78647bdd724f15120.png

(1)如上图所示为一个6x6的迷宫,先假设迷宫中所有的通路都是完全封闭的,黄色的格子表示可以通过,黑色的格子表示墙壁或者障碍不能通过。

(2)随机选择一个黄色的格子作为当前正在访问的格子,同时把该格子放入一个已经访问的列表中。

(3)循环以下操作,直到所有的格子都被访问到。

1.得到当前访问格子的四周(上下左右)的格子,在这些格子中随机选择一个没有在访问列表中的格子,如果找到,则把该格子和当前访问的格子中间的墙打通(置为0),把该格子作为当前访问的格子,并放入访问列表。

2.如果周围所有的格子都已经访问过,则从已访问的列表中,随机选取一个作为当前访问的格子。

通过以上的迷宫生成算法,可以生成一个自然随机的迷宫、

下面使用代码实现一个R行N列大小的随机迷宫,R行表示的是刚开始空白格子的行数,而格子之间还有墙壁和障碍物,所以最终产生的二维数组大小实际为2R+1 * 2N+1

69c5a8ac3fa60e0848d784a6dd461da6.png

1 //产生随机迷宫

2 primMaze:function(r,c)

3 {

4 //初始化数组

5 function init(r,c)

6 {

7 var a = new Array(2*r+1);

8 //全部置1

9 for(var i=0,len=a.length;i

10 {

11 var cols = 2*c+1;

12 a[i]= new Array(cols);

13 ArrayUtil.fillWith(a[i],1);

14 }

15 //中间格子为0

16 for(var i=0;i

17 for(var j=0;j

18 {

19 a[2*i+1][2*j+1] = 0;

20 }

21 return a;

22 }

23 //处理数组,产生最终的数组

24 function process(arr)

25 {

26 //acc存放已访问队列,noacc存放没有访问队列

27 var acc = [],noacc = [];

28 var r = arr.length>>1,c=arr[0].length>>1;

29 var count = r*c;

30 for(var i=0;i

31 //定义空单元上下左右偏移

32 var offs=[-c,c,-1,1],offR=[-1,1,0,0],offC=[0,0,-1,1];

33 //随机从noacc取出一个位置

34 var pos = MathUtil.randInt(count);

35 noacc[pos]=1;

36 acc.push(pos);

37 while(acc.length

38 {

39 var ls = -1,offPos = -1;

40 offPos = -1;

41 //找出pos位置在二维数组中的坐标

42 var pr = pos/c|0,pc=pos%c,co=0,o=0;

43 //随机取上下左右四个单元

44 while(++co<5)

45 {

46 o = MathUtil.randInt(0,5);

47 ls =offs[o]+pos;

48 var tpr = pr+offR[o];

49 var tpc = pc+offC[o];

50 if(tpr>=0&&tpc>=0&&tpr<=r-1&&tpc<=c-1&&noacc[ls]==0){ offPos = o;break;}

51 }

52 if(offPos<0)

53 {

54

55 pos = acc[MathUtil.randInt(acc.length)];

56 }

57 else

58 {

59 pr = 2*pr+1;

60 pc = 2*pc+1;

61 //相邻空单元中间的位置置0

62 arr[pr+offR[offPos]][pc+offC[offPos]]=0;

63 pos = ls;

64 noacc[pos] = 1;

65 acc.push(pos);

66 }

67 }

68 }

69 var a = init(r,c);

70 process(a);

71 return a;

72 }

69c5a8ac3fa60e0848d784a6dd461da6.png

利用上面的算法我们就可以实现一个类似于下面的随机迷宫了。

3bbcff8c4651808d137866255281bed5.png

有了随机迷宫就得开始寻路了,下一篇的博客中我们将一起学习一下最常见的A*寻路算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值