不重叠随机圆的JAVASCRIPT程序实现

在设计一个游戏时,需要随机生成不重叠的森林树木。关键在于随机生成树木大小和位置。实现方法包括建立坐标地图,随机生成半径和坐标,尝试放置并检测碰撞。通过优化,只需检测周围一定范围内的树木碰撞,提高效率。修复后的代码实现了更自然的树木分布效果。

最近在设计一个游戏,游戏中需要随机生成森林树木,如何让树木显得随机自然确实是个难题。一个是树木的大小需要随机,然后是树木的位置需要随机,这两个是关键,其它诸如颜色、形状等等属性的变化则不是大问题。


至于将不同大小的树木种植到平地上的问题其实可以简化为在一个平面上摆放互不重叠的随机大小的圆。


具体实现思路:


1. 建立一个n,n的矩阵作为树木可能出现的坐标地图。

2. 随机生成树木半径尺寸和坐标位置。

3. 尝试将树木放入矩阵对应坐标位置。

4. 检测该位置周边一个小范围框内是否有别的树木,两个树木间是否会发生碰撞,如果碰撞则放弃,如果不碰撞则直接植入这个树。

这一步是最关键最复杂的。由于树木尺寸有个最大限定,所以可以确定每次只需要检测周边最大树木尺寸和当前树木尺寸之和范围内树木是否碰撞即可,无需每次和已经植入的所有树木全部检测碰撞,于是可以大大节约计算量。










<!DOCTYPE html>
<HTML>

<HEAD>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,target-densitydpi=high-dpi,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0, user-scalable=no"/>
<TITLE></TITLE>

<STYLE TYPE="TEXT/CSS">
	body{
		margin:0px;
		padding:0px;		
		overflow:hidden;
	}
	div{
		position:absolute;
		margin:0px;
		padding:0px;
		background-color:rgba(255,0,0,0.5);
	}

</STYLE>

<SCRIPT TYPE="TEXT/JAVASCRIPT">

	function init(){
		
		//初始化布局数组
		var position=new Array();
		for(var i=0;i<100;i++){
			position[i]=new Array();
			for(var j=0;j<100;j++){
				position[i][j]={radius:0,isPlanted:0,isSet:0};
			}
		}
		
		//随机种植树木
		var treeCount=1000;
		//树木最大半径
		var treeRadiusMax=3;
		
		for(var i=0;i<treeCount;i++){
			
			//随机选择一个位置来种植一棵树
			var treeX=Math.floor(Math.random()*100);
			var treeY=Math.floor(Math.random()*100);			
			
			if(position[treeX][treeY].isSet==1){
				//如果该位置已经植入树木则跳过后续操作
				continue;
			}
			//树木直径随机
			var treeRadius=treeRadiusMax*Math.random();
			treeRadius=Math.max(0.5,treeRadius);
			
			//初始设定为可以种植			
			position[treeX][treeY].radius=treeRadius;	
			position[treeX][treeY].isPlanted=1;
						
			checkStartX=Math.max(treeX-Math.ceil(treeRadius)-treeRadiusMax,0);
			checkStartY=Math.max(treeY-Math.ceil(treeRadius)-treeRadiusMax,0);
			checkEndX=Math.min(treeX+Math.ceil(treeRadius)+treeRadiusMax,99);
			checkEndY=Math.min(treeY+Math.ceil(treeRadius)+treeRadiusMax,99);
			
			
			for(var x=checkStartX;x<=checkEndX;x++){
				for(var y=checkStartY;y<=checkEndY;y++){
					if((treeX==x&&treeY==y)==false){
						
						//比较两点间距离和两点半径和的大小 判断是否重叠						
						var treeDistanceSquared=(treeX-x)*(treeX-x)+(treeY-y)*(treeY-y);						
						var radiusSumSquared=(position[x][y].radius+treeRadius)*(position[x][y].radius+treeRadius);
						
						if(treeDistanceSquared<radiusSumSquared){
							//发生碰撞则标记不可种植							
							position[treeX][treeY].radius=0;
							position[treeX][treeY].isPlanted=0;
						}					
						
					}					
				}				
			}
			
			
			if(position[treeX][treeY].isPlanted==1){
			
				position[treeX][treeY].isSet=1;	
				
				//显示结果图形
				var factor=10;
				var elementSize=position[treeX][treeY].radius*factor*2;
				var elementRadius=position[treeX][treeY].radius*factor;
				var elementLeft=treeX*factor-position[treeX][treeY].radius;
				var elementTop=treeY*factor-position[treeX][treeY].radius;				

				showResult(i,elementSize,elementRadius,elementLeft,elementTop);						
							
			}
			
		}//植树完毕
				
	}//初始化完毕
	
	
	
	function showResult(i,elementSize,elementRadius,elementLeft,elementTop){
	
		var treeElement=document.createElement("div");	

		treeElement.setAttribute("id","tree"+i);
		treeElement.style.width=elementSize+"px";
		treeElement.style.height=elementSize+"px";
		treeElement.style.borderRadius=elementRadius+"px";				
		treeElement.style.left=elementLeft+"px";
		treeElement.style.top=elementTop+"px";	
		treeElement.style.backgroundColor="rgba("+Math.floor(Math.random()*256)+","+Math.floor(Math.random()*256)+","+Math.floor(Math.random()*256)+","+"0.9)";	
							
		document.body.appendChild(treeElement);		
	}

	window.onload=function(){
		init();
	}

</SCRIPT>

</HEAD>

<BODY>
	
</BODY>

</HTML>


加了空白区域控制,并调大树木数量后的效果是这样的



<!DOCTYPE html>
<HTML>

<HEAD>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,target-densitydpi=high-dpi,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0, user-scalable=no"/>
<TITLE></TITLE>

<STYLE TYPE="TEXT/CSS">
	body{
		margin:0px;
		padding:0px;		
		overflow:hidden;
	}
	div{
		position:absolute;
		margin:0px;
		padding:0px;
		background-color:rgba(255,0,0,0.5);
	}

</STYLE>

<SCRIPT TYPE="TEXT/JAVASCRIPT">

	function init(){
		
		//初始化布局数组
		var position=new Array();
		for(var i=0;i<100;i++){
			position[i]=new Array();
			for(var j=0;j<100;j++){
				position[i][j]={radius:0,isPlanted:0,isSet:0};
			}
		}
		
		//随机种植树木
		var treeCount=500;
		//树木最大半径
		var treeRadiusMax=3;
		
		for(var i=0;i<treeCount;i++){
			
			//随机选择一个位置来种植一棵树
			var treeX=Math.floor(Math.random()*100);
			var treeY=Math.floor(Math.random()*100);	
			
			//不种植的区域排除掉
			var vacantStartX=25;
			var vacantEndX=75;
			var vacantStartY=25;
			var vacantEndY=75;
			
			if(treeX>=vacantStartX&&treeX<=vacantEndX&&treeY>=vacantStartY&&treeY<=vacantEndY){
				//如果在不种植区则跳过后续操作
				continue;
			}
			
			if(position[treeX][treeY].isSet==1){
				//如果该位置已经植入树木则跳过后续操作
				continue;
			}
			//树木直径随机
			var treeRadius=treeRadiusMax*Math.random();
			treeRadius=Math.max(0.5,treeRadius);
			
			//初始设定为可以种植			
			position[treeX][treeY].radius=treeRadius;	
			position[treeX][treeY].isPlanted=1;
						
			checkStartX=Math.max(treeX-Math.ceil(treeRadius)-treeRadiusMax,0);
			checkStartY=Math.max(treeY-Math.ceil(treeRadius)-treeRadiusMax,0);
			checkEndX=Math.min(treeX+Math.ceil(treeRadius)+treeRadiusMax,99);
			checkEndY=Math.min(treeY+Math.ceil(treeRadius)+treeRadiusMax,99);
			
			
			for(var x=checkStartX;x<=checkEndX;x++){
				for(var y=checkStartY;y<=checkEndY;y++){
					if((treeX==x&&treeY==y)==false){
						
						//比较两点间距离和两点半径和的大小 判断是否重叠						
						var treeDistanceSquared=(treeX-x)*(treeX-x)+(treeY-y)*(treeY-y);						
						var radiusSumSquared=(position[x][y].radius+treeRadius)*(position[x][y].radius+treeRadius);
						
						if(treeDistanceSquared<radiusSumSquared){
							//发生碰撞则标记不可种植							
							position[treeX][treeY].radius=0;
							position[treeX][treeY].isPlanted=0;
						}					
						
					}					
				}				
			}
			
			
			if(position[treeX][treeY].isPlanted==1){
			
				position[treeX][treeY].isSet=1;	
				
				//显示结果图形
				var factor=10;
				var elementSize=position[treeX][treeY].radius*factor*2;
				var elementRadius=position[treeX][treeY].radius*factor*2;
				var elementLeft=treeX*factor-position[treeX][treeY].radius;
				var elementTop=treeY*factor-position[treeX][treeY].radius;				

				showResult(i,elementSize,elementRadius,elementLeft,elementTop);						
							
			}
			
		}//植树完毕
				
	}//初始化完毕
	
	
	
	function showResult(i,elementSize,elementRadius,elementLeft,elementTop){
	
		var treeElement=document.createElement("div");	

		treeElement.setAttribute("id","tree"+i);
		treeElement.style.width=elementSize+"px";
		treeElement.style.height=elementSize+"px";
		treeElement.style.borderRadius=elementRadius+"px";				
		treeElement.style.left=elementLeft+"px";
		treeElement.style.top=elementTop+"px";	
		treeElement.style.backgroundColor="rgba("+Math.floor(Math.random()*256)+","+Math.floor(Math.random()*256)+","+Math.floor(Math.random()*256)+","+"0.9)";	
							
		document.body.appendChild(treeElement);		
	}

	window.onload=function(){
		init();
	}

</SCRIPT>

</HEAD>

<BODY>
	
</BODY>

</HTML>


the above codes have some bugs, and I have fixed them, the flowing images show these effects:




the corrected functions:


<!DOCTYPE html>
<HTML>

<HEAD>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,target-densitydpi=high-dpi,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0, user-scalable=no"/>
<TITLE></TITLE>

<STYLE TYPE="TEXT/CSS">
	body{
		margin:0px;
		padding:0px;		
		overflow:hidden;
	}
	div{
		position:absolute;
		margin:0px;
		padding:0px;
		background-color:rgba(255,0,0,0.5);
	}

</STYLE>

<SCRIPT TYPE="TEXT/JAVASCRIPT">

	function init(){
		
		//初始化布局数组
		var position=new Array();
		for(var i=0;i<100;i++){
			position[i]=new Array();
			for(var j=0;j<100;j++){
				position[i][j]={radius:0,isPlanted:0};
			}
		}
		
		//随机种植树木
		var treeCount=10000;
		//树木最大半径
		var treeRadiusMax=5;
		
		for(var i=0;i<treeCount;i++){
			
			//随机选择一个位置来种植一棵树
			var treeX=Math.floor(Math.random()*100);
			var treeY=Math.floor(Math.random()*100);	
			
			//不种植的区域排除掉
			var vacantStartX=25;
			var vacantEndX=75;
			var vacantStartY=25;
			var vacantEndY=75;
			
			if(treeX>=vacantStartX&&treeX<=vacantEndX&&treeY>=vacantStartY&&treeY<=vacantEndY){
				//如果在不种植区则跳过后续操作
				continue;
			}
			
			if(position[treeX][treeY].isPlanted==1){
				//如果该位置已经植入树木则跳过后续操作
				continue;
			}
			//树木直径随机
			var treeRadius=treeRadiusMax*Math.random();
			treeRadius=Math.max(0.5,treeRadius);
			
			//初始设定为可以种植			
			position[treeX][treeY].radius=treeRadius;	
			position[treeX][treeY].isPlanted=1;
			
			//计算检测框范围
			checkStartX=Math.max(treeX-Math.ceil(treeRadius)-treeRadiusMax,0);
			checkStartY=Math.max(treeY-Math.ceil(treeRadius)-treeRadiusMax,0);
			checkEndX=Math.min(treeX+Math.ceil(treeRadius)+treeRadiusMax,99);
			checkEndY=Math.min(treeY+Math.ceil(treeRadius)+treeRadiusMax,99);
			
			
			for(var x=checkStartX;x<=checkEndX;x++){
				for(var y=checkStartY;y<=checkEndY;y++){
					//除了当前位置 和框定范围内已经植入的树木比较距离
					if(!(treeX==x&&treeY==y)&&(position[x][y].isPlanted==1)){						
						//比较两点间距离和两点半径和的大小 判断是否重叠						
						var treeDistanceSquared=(treeX-x)*(treeX-x)+(treeY-y)*(treeY-y);						
						var radiusSumSquared=(position[x][y].radius+treeRadius)*(position[x][y].radius+treeRadius);
						
						if(treeDistanceSquared<radiusSumSquared){
							//发生碰撞则标记不可种植							
							position[treeX][treeY].radius=0;
							position[treeX][treeY].isPlanted=0;
						}					
						
					}					
				}				
			}
			
			
			if(position[treeX][treeY].isPlanted==1){			
				
				//显示结果图形
				var factor=6;
				var elementSize=position[treeX][treeY].radius*factor*2;
				var elementRadius=position[treeX][treeY].radius*factor*2;
				var elementLeft=(treeX-position[treeX][treeY].radius)*factor;
				var elementTop=(treeY-position[treeX][treeY].radius)*factor;				

				showResult(i,elementSize,elementRadius,elementLeft,elementTop);						
							
			}
			
		}//植树完毕
				
	}//初始化完毕
	
	
	
	function showResult(i,elementSize,elementRadius,elementLeft,elementTop){
	
		var treeElement=document.createElement("div");	

		treeElement.setAttribute("id","tree"+i);
		treeElement.style.width=elementSize+"px";
		treeElement.style.height=elementSize+"px";
		treeElement.style.borderRadius=elementRadius+"px";				
		treeElement.style.left=elementLeft+"px";
		treeElement.style.top=elementTop+"px";	
		treeElement.style.backgroundColor="rgba("+Math.floor(Math.random()*256)+","+Math.floor(Math.random()*256)+","+Math.floor(Math.random()*256)+","+"0.9)";	
							
		document.body.appendChild(treeElement);		
	}

	window.onload=function(){
		init();
	}

</SCRIPT>

</HEAD>

<BODY>
	
</BODY>

</HTML>


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值