不重叠随机圆的JAVASCRIPT程序实现
2017-12-15 15:25
651 查看
最近在设计一个游戏,游戏中需要随机生成森林树木,如何让树木显得随机自然确实是个难题。一个是树木的大小需要随机,然后是树木的位置需要随机,这两个是关键,其它诸如颜色、形状等等属性的变化则不是大问题。
至于将不同大小的树木种植到平地上的问题其实可以简化为在一个平面上摆放互不重叠的随机大小的圆。
具体实现思路:
1. 建立一个n,n的矩阵作为树木可能出现的坐标地图。
2. 随机生成树木半径尺寸和坐标位置。
3. 尝试将树木放入矩阵对应坐标位置。
4. 检测该位置周边一个小范围框内是否有别的树木,两个树木间是否会发生碰撞,如果碰撞则放弃,如果不碰撞则直接植入这个树。
这一步是最关键最复杂的。由于树木尺寸有个最大限定,所以可以确定每次只需要检测周边最大树木尺寸和当前树木尺寸之和范围内树木是否碰撞即可,无需每次和已经植入的所有树木全部检测碰撞,于是可以大大节约计算量。
加了空白区域控制,并调大树木数量后的效果是这样的
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. 建立一个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>
相关文章推荐
- 基于JavaScript实现简单的随机抽奖小程序
- 基于JavaScript实现简单的随机抽奖小程序
- 使用Java程序实现随机验证码功能的实例
- JavaScript实现为指定对象添加多个事件处理程序的方法
- 基于javascript实现随机颜色变化效果
- php+javascript实现的动态显示服务器运行程序进度条功能示例
- javascript实现简单的可随机变色网页计算器示例
- html中使用javascript调用本地程序(exe、doc等)实现代码
- javascript实现10个球随机运动、碰撞实例详解
- javascript中巧用“闭包”实现程序的暂停执行功能
- javascript实现的平方米、亩、公顷单位换算小程序
- 网络121第3周实验——实现随机点名的签到程序
- 微信小程序答题系统实现随机出题 答题小程序如何实现随机出题 微信小程序 答题系统
- 使用javascript做的一个随机点名程序
- javascript 随机抽奖程序代码
- 第三周作业-实现随机点名的签到程序 第四需求,非头像版
- javascript 实现倒计时程序
- javascript随机抽签程序
- javascript实现随机生成DIV背景色