HTML 5实现3D迷宫

开发 前端
在之前的一篇文章:《javascript实现3D房间》中,3D效果的实现只局限于平面(意思是从侧面看没有立体效果),在这种有局限性的3D效果中,我们以一个个物体为单位,通过不同物体平面之间的视觉差实现3D。而在这次的效果中,为了使物体从不同角度看都能具有立体效果,我们把单位从平面改成线。

功能描述:

左右方向键控制玩家的方向,上下方向键控制玩家的前进和后退。

效果预览:

 

51CTO推荐专题:HTML 5 下一代Web开发标准详解

实现原理:

在上面的效果预览中,可以看到右边是2D的平面地图,而左边的则是***人称的3D视图,这两幅图的关系是非常密切的,实质上,实现3D视觉的过程,就是依据2D地图把地图转换成***人称视觉的过程。

在之前的一篇文章:《javascript实现3D房间》中,3D效果的实现只局限于平面(意思是从侧面看没有立体效果),在这种有局限性的3D效果中,我们以一个个物体为单位,通过不同物体平面之间的视觉差实现3D。而在这次的效果中,为了使物体从不同角度看都能具有立体效果,我们把单位从平面改成线。

首先,我们创建一个叫视觉平面的东西,它像一面镜子,把实物投影到一个平面上,首先初始化该平面的尺寸:

screenSize:[320,240],//视觉屏幕尺寸 
  • 1.

之后,我们可以以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); 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

由于该效果需要两个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.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.

之后,就可以开始循环遍历每条像素线,绘制出物体内容。在处理每条像素线的过程中,我们让射线每次增加1像素的长度,当射线遇到非空地的时候(getPosValue(x,y)>0),就停止增长,并记录下此时射线的长度,该长度就是玩家到该像素线内容的实际距离。

上面代码中,注释掉的部分其实就是用于绘制出发射的射线,如果大家有需要,可以恢复该部分的代码,就可以看到玩家的视觉范围。

需要注意的是,由于视觉平面有区别人的眼球(是一个平面而非球体),因此我们还需要使距离乘上玩家视觉角度的余弦值,从而避免了鱼眼效果。

***,我们还可以在3D视觉图上绘制出玩家(拿枪的手),达到更好的效果。

完整demo下载:点击下载

原文:http://www.cnblogs.com/Cson/archive/2012/02/27/2368955.html

【编辑推荐】

  1. HTML 5中的文件处理之FileAPI
  2. HTML 5 Canvas组件绘制太极图案
  3. HTML 5开发:地理位置定位指南
  4. 一句代码实现HTML 5淘宝语音搜索
  5. 使用HTML 5和CSS3制作登录页面完整步骤
责任编辑:陈贻新 来源: Cson's Room
相关推荐

2014-09-12 10:30:51

HTML5热力图

2012-04-24 15:07:49

HTML5

2015-10-08 08:48:37

HTML53D网络拓扑树

2015-06-26 11:51:26

HTML5JavaScript

2009-12-14 08:58:25

HTML5网页3DWebGL

2012-06-16 16:57:52

WebGL

2014-02-24 11:43:44

HTML5机房监控

2011-05-26 10:55:39

2021-09-16 07:52:18

SwiftUScroll效果

2022-09-19 19:16:42

轮播图has

2011-05-26 10:08:14

2011-10-06 13:30:45

宏碁投影仪

2017-07-12 23:08:03

白鹭引擎

2012-11-26 12:51:44

木材3D打

2023-05-26 07:08:05

CSS模糊实现文字

2010-06-09 10:50:08

OpenSUSE 3D

2019-11-18 10:22:01

深度学习编程人工智能

2015-12-07 09:05:37

HTML5动画源码

2015-04-03 11:40:08

Cocos 2015

2011-05-26 10:05:07

优派投影机
点赞
收藏

51CTO技术栈公众号