오랫동안 캔버스를 사용하지 않았기 때문에 작은 게임 테트리스를 작성하면서 캔버스에 다시 익숙해졌습니다. 어느 정도 캔버스 기반이 있다면 구현하는 것은 어렵지 않습니다.
원리에 대한 자세한 설명게임의 최종 인터페이스를 살펴보면 다음과 같은 주요 기능을 구현해야 함을 알 수 있습니다.
전체 패널은 왼쪽 위 모서리(0,0)를 원점으로 하고 오른쪽 위 모서리(12,0), 왼쪽 아래 모서리(0,20), 오른쪽 아래 모서리(12,20)를 갖는 좌표계입니다. ) 각 점의 좌표 위치를 결정할 수 있습니다. 사각형이 채워졌는지 여부에 관계없이 각 사각형을 배열 요소로 생각할 수 있습니다. 0은 채워지지 않았음을 의미하고 1은 채워졌음을 의미합니다. 12*20 패널은 2개의 배열 레이어를 사용합니다. 즉, 길이가 12인 20개의 배열이 구현됩니다.
var 맵 = [[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,1,0 ,1,0], ...];
패널을 그리는 코드는 가장 기본적인 캔버스 API를 사용하여 구현할 수 있습니다.
//그리드 for(var i=0;i<12;i++){ for(var j=0;j<20;j++){ ctx.fillRect(i*40,j*40,40,40); 스트로크Rect(i*40,j*40,40,40); if(this.maps[j][i]==1){//사각형이 콘텐츠로 채워졌습니다. ctx.save(); ctx.lineWidth=4; ctx.fillStyle='hsla(200,100%,50%,.5)'; ctx.StrokeStyle='hsla(200,100%,50%,.9)'; j*40,40,40); ctx.StrokeRect(i*40+2,j*40+2,38,38); ctx.restore(); } } } //테두리 ctx.lineWidth=4;hsla(0,100%,0 %,.3)'; ctx.moveTo(0,0); ctx.lineTo(12*40,20*40); ctx.lineTo(12*40,0); ctx.restore();블록 구현
게임에는 다음 7가지 그래픽이 사용됩니다.
위에서 소개한 좌표계와 결합하여 배열 [x1, y1, x2, y2, x3, y3, x4, y4]는 위 그래픽의 4개 점 좌표를 나타내는 데이터입니다. 다음과 같이:
변수 도착 = [[4,0,4,1,5,1,6,1],[4,1,5,1,6,1,6,0],[4,0,5,0,5,1, 6,1],[4,1,5,0, 5,1,6,0],[5,0,4,1,5,1,6,1],[4,0,5,0,6,0,7,0],[5,0, 6,0,5,1,6,1]];
블록을 이동하려면 전체 배열을 탐색하고 변위 벡터를 추가하면 됩니다. 매우 간단합니다.
class Shape { constructor(m){ this.m = Object.ass([],m); } move(x,y){ // 변위 var m = this.m, l = m.length; |0; for (var i=0;i<l;i=i+2){ m[i]+=x; m[i+1]+=y }
블록 회전 왼쪽, 오른쪽, 위아래로 움직이는 것 외에도 테트리스의 블록도 회전합니다. 그렇죠? 조금만 생각해 보면 이것이 단지 행렬 변환이라는 것을 알게 될 것입니다. 즉, 모양이 중심점을 중심으로 90도 회전할 때마다 발생합니다. 물론 이 처리는 완벽하지 않습니다.
class Shape { 변환(){//2차원 행렬 변환 var m =this.m, l = m.length, c = Math.ceil(l/2), x = m[c], y = m[c+ 1], cos = Math.cos(Math.PI/180 * 90), sin = Math.sin(Math.PI/180 * 90) for (var i=0;i<l;i=i+2) { if(i == c) 계속; var mx = m[i]- x, my = m[i+1] - y, nx = mx*cos - my*sin, ny = my*cos + mx*sin; m[i]=x+nx; m[i+1]=y+ny } 이것을 반환합니다;경계 조건
그것은 주로 다음 세 가지 측면을 포함합니다
배열을 탐색합니다. (1) 임의 지점의 y 좌표가 19이면 바닥에 도달했음을 의미합니다. (2) 지도에서 좌표의 y+1 위치에 대한 정보를 가져옵니다. 채워졌습니다. 두 경우 모두 이동하는 블록의 주기가 끝나면 맵에 해당하는 배열에 블록의 좌표를 채워 넣으면 됩니다.
좌표의 y+1이 채워지고 현재 좌표가 1보다 작은 경우, 즉 이미 인터페이스의 상단에 있는 경우 게임이 종료됩니다.
var isEnd = false,isOver=false,x,y;for(var i=0,sl=that.shape.m.length;i<sl;i=i+2){ x=that.shape.m[i ]; y=that.shape.m[i+1]; if(y >= 19){ // 하단 isEnd = true;break } if(that.maps[y+1][x]== 1){ // y+1 위치가 채워졌습니다. isEnd = true; if(y <= 1){isOver=true;} // 게임이 끝났습니다. }}
블록 이동 주기가 끝나면 각 레이어가 가득 찼는지 확인하고, 사각형 이후의 처리는 가득 찼는지 확인합니다. 특정 배열의 모든 요소가 1이면 그리드가 가득 찼음을 의미합니다. 그런 다음 배열을 삭제하고 동시에 각 요소가 0인 배열을 목록의 헤드에 푸시합니다.
checkPoint(){ var that = this, map = that.maps; for(var i=0,l=maps.length;i<l;i++){ if(Math.min.apply(null,maps[i]) == 1){// 레이어가 가득 찼음을 나타냅니다. that.maps.splice(i,1); // 점수를 높이세요 that.maps.unshift([0,0,0,0,0,0,0,0,0,0,0,0]) } } return this;}바인딩 이벤트
가장 중요한 것은 keydown 이벤트를 바인딩하는 것입니다. 왼쪽 Shift 및 오른쪽 Shift 이벤트에는 경계 판단이 포함된다는 점에 유의해야 합니다.
binEvent(){ var that = this; document.addEventListener('keydown',function(e){ switch(e.keyCode){ 사례 13: //cancelAnimationFrame(that.timer) 입력; that.init().update( ); 중단; 사례 80: //p that.pause = !that.pause; 사례 40: //down that.d = 0.5; //왼쪽 var over = false, 지도 = that.maps, 모양 = that.shape, m = 모양.m for(var i=0,l=m.length;i<l;i=i+2){ if(m[i]<=0 || 지도[m[i+1]][m[i]-1] == 1){ over = true;break } } if(!over) Shape.move( -1,0); 39: //오른쪽 var over = false, 모양 = that.shape, 지도 = that.maps, m = 모양.m for(var i=0,l=m.length;i<l;i=i+2 ){ if(m[i]>=11 || map[m[i+1]][m[i]+1] == 1){ over = true;break } } if(!over) 모양. 이동(1,0); 사례 32: //space that.shape.transform(); break; } },false);요약
테트리스의 가장 기본적인 기능은 여기에 구현되지만 레벨과 같은 기능적 포인트는 구현되지 않은 동시에 데모에는 수정해야 할 불완전성이 있습니다.
위의 내용은 이 기사의 전체 내용입니다. 모든 분들의 학습에 도움이 되기를 바랍니다. 또한 모든 분들이 VeVb Wulin Network를 지지해 주시길 바랍니다.