首頁  >  文章  >  web前端  >  詳細介紹HTML5實作3D迷宮的程式碼案例

詳細介紹HTML5實作3D迷宮的程式碼案例

黄舟
黄舟原創
2017-03-24 15:41:082294瀏覽

功能描述:

  左右方向鍵控制玩家的方向,上下方向鍵控制玩家的前進和後退。

效果預覽:

  詳細介紹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迷宮的程式碼案例的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn