728x90
안녕하세요 테트리스 마지막 게시글입니다
테트리스 게임 이전편은 아래 링크에서 확인하실 수 있습니다
오늘은 일시정지 기능을 추가해보도록 하겠습니다
기존 게임은 중간에 멈추지 않고 계속 플레이할 수 있었는데요
키보드의 p 글자를 눌러서 게임을 멈추고 다시 누르면 이어서 플레이할 수 있도록 구현해보았습니다
먼저 html 코드 변경된 부분입니다.
status 라는 id 를 가진 div 를 추가해 "게임 중..." 임을 표시하도록 했습니다
/* 현재 진행 상태div에 대한 style 속성값 */
#status {
position: absolute;
top: 10px; /* 상단에 위치 */
left: 50%;
transform: translateX(-50%); /* 수평 중앙 정렬 */
font-size: 15px;
color: white;
font-family: Arial, sans-serif;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
display: none; /* 초기에는 숨겨짐 */
}
</style>
</head>
<body>
<canvas id="tetris" width="300" height="600"></canvas>
<div id="info">
<div id="level">Level: 0</div>
<div id="speed">Speed: 1000ms</div>
</div>
<!-- 현재 게임 진행 상태 div -->
<div id="status">게임 중...</div> <!-- 상태 텍스트 추가 -->
<script src="tetris2.js"></script>
</body>
</html>
자바 스크립트 변경된 부분입니다
방향키에 따라 블록 위치를 조정하는 함수에 p 키에 대한 조건을 추가해줍니다
let paused = false;
document.addEventListener('keydown', event => {
if (event.keyCode === 37) { // 왼쪽 화살표
playerMove(-1);
} else if (event.keyCode === 39) { // 오른쪽 화살표
playerMove(1);
} else if (event.keyCode === 40) { // 아래 화살표
playerDrop();
} else if (event.keyCode === 81) { // Q 키 (회전 왼쪽)
player.matrix = rotate(player.matrix, -1);
} else if (event.keyCode === 87) { // W 키 (회전 오른쪽)
player.matrix = rotate(player.matrix, 1);
} else if (event.keyCode === 80) { // P 키 (일시 정지/재시작)
togglePause();
}
});
function togglePause() {
paused = !paused;
updateLevelAndSpeed();
}
일시 정지 상태에 따라 UI 를 업데이트 해주는 코드 입니다
// 일시 정지 상태에 따른 UI 업데이트
const status = document.getElementById('status');
if (paused) {
status.textContent = '일시 정지';
status.style.display = 'block';
} else {
status.textContent = '게임 중...';
status.style.display = 'block';
setTimeout(() => {
status.style.display = 'none';
}, 1000); // "게임 중..." 표시를 1초간 유지
}
}
전체 코드 입니다
tetris.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tetris Game2</title>
<style>
canvas {
background-color: #000;
display: block;
margin: 0 auto;
border: 2px solid;
}
#info {
text-align: center;
color: rgb(0, 0, 0);
font-family: Arial, sans-serif;
margin-top: 10px;
}
#level, #speed {
font-size: 18px;
margin: 5px 0;
}
/* 현재 진행 상태 */
#status {
position: absolute;
top: 10px; /* 상단에 위치 */
left: 50%;
transform: translateX(-50%); /* 수평 중앙 정렬 */
font-size: 15px;
color: white;
font-family: Arial, sans-serif;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
display: none; /* 초기에는 숨겨짐 */
}
</style>
</head>
<body>
<canvas id="tetris" width="300" height="600"></canvas>
<div id="info">
<div id="level">Level: 0</div>
<div id="speed">Speed: 1000ms</div>
</div>
<!-- 현재 게임 진행 상태 -->
<div id="status">게임 중...</div> <!-- 상태 텍스트 추가 -->
<script src="tetris2.js"></script>
</body>
</html>
tetris2.js
const canvas = document.getElementById('tetris');
const context = canvas.getContext('2d');
const grid = 20; // 테트리스 그리드 크기
const cols = canvas.width / grid;
const rows = canvas.height / grid;
let board = Array.from({ length: rows }, () => Array(cols).fill(0));
const colors = [
null,
'cyan',
'blue',
'orange',
'yellow',
'green',
'purple',
'red'
];
const tetrominoes = [
[
[1, 1, 1, 1], // I
],
[
[0, 2, 0],
[2, 2, 2], // T
],
[
[3, 3],
[3, 3], // O
],
[
[0, 4, 4],
[4, 4, 0], // S
],
[
[5, 5, 0],
[0, 5, 5], // Z
],
[
[6, 0, 0],
[6, 6, 6], // J
],
[
[0, 0, 7],
[7, 7, 7], // L
]
];
function createPiece(type) {
return tetrominoes[type];
}
function drawMatrix(matrix, offset) {
matrix.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
context.fillStyle = colors[value];
context.fillRect((x + offset.x) * grid, (y + offset.y) * grid, grid, grid);
}
});
});
}
function collide(board, player) {
const [m, o] = [player.matrix, player.pos];
for (let y = 0; y < m.length; y++) {
for (let x = 0; x < m[y].length; x++) {
if (m[y][x] !== 0 &&
(board[y + o.y] &&
board[y + o.y][x + o.x]) !== 0) {
return true;
}
}
}
return false;
}
function merge(board, player) {
player.matrix.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
board[y + player.pos.y][x + player.pos.x] = value;
}
});
});
clearLines();
}
function clearLines() {
outer: for (let y = board.length - 1; y >= 0; y--) {
for (let x = 0; x < board[y].length; x++) {
if (board[y][x] === 0) {
continue outer;
}
}
const row = board.splice(y, 1)[0].fill(0);
board.unshift(row);
linesCleared += 1;
}
}
let dropCounter = 0;
let dropInterval = 1000;
let lastTime = 0;
let paused = false;
function update(time = 0) {
if (!paused) {
const deltaTime = time - lastTime;
lastTime = time;
dropCounter += deltaTime;
if (dropCounter > dropInterval) {
playerDrop();
}
draw();
}
requestAnimationFrame(update);
}
function playerDrop() {
player.pos.y++;
if (collide(board, player)) {
player.pos.y--;
merge(board, player);
playerReset();
}
dropCounter = 0;
}
function playerMove(dir) {
player.pos.x += dir;
if (collide(board, player)) {
player.pos.x -= dir;
}
}
function playerReset() {
player.matrix = createPiece(Math.floor(Math.random() * tetrominoes.length));
player.pos.y = 0;
player.pos.x = Math.floor((cols - player.matrix[0].length) / 2);
if (collide(board, player)) {
board.forEach(row => row.fill(0));
}
}
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
drawMatrix(board, { x: 0, y: 0 });
drawMatrix(player.matrix, player.pos);
// 일시 정지 상태에 따른 UI 업데이트
const status = document.getElementById('status');
if (paused) {
status.textContent = '일시 정지';
status.style.display = 'block';
} else {
status.textContent = '게임 중...';
status.style.display = 'block';
setTimeout(() => {
status.style.display = 'none';
}, 1000); // "게임 중..." 표시를 1초간 유지
}
}
function rotate(matrix, dir) {
for (let y = 0; y < matrix.length; y++) {
for (let x = 0; x < y; x++) {
[matrix[x][y], matrix[y][x]] = [matrix[y][x], matrix[x][y]];
}
}
if (dir > 0) {
matrix.forEach(row => row.reverse());
} else {
matrix.reverse();
}
return matrix;
}
const player = {
pos: { x: 0, y: 0 },
matrix: createPiece(Math.floor(Math.random() * tetrominoes.length))
};
document.addEventListener('keydown', event => {
if (event.keyCode === 37) { // 왼쪽 화살표
playerMove(-1);
} else if (event.keyCode === 39) { // 오른쪽 화살표
playerMove(1);
} else if (event.keyCode === 40) { // 아래 화살표
playerDrop();
} else if (event.keyCode === 81) { // Q 키 (회전 왼쪽)
player.matrix = rotate(player.matrix, -1);
} else if (event.keyCode === 87) { // W 키 (회전 오른쪽)
player.matrix = rotate(player.matrix, 1);
} else if (event.keyCode === 80) { // P 키 (일시 정지/재시작)
togglePause();
}
});
function togglePause() {
paused = !paused;
updateLevelAndSpeed();
}
update();
// 1분마다 레벨을 증가시키고, 속도를 올리는 타이머
setInterval(() => {
if (!paused) { // 게임이 일시 정지 상태가 아닐 때만
increaseLevel();
}
}, 60000);
let level = 0;
let linesCleared = 0;
function increaseLevel() {
level += 1;
dropInterval *= 0.8; // 속도 증가 비율을 20%로 조정
updateLevelAndSpeed(); // 레벨과 속도 UI 업데이트
}
function updateLevelAndSpeed() {
document.getElementById('level').textContent = `Level: ${level}`;
document.getElementById('speed').textContent = `Speed: ${Math.round(dropInterval)}ms`;
}
// 게임 시작 시 UI 초기화
updateLevelAndSpeed();
시연 영상입니다
'JavaScript' 카테고리의 다른 글
[JavaScript] 비행기 슈팅 게임 만들기 - (2) 적 생성하기 (2) | 2024.09.21 |
---|---|
[JavaScript] 비행기 슈팅 게임 만들기 - (1) 비행기 그리기 (3) | 2024.09.15 |
[JavaScript] 틱택토(Tic-Tac-Toe) 게임 만들기 (2) | 2024.09.09 |
[JavaScript] 도형을 드래그하여 테두리에 정확히 맞추기 (2) | 2024.09.05 |
[JavaScript] 간단한 테트리스 게임 만들기 (2) - 레벨업 하기 (4) | 2024.09.04 |