>웹 프론트엔드 >H5 튜토리얼 >HTML5에서 3D 미로를 구현하는 코드 사례에 대한 자세한 소개

HTML5에서 3D 미로를 구현하는 코드 사례에 대한 자세한 소개

黄舟
黄舟원래의
2017-03-24 15:41:082331검색

기능 설명:

왼쪽 및 오른쪽 방향 키는 플레이어의 방향을 제어하고, 위쪽 및 아래쪽 방향 키는 플레이어의 전진 및 후진 이동을 제어합니다.

효과 미리보기:

 HTML5에서 3D 미로를 구현하는 코드 사례에 대한 자세한 소개

구현원리:

위 효과 미리보기를 보면 오른쪽은 2D 평면 지도이고, 왼쪽은 1인칭 3D 뷰라는 것을 알 수 있습니다. 두 사진의 관계는 본질적으로 매우 가깝습니다. , 3D 비전을 구현하는 과정은 지도를 2D 지도를 기반으로 1인칭 비전으로 변환하는 과정입니다.

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);

이 효과에는 두 개의

캔버스(하나는 지도 표시용, 하나는 3D 시각 지도 표시용)가 필요하므로 먼저 3D 시각 지도 위에 캔버스를 가져와 땅을 그립니다. 그리고 하늘.

//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으로 문의하세요.