您好,欢迎访问一九零五行业门户网

详细介绍HTML5实现3D迷宫的代码案例

功能描述:
左右方向键控制玩家的方向,上下方向键控制玩家的前进和后退。
效果预览:
实现原理:
在上面的效果预览中,可以看到右边是2d的平面地图,而左边的则是第一人称的3d视图,这两幅图的关系是非常密切的,实质上,实现3d视觉的过程,就是依据2d地图把地图转换成第一人称视觉的过程。
3d效果的实现只局限于平面(意思是从侧面看没有立体效果),在这种有局限性的3d效果中,我们以一个个物体为单位,通过不同物体平面之间的视觉差实现3d。而在这次的效果中,为了使物体从不同角度看都能具有立体效果,我们把单位从平面改成线。
首先,我们创建一个叫视觉平面的东西,它像一面镜子,把实物投影到一个平面上,首先初始化该平面的尺寸:
screensize:[320,240],//视觉屏幕尺寸
之后,我们可以以1像素为单位,只要知道物体每个像素在该视觉平面上显示出来的高度,就可以绘制出物体在第一人称视觉上的效果。
以视觉平面上的第一个像素线段为例,根据比例可得知:玩家到视觉平面的距离/玩家到物体的实际距离=物体在视觉平面上的高度/物体的实际高度。由于玩家到视觉平面的距离和物体的实际高度我们可以自己定义,因此我们只要知道玩家到物体的距离,就可以知道物体该像素在视觉平面的高度。
怎样知道玩家到物体的实际距离呢?这时我们就需要借助和3d视觉图密切相关的2d地图了。首先,我们定义玩家的最大视觉角度为60度(意思是玩家的视觉范围角度),由于我们现在处理的是平面的第一条像素线,因此该像素线相对于玩家的角度就为-30度。在地图上,我们可以知道玩家的x,y位置和玩家的方向,因此我们就可以知道第一条像素线在地图上的方向。
在2d地图上怎么表示3d视觉平面上的一条像素线呢?其实仔细想想就可以发现,3d视觉平面中的一条像素线,相当于2d地图上特定方向上发出的一条射线,射线与物体的交点就是3d视觉平面中的那条像素线的内容。因此,只要我们计算出该射线的长度(起点:玩家位置 终点:射线和物体相交的位置),就可以知道玩家与物体的距离,从而求得改像素的物体在视觉平面上的高度。
最后只要循环遍历视觉平面上的每一条1px宽的像素线,并根据2d地图上对应射线的长度,就可以求得视觉平面上所有视觉范围内的物体每一像素的高度,形成3d视觉效果。
代码分析:
主要看实现的核心代码,循环遍历视觉平面上每条像素线,绘制出该像素线上的物体内容:
var context=this.screencontext; context.clearrect(0,0,this.screensize[0],this.screensize[1]); context.fillstyle="rgb(203,242,238)"; context.fillrect(0,0,this.screensize[0],this.screensize[1]/2); context.fillstyle="rgb(77,88,87)"; context.fillrect(0,this.screensize[1]/2,this.screensize[0],this.screensize[1]/2);
由于该效果需要两个canvas(一个显示地图,一个显示3d视觉图),因此我们首先获取3d视觉图上的canvas,并绘制地面和天空。
//cngame.context.beginpath(); for(var index=0,colcount=this.screensize[0]/this.viewcolwidth;index<colcount;index++){ screenx=-this.screensize[0]/2+index*this.viewcolwidth;//该竖线在屏幕的x坐标 colangle=math.atan(screenx/this.screendistant);//玩家的视线到屏幕上的竖线所成的角度 colangle%=2*math.pi; var angle=this.player.angle/180*(math.pi)-colangle;//射线在地图内所成的角度 angle%=2*math.pi; if(angle<0){ angle+=2*math.pi; } distant=0; x=0; y=0; centerx=this.player.x+(this.player.width)/2;//玩家中点x坐标 centery=this.player.y+(this.player.height)/2;//玩家中y坐标 while(this.map.getposvalue(centerx+x,centery-y)==0){ distant+=1; x=distant*math.cos(angle); y=distant*math.sin(angle); } //如果射线在地图遇到墙壁,则画线 /*cngame.context.strokestyle="#000"; cngame.context.moveto(centerx,centery); cngame.context.lineto(centerx+x,math.floor(centery-y)); cngame.context.closepath(); */ distant*=math.cos(colangle);//防止鱼眼效果 heightinscreen=this.screendistant/(distant)*this.wallsize[2];//根据玩家到墙壁的距离计算墙壁在视觉平面的高度 var img=cngame.loader.loadedimgs[srcobj.stone2]; context.drawimage(img,0,0,2,240,this.viewcolwidth*index,(this.screensize[1]-heightinscreen)/2, this.viewcolwidth,heightinscreen) }
之后,就可以开始循环遍历每条像素线,绘制出物体内容。在处理每条像素线的过程中,我们让射线每次增加1像素的长度,当射线遇到非空地的时候(getposvalue(x,y)>0),就停止增长,并记录下此时射线的长度,该长度就是玩家到该像素线内容的实际距离。
上面代码中,注释掉的部分其实就是用于绘制出发射的射线,如果大家有需要,可以恢复该部分的代码,就可以看到玩家的视觉范围。
需要注意的是,由于视觉平面有区别人的眼球(是一个平面而非球体),因此我们还需要使距离乘上玩家视觉角度的余弦值,从而避免了鱼眼效果。
最后,我们还可以在3d视觉图上绘制出玩家(拿枪的手),达到更好的效果。
以上就是详细介绍html5实现3d迷宫的代码案例的详细内容。
其它类似信息

推荐信息