기능 설명:
왼쪽 및 오른쪽 방향 키는 플레이어의 방향을 제어하고, 위쪽 및 아래쪽 방향 키는 플레이어의 전진 및 후진 이동을 제어합니다.
효과 미리보기:
구현원리:
위 효과 미리보기를 보면 오른쪽은 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) }
광선이 비어 있지 않은 영역(getPosValue (x, y) > 0)을 만나면 성장이 멈추고 기록 이때 광선의 길이는 플레이어에서 픽셀 라인의 내용까지의 실제 거리입니다.
위 코드에서에서 주석 처리한 부분은 실제로 방출된 광선을 그리는 데 사용됩니다. 필요한 경우 코드의 이 부분을 복원하면 볼 수 있습니다. 플레이어의 시각적 범위.
시각 평면은 인간의 안구와 다르기 때문에(구가 아닌 평면)따라서 거리에 플레이어 시각의 코사인을 곱해야 한다는 점에 유의해야 합니다. 피쉬아이 효과를 피하기 위한 각도 .
마지막으로 3D 시각적 지도에 플레이어(총을 들고 있는 손)를 그려서 더 나은 결과를 얻을 수도 있습니다.위 내용은 HTML5에서 3D 미로를 구현하는 코드 사례에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!