728x90
안녕하세요.
오늘은 이전에 만들었던 벽돌깨기 게임 예제를 더 발전시키기 위해서 목숨 기능을 추가해보겠습니다.
목숨은 플레이어가 실수로 공을 놓쳤을 때 줄어들며, 목숨이 0이 되면 게임이 종료됩니다.
기존의 코드는 아래 링크를 통해 확인해주세요.
2024.08.12 - [JavaScript] - [JavaScript] 벽돌깨기 게임 만들기 (3) 게임 시작, 게임 오버, 게임 클리어, 다시 시작 구현하기
1. 목숨 변수 선언
먼저, 목숨을 저장할 변수를 추가합니다.
let lives;
이 변수를 init 함수에 추가하여, 게임을 시작할 때마다 목숨을 초기화합니다.
function init() {
// 공의 위치와 이동 속도 설정
x = canvas.width / 2;
y = canvas.height - 30;
dx = 2;
dy = -2;
ballRadius = 10;
// 패들 설정
paddleHeight = 10;
paddleWidth = 75;
paddleX = (canvas.width - paddleWidth) / 2;
// 벽돌 설정
brickRowCount = 3;
brickColumnCount = 5;
brickWidth = 75;
brickHeight = 20;
brickPadding = 10;
brickOffsetTop = 30;
brickOffsetLeft = 30;
bricks = [];
for(let c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for(let r = 0; r < brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1 };
}
}
lives = 3; // 목숨을 초기화합니다.
gameStarted = false;
}
2. 남은 목숨을 화면에 표시하기
게임 도중 플레이어에게 남은 목숨의 수를 화면에 표시하여 얼마나 많은 기회를 남겨두고 있는지 알 수 있도록 하는 drawLives 함수를 만듭니다.
function drawLives() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Lives: " + lives, canvas.width - 65, 20);
}
이제 이 함수를 게임 루프(draw 함수)에서 호출하여, 매 프레임마다 남은 목숨을 표시하도록 합니다.
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPaddle();
drawLives(); // 남은 목숨을 화면에 표시
collisionDetection();
// (생략)
}
3. 목숨이 0이 되었을 때 게임 종료
draw 함수에서 공이 바닥에 닿을 때 목숨을 하나 줄이고, 목숨이 0이 되면 gameOver 함수를 호출하여 게임을 종료하도록 코드를 수정합니다.
// 기존 코드
if(y + dy > canvas.height - ballRadius) {
gameOver();
return;
}
// 수정한 코드
if(y + dy > canvas.height - ballRadius) {
lives--; // 목숨을 하나 줄입니다.
if(!lives) {
gameOver(); // 목숨이 0이면 게임 오버 처리
return;
} else {
// 목숨이 남아 있으면 게임을 계속할 수 있도록 위치를 초기화합니다.
x = canvas.width / 2;
y = canvas.height - 30;
dx = 2;
dy = -2;
paddleX = (canvas.width - paddleWidth) / 2;
}
}
4. 전체 코드
// 캔버스와 2D 컨텍스트 가져오기
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
let x, y, dx, dy, ballRadius, paddleHeight, paddleWidth, paddleX;
let brickRowCount, brickColumnCount, brickWidth, brickHeight, brickPadding, brickOffsetTop, brickOffsetLeft;
let bricks, gameInterval, gameStarted = false;
const startButton = document.getElementById("startButton");
const restartButton = document.getElementById("restartButton");
// 추가된 변수들
let lives;
function init() {
// 공의 위치와 이동 속도 설정
x = canvas.width / 2;
y = canvas.height - 30;
dx = 2; // 공의 x축 이동 속도
dy = -2; // 공의 y축 이동 속도
ballRadius = 10;
// 패들 설정
paddleHeight = 10;
paddleWidth = 75;
paddleX = (canvas.width - paddleWidth) / 2;
// 벽돌 설정
brickRowCount = 3;
brickColumnCount = 5;
brickWidth = 75;
brickHeight = 20;
brickPadding = 10;
brickOffsetTop = 30;
brickOffsetLeft = 30;
bricks = [];
for(let c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for(let r = 0; r < brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1 };
}
}
lives = 3; // 플레이어에게 3개의 목숨을 부여
gameStarted = false; // 게임이 아직 시작되지 않음
}
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawBricks() {
for(let c = 0; c < brickColumnCount; c++) {
for(let r = 0; r < brickRowCount; r++) {
if(bricks[c][r].status == 1) {
let brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft;
let brickY = (r * (brickHeight + brickPadding)) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
}
}
}
function collisionDetection() {
for(let c = 0; c < brickColumnCount; c++) {
for(let r = 0; r < brickRowCount; r++) {
let b = bricks[c][r];
if(b.status == 1) {
if(x > b.x && x < b.x + brickWidth && y > b.y && y < b.y + brickHeight) {
dy = -dy;
b.status = 0;
}
}
}
}
}
function mouseMoveHandler(e) {
let relativeX = e.clientX - canvas.offsetLeft;
if(relativeX > 0 && relativeX < canvas.width) {
paddleX = relativeX - paddleWidth / 2;
}
}
document.addEventListener("mousemove", mouseMoveHandler, false);
function checkBricks() {
for(let c = 0; c < brickColumnCount; c++) {
for(let r = 0; r < brickRowCount; r++) {
if(bricks[c][r].status == 1) {
return false;
}
}
}
return true;
}
function gameClear() {
clearInterval(gameInterval);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.font = "24px Arial";
ctx.fillStyle = "#0095DD";
ctx.textAlign = "center";
ctx.fillText("Game Clear!", canvas.width / 2, canvas.height / 2);
restartButton.style.display = "block";
}
function gameOver() {
clearInterval(gameInterval);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.font = "24px Arial";
ctx.fillStyle = "#FF0000";
ctx.textAlign = "center";
ctx.fillText("Game Over", canvas.width / 2, canvas.height / 2 - 20);
restartButton.style.display = "block";
}
function drawLives() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Lives: " + lives, canvas.width - 65, 20);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPaddle();
drawLives(); // 남은 목숨을 화면에 표시
collisionDetection();
if(checkBricks()) {
gameClear();
return;
}
if(x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if(y + dy > canvas.height - ballRadius) {
lives--; // 목숨을 하나 줄입니다.
if(!lives) {
gameOver(); // 목숨이 0이면 게임 오버 처리
return;
} else {
// 목숨이 남아 있으면 게임을 계속할 수 있도록 위치를 초기화합니다.
x = canvas.width / 2;
y = canvas.height - 30;
dx = 2;
dy = -2;
paddleX = (canvas.width - paddleWidth) / 2;
}
}
if(y + dy < ballRadius || (y + dy > canvas.height - paddleHeight - ballRadius && x > paddleX && x < paddleX + paddleWidth)) {
dy = -dy;
}
x += dx;
y += dy;
}
function startGame() {
startButton.style.display = "none";
restartButton.style.display = "none";
let countdown = 3;
gameInterval = setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.font = "24px Arial";
ctx.fillStyle = "#0095DD";
ctx.textAlign = "center";
ctx.fillText(countdown, canvas.width / 2, canvas.height / 2);
countdown--;
if(countdown < 0) {
clearInterval(gameInterval);
gameInterval = setInterval(draw, 10); // 게임 시작
}
}, 1000);
}
startButton.addEventListener("click", () => {
init();
startGame();
});
restartButton.addEventListener("click", () => {
init();
startGame();
});
'JavaScript' 카테고리의 다른 글
[JavaScript] 간단한 테트리스 게임 만들기 (2) - 레벨업 하기 (4) | 2024.09.04 |
---|---|
[JavaScript] 벽돌깨기 게임 발전시키기 - 가속도와 마찰력 추가하기 (2) | 2024.09.03 |
[JavaScript] 간단한 테트리스 게임 만들기 (0) | 2024.08.24 |
[JavaScript] 벽돌깨기 게임 만들기 (3) 게임 시작, 게임 오버, 게임 클리어, 다시 시작 구현하기 (0) | 2024.08.22 |
[JavaScript] 벽돌깨기 게임 만들기 (2) 공 튕기기 (0) | 2024.08.18 |