您的位置:首页 > Web前端 > JavaScript

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

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

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

具体实现思路:

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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息