정보실

웹학교

정보실

javascript 테트리스 턴 35 (2)

본문

테트로 미노 


4 개의 사각형으로 구성된 7 가지 클래식 패턴을 테트로미노라고합니다.


1*lkdxm0UQVwn3l4CYZugQYQ.png 

7 개의 테트로 미노의 클래식 세트.


긴 스틱은 3x3 상자에 맞지 않는 유일한 테트로미노입니다.


1*mDMc7i2sLVMpTfamNh1KkQ.png 

스틱은 4x4 그리드가 필요한 유일한 테트로미노이므로 홀수 볼 케이스입니다.


이 스틱을 따로 처리하거나 대신 모든 테트로미노를 4x4 어레이에 넣을 수 있습니다. 이 문제를 처리하는 방법에는 여러 가지가 있습니다. 이 자습서에서는 3x3 상자에 맞는 더 짧은 스틱을 사용합니다.


JavaScript 배열을 사용하여 테트로 미노를 나타냅니다.


1*pEbWIUa1M9uJhwGlnxtx4g.png 

기술적으로 2 차원 배열을 사용하여 9x9 테트로 미노를 나타낼 수 있습니다. 그러나 1 차원 배열로 표현할 수도 있습니다 (여기 그림 참조). 이렇게 하면 우물 격자에서 좀 더 쉽게 래스터화 할 수 있습니다.


실제로 테트로미노 중 하나를 나타내려면 0 대신 1을 사용하여 솔리드 파트를 지정합니다.

1*SNv4EQc1p5YO08tGpAuemw.png 

1 차원 배열을 사용하여 테트로미노를 정의하는 한 가지 방법.


이 방법으로 모든 테트로미노를 정의한 다음 이들을 모두 포함하는 전체 목록을 나타내는 하나의 배열에 배치 할 수 있습니다. 창의력을 발휘하려면 자신 만의 모양을 만들 수도 있습니다.


let A = [0,0,1,
0,0,1,
0,1,1];

let B = [1,0,0,
1,0,0,
1,1,0];

let C = [0,0,0,
0,1,0,
1,1,1];

let D = [0,0,0,
0,1,1,
1,1,0];

let E = [0,0,0,
1,1,0,
0,1,1];

let F = [1,1,0,
1,1,0,
0,0,0];

let G = [0,0,0,
1,1,1,
0,0,0]; 


그런 다음 모든 테트로미노를 다른 배열에 넣습니다.


let tetrominos = [A,B,C,D,E,F,G]; 


이런 식으로 Math.rand 함수를 사용하여 임의의 테트로미노를 생성 할 수 있습니다.


또한“다음”및“현재”테트로미노에 대한 자리 표시자가 필요합니다. 그것들을 각각 현재와 다음이라고 부릅니다.


let current = [0,0,0, 0,0,0, 0,0,0];
let next = [0,0,0, 0,0,0, 0,0,0]; 


무작위 테트로미노를 생성하는 기능은 다음과 같습니다.


// Generate a random tetromino and return it as 3x3 array
function make_random() {
// 1.) Select random tetromino from tetrominos array by index
let index = Math.floor((Math.random() * tetrominos.length));
// 2.) Copy it into current array (avoid reference assignment)
return [...tetrominos[ index ]];
}


여기서는… (rest / spread syntax)를 사용하여 배열의 복사본을 만들었습니다. 해당 배열을 변수에 할당하면 원래 tetromino에 대한 참조가 만들어집니다. 우리는 참조를 원하지 않습니다. 대신 메모리에 별도의 사본을 만듭니다. [... tetrominos [index]]를 반환하면 앞서 생성 한 tetrominos [] 배열에서 tetrominos 중 하나의 복사본을 만듭니다.


임의의 테트로미노를 생성하여 현재 또는 다음 변수에 저장하려면 :


current = make_random();
next = make_random(); 


테트로미노가 떨어지면 우물에 영구적으로 갇히고 나면 다음 전류와 전류를 교환 할 수 있습니다.


키보드 컨트롤 


키보드 컨트롤 소스 코드는 다음과 같습니다.


// Keyboard input
document.addEventListener("keydown", (e) => {

let key_code = e.keyCode;
// Erase the teetromino
erase();

// Left
if (key_code == 37) {
if (will_collide(dir.LEFT)) {
reset();
} else position.x -= 1
}

// Right
if (key_code == 39) {
if (will_collide(dir.RIGHT)) {
reset();
} else position.x += 1
}

// Down
if (key_code == 40) {
if (will_collide(dir.DOWN)) {
reset();
} else position.y += 1
}

if (key_code == 38) { position.y -= 1 }

// Rotate
if (key_code == 90) { rotate_left() }
if (key_code == 88) { rotate_right(); }
// Draw the current tetromino
draw();
});


떨어지는 애니메이션 


게임 루프는 지우기, 넘어짐 및 그리기 기능으로 구성됩니다.


이것이 떨어지는 블록의 환상을 만드는 것입니다.


// Game-loop Animation
setInterval(() => {
// Erase the current tetromino block from the well
erase();
// Progress the tetromino by 1 square down
fall();
// Draw the tetromino at its new fallen position
draw();

}, 15);


게임에서 setInterval 함수를 사용하는 것이 일반적입니다. 그러나 화면을 업데이트 하기 위한 것이 아닙니다. 사실, 그것은 약간 고르지 않습니다. 눈치 채지 못하는 유일한 이유는 테트리스 애니메이션이 상대적으로 느리기 때문입니다.


부드러운 애니메이션이 중요한 빠른 속도의 게임을 만드는 경우 requestAnimationFrame을 대신 사용합니다. 그러면 애니메이션이 모니터의 재생 빈도에 동기화 됩니다. 그러나 이 간단한 테트리스 게임에서는 결과가 거의 동일하기 때문에 실제로 그렇게 하는 것이 거의 의미가 없습니다.


또 다른 문제는 17 미만의 Edge 버전이며 Internet Explorer는 페인트 주기 전에 requestAnimationFrame을 안정적으로 시작하지 않습니다.


충돌 감지 


테트리스에는 두 가지 유형의 충돌이 있습니다. 벽과 떨어진 벽돌.


테트리스의 충돌 감지는 까다롭습니다. 벽돌이 벽, 우물 바닥 또는 다른 tetrominos와 물리적으로 이동하기 전에 한 애니메이션 단계와 충돌하는지 확인해야 합니다. 테트로미노를 다른 차단 영역 위에 두지 말고 그 위에 두지 않기를 원하기 때문입니다.


무슨 뜻인지 설명하기 위해 우물 바닥에서 떨어지는 테트로미노를 보여주는 이 애니메이션을 만들었습니다. 또는 벽을 접촉하여 칠하십시오. 이것이 피하고 싶은 상황입니다.


1*RHV-a2-6z4kls6CE1bT3dQ.gif 

"실시간"으로 충돌 감지를 작성하지 마십시오. 현재 블록이 현재 프레임이 아닌 다음 프레임에서 이동하는 방향으로 이동하면 현재 블록이 미래에 충돌하는지 확인해야 합니다. 그리고 향후 충돌이 발생하면 추가 이동을 방지하고 벽돌을 솔리드 블록과 함께 잘 붙입니다 (후자는 이 애니메이션에 표시되지 않음). 다음 섹션 중 하나에서 설명합니다.


참고 :이 단계에서는 벽과 우물 바닥과 만 충돌을 확인하려고 합니다. 이 시점에서 떨어진 블록간에 충돌이 없습니다. 우리는 나중에 블록을 우물에 붙여 넣고 고체로 표시하여 처리합니다.


(다음 섹션 중 하나에서 설명합니다.)


이 문제를 처리하기 위해 미래에 테트로미노에 어떤 일이 발생하는지 결정하는 기능을 작성할 수 있습니다. 한 블록이 왼쪽, 오른쪽 또는 아래쪽으로 이동 한 경우.


키보드 이벤트를 가로 채서 그렇게 할 수 있습니다. 키를 누르면 이 기능은 새로운 위치로 이동 한 tetromino가 벽 또는 다른 블록과 충돌하는지 알려줍니다. 향후 위치에 충돌이 없으면 블록을 그곳으로 이동합니다. 그렇지 않으면 우리는 well array에 block을 붙여 넣고 그것을 solid block으로 표시하고 다음 tetromino를 생성합니다.


이 고립 된 예를 살펴 보겠습니다.


// Left arrow key is pressed
if (key_code == 37) {
// Will tetromino collide with walls or if it is moved left?
if (will_collide( dir.LEFT ))
reset();
else
// Tetromino will not collide, move to that position
position.x -= 1;
} 


will_collide 함수가 true를 반환하면 뷰를 재설정 합니다. reset () 함수는 실제로 현재 위치의 웰에 tetromino를 붙여 넣습니다.


다음은 reset() 및 past() 함수 목록입니다.


reset() 

재설정 함수는 도우미 기능에 가깝습니다. paste(), clear_row(), make_random(), update_next()를 호출하고 the fog of darkness를 지웁니다.


function reset() {
paste(); // paste current tetromino onto the well
clear_row(); // clear rows if any
current = [...next]; // swap current and next tetromino
next = make_random(); // generate next tetromino
update_next(); // Update "next" box

// reset current position to top and middle of the well
position.x = parseInt(width/2) - 1;
position.y = -3;

reset_fog(); // clear the fog of darkness
} 


paste() 


// "paste" current block onto the well
function paste() {
let index = 0; // Prevent pasting blocks that fall outside of the well:
if (position.x >= 0 && position.x <= width - 1) {
if (position.y >= -3 && position.y <= height - 1) {
// Iterate over the 3x3 block of tetromino:
for (let y = position.y; y < position.y + 3; y++) {
for (let x = position.x; x < position.x + 3;
x++, index++) {
// If tetromino is solid at that square
if (current[index] == 1) {
let id = "square_x" + x + "y" + y;
let sq = document.getElementById(id);
if (sq) {
well[x][y] = 3;
sq.style.backgroundColor = color.solid;
}
}
}
}
}
}
}


erase() 


paste()와 동일하며 현재 떨어지는 테트로미노를 모두 0으로 설정하여 우물 배열에서 효과적으로 제거합니다 (다음 위치로 애니메이션 하기 전에).


페이지 정보

조회 48회 ]  작성일19-08-09 22:40

웹학교