Don't Step on the White Tile

JavaScriptBeginner
지금 연습하기

소개

이 프로젝트는 "Don't Step on the White Tile"이라는 간단하면서도 흥미로운 웹 기반 게임을 만드는 과정을 안내합니다. 이 단계를 따라가면서 HTML, CSS, JavaScript 를 결합하여 플레이어가 흰색 타일을 밟지 않고 점수를 얻는 인터랙티브 게임을 구축하는 방법을 배우게 됩니다. 이 프로젝트는 웹 개발 기술을 연습하려는 초보자에게 이상적입니다.

👀 미리보기

🎯 과제

이 프로젝트에서 다음을 배우게 됩니다:

  • 게임 인터페이스를 레이아웃하기 위한 기본적인 HTML 구조 설정 방법.
  • 게임을 스타일링하여 시각적으로 매력적이고 사용자 친화적으로 만들기 위해 CSS 를 활용하는 방법.
  • 움직이는 타일, 점수 시스템, 게임 로직과 같은 동적 기능을 추가하기 위해 JavaScript 를 구현하는 방법.
  • 클릭과 같은 이벤트를 통해 사용자 상호 작용을 처리하여 게임의 상호 작용성을 향상시키는 방법.
  • 점수 및 게임 종료 조건과 같은 게임 상태를 동적으로 업데이트하기 위해 DOM 을 조작하는 방법.
  • 게임 루프, 충돌 감지, 속도 조절과 같은 기본적인 게임 개발 개념을 적용하는 방법.

🏆 성과

이 프로젝트를 완료하면 다음을 수행할 수 있습니다:

  • HTML, CSS 및 JavaScript 를 결합하여 인터랙티브 웹 애플리케이션을 만드는 방법을 확실하게 이해할 수 있습니다.
  • 애니메이션, 사용자 입력 처리 및 실시간 업데이트와 같은 게임 개발 개념에 대한 실질적인 경험을 적용할 수 있습니다.
  • DOM 을 조작하고 이벤트를 처리하여 반응형 웹 애플리케이션을 만들 수 있습니다.
  • 게임 로직 구현 및 게임 종료 조건과 같은 엣지 케이스 (edge cases) 처리를 통해 문제 해결 능력을 향상시킬 수 있습니다.
  • 웹 디자인 및 게임 미학에서 창의성을 보여주고, 추가적인 사용자 정의 및 개선 사항을 탐색할 수 있습니다.
  • 웹 기술 분야에서 더 많은 학습과 탐구를 위한 발판을 마련하여, 더 복잡한 웹 개발 및 게임 디자인 프로젝트를 위한 기초 단계를 밟을 수 있습니다.

HTML 구조 설정

index.html에서 게임의 기본적인 HTML 구조를 생성하는 것으로 시작합니다. 여기에는 게임 제목, 점수 표시, 주요 게임 영역 (#main) 및 시작 버튼이 포함됩니다. 주요 게임 영역에는 움직이는 타일 행이 포함됩니다.

<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Don't Step on the White Tile</title>
    <link rel="stylesheet" href="index.css" />
  </head>
  <body>
    <h2>Score</h2>
    <h2 id="score">0</h2>
    <div id="main">
      <div id="con"></div>
    </div>
    <div class="btn">
      <button class="start" onclick="start()">Start Game</button>
    </div>
    <script src="index.js"></script>
  </body>
</html>

이 단계에서는 게임의 기본적인 HTML 구조를 설정했습니다. 이 구조에는 게임 제목, 점수 표시, 움직이는 타일을 위한 #main으로 식별되는 주요 게임 영역, 그리고 게임을 시작하기 위한 시작 버튼이 포함됩니다. #main 영역은 나중에 플레이어가 게임 중에 상호 작용할 타일 행으로 채워집니다. 이 설정은 CSS 와 JavaScript 가 스타일과 기능을 추가할 게임의 골격을 구성하므로 매우 중요합니다.

✨ 솔루션 확인 및 연습

CSS 스타일 제작

index.css에서 게임을 시각적으로 구성하기 위한 CSS 스타일을 정의합니다. 이 단계에는 주요 게임 컨테이너, 개별 타일 (셀) 및 시작 버튼의 스타일을 지정하여 게임을 시각적으로 매력적으로 만드는 작업이 포함됩니다.

#main {
  width: 408px;
  height: 408px;
  background: white;
  border: 2px solid gray;
  margin: 0 auto;
  overflow: hidden;
}

h2 {
  text-align: center;
}

#con {
  width: 100%;
  height: 400px;
  position: relative;
  top: -408px;
  border-collapse: collapse;
}

.row {
  height: 100px;
  width: 100%;
}

.cell {
  height: 100px;
  width: 100px;
  float: left;
  border: rgb(54, 74, 129) 1px solid;
}

.black {
  background: black;
}

.btn {
  width: 100%;
  text-align: center;
}

.start {
  margin: 20px auto;
  width: 150px;
  height: 50px;
  border-radius: 10px;
  background: yellowgreen;
  line-height: 50px;
  color: #fff;
}

게임의 시각적 측면을 결정하는 CSS 스타일을 정의했습니다. 스타일에는 주요 게임 영역의 레이아웃, 타일 (또는 셀) 의 모양, 시작 버튼의 스타일 지정이 포함됩니다. 이러한 스타일을 설정함으로써 게임을 시각적으로 매력적으로 만들고, 게임 보드 및 시작 버튼과 같이 플레이어가 상호 작용할 사용자 인터페이스 요소를 정의했습니다. 이러한 스타일은 게임을 플레이어에게 매력적이고 접근 가능하게 만드는 데 필수적입니다.

✨ 솔루션 확인 및 연습

게임 초기화

이 단계에서는 index.js에서 게임을 활성화하는 데 필요한 JavaScript 를 작성하기 시작합니다. 게임을 초기화하고 게임 영역에 대한 초기 행 집합을 동적으로 생성하기 위해 startinit 함수를 생성하는 것으로 시작합니다.

// Helper function to get element by ID
function $(id) {
  return document.getElementById(id);
}

// Function to create a div with a given class name
function createDiv(className) {
  var div = document.createElement("div");
  div.className = className;
  return div;
}

var gameStarted = false;

// Function to start the game
function start() {
  if (!gameStarted) {
    init();
  } else {
    alert("The game has already started, no need to click again!");
  }
}

// Initialize the game
function init() {
  gameStarted = true;
  for (var i = 0; i < 4; i++) {
    createRow();
  }
}

이 단계에서 JavaScript 를 사용하여 게임에 생명을 불어넣기 시작했습니다. 작성한 코드는 게임을 초기화하고 초기 타일 행을 생성하기 위한 메커니즘을 설정합니다. 여기에는 DOM 조작을 위한 도우미 함수 정의, 여러 게임 시작을 방지하기 위한 플래그 설정, 그리고 게임 영역에 행을 동적으로 추가하기 위한 기반 마련이 포함됩니다. 이 단계는 타일이 움직이고 플레이어가 게임에 참여할 수 있는 게임의 인터랙티브 부분을 준비하면서 게임의 동적 요소를 설정하므로 중요합니다.

✨ 솔루션 확인 및 연습

행 이동 처리 및 게임 오버 확인

JavaScript 기능을 확장하여 행을 아래로 이동하고 게임 오버 여부를 확인하는 기능을 포함합니다. 여기에는 행의 위치를 업데이트하고 '밟히지' 않고 허용된 경계를 통과한 행이 있는지 확인하는 게임 루프를 생성하는 작업이 포함됩니다.

// Continue in index.js

var speed = 6; // Initial speed of the moving rows
var clock = null;

// Move the rows down
function move() {
  var con = $("con");
  var top = parseInt(window.getComputedStyle(con, null)["top"]);
  if (speed + top > 0) {
    top = 0;
  } else {
    top += speed;
  }
  con.style.top = top + "px";
  checkGameOver();
  if (top == 0) {
    createRow();
    con.style.top = "-102px";
    deleteRow();
  }
}

// Check if the game is over
function checkGameOver() {
  var con = $("con");
  var rows = con.childNodes;
  var conTop = parseInt(window.getComputedStyle(con, null)["top"]);
  var conHeight = con.offsetHeight;
  for (var i = 0; i < rows.length; i++) {
    var row = rows[i];
    var rowTop = conTop + i * row.offsetHeight;
    if (rowTop >= conHeight && row.passed !== 1) {
      fail();
      break;
    }
  }
}

여기서는 행을 아래로 이동하고 게임 오버 조건을 확인하는 로직을 추가하여 게임의 기능을 확장했습니다. move 함수는 행의 위치를 업데이트하여 플레이어가 밟지 않도록 해야 하는 타일의 움직임을 시뮬레이션합니다. checkGameOver 함수는 '밟히지' 않고 게임 영역의 하단을 통과한 행이 있는지 모니터링하며, 이는 게임을 종료합니다. 이 단계는 주요 게임 플레이 메커니즘과 도전을 도입하여 게임을 인터랙티브하고 매력적으로 만듭니다.

✨ 솔루션 확인 및 연습

점수 계산 및 속도 증가 구현

이 단계에서는 게임의 점수 매기기 메커니즘을 구현하고 플레이어의 점수가 증가함에 따라 행의 속도를 높이는 데 집중합니다. 이는 게임에 도전 수준을 추가하여 게임의 몰입도를 유지합니다.

// Continue in index.js

// Update the score
function score() {
  var newScore = parseInt($("score").innerHTML) + 1;
  $("score").innerHTML = newScore;
  if (newScore % 10 == 0) {
    speedUp();
  }
}

// Increase the speed of the moving rows
function speedUp() {
  speed += 2;
  if (speed == 20) {
    alert("Incredible speed!");
  }
}

이 단계에서는 게임의 점수 시스템을 구현하고 플레이어의 점수가 증가함에 따라 움직이는 행의 속도를 높이는 기능을 추가했습니다. 이는 플레이어에게 자신의 성과에 대한 피드백을 제공할 뿐만 아니라 게임의 난이도를 점진적으로 증가시킵니다. 점수 매기기 메커니즘은 플레이어가 흰색 타일을 성공적으로 피했을 때 보상을 제공하며, 증가하는 속도는 플레이어의 반응 시간을 시험하여 게임을 더욱 몰입적이고 경쟁적으로 만듭니다.

✨ 솔루션 확인 및 연습

사용자 상호 작용 처리

타일에 대한 사용자 클릭을 처리하는 로직을 구현합니다. 플레이어는 검은색 타일을 클릭하면 점수를 얻고 흰색 타일을 클릭하면 잃게 됩니다.

// Continue in index.js

// Judge the player's action
function judge(ev) {
  ev = ev || event;
  if (ev.target.className.indexOf("black") !== -1) {
    ev.target.className = "cell";
    ev.target.parentNode.passed = 1;
    score();
  } else if (ev.target.className.indexOf("cell") !== -1) {
    fail();
  }
}

이 단계에서는 게임 내에서 사용자 클릭을 처리하는 judge 함수를 구현했습니다. 플레이어가 타일을 클릭하면 함수는 해당 타일이 검은색인지 여부를 결정합니다. 타일이 검은색 (올바른 움직임) 이면 일반 셀로 바뀌고 점수가 업데이트됩니다. 타일이 검은색이 아니면 (잘못된 움직임) 게임 오버 시퀀스가 트리거됩니다. 이 함수는 플레이어가 타일을 클릭하여 게임과 상호 작용하고 자신의 행동에 대한 즉각적인 피드백을 받을 수 있도록 하여 게임의 상호 작용성에 매우 중요합니다.

✨ 솔루션 확인 및 연습

행 생성 및 삭제

게임이 원활하게 실행되도록 새로운 타일 행을 동적으로 생성하고 더 이상 보이지 않는 가장 오래된 행을 삭제하는 함수를 개발합니다.

// Continue in index.js

// Randomly assign the black cell in a row
function createCell() {
  var temp = ["cell", "cell", "cell", "cell"];
  var i = Math.floor(Math.random() * 4);
  temp[i] = "cell black";
  return temp;
}

// Create a new row of tiles
function createRow() {
  var con = $("con");
  var row = createDiv("row");
  var arr = createCell();
  for (var i = 0; i < 4; i++) {
    row.appendChild(createDiv(arr[i]));
  }
  if (con.firstChild == null) {
    con.appendChild(row);
  } else {
    con.insertBefore(row, con.firstChild);
  }
}

// Delete the last row if there are more than 5 rows
function deleteRow() {
  var con = $("con");
  if (con.childNodes.length == 6) {
    con.removeChild(con.lastChild);
  }
}

createRow 함수를 추가하여 무작위 위치에 검은색 타일 하나를 포함하는 타일 행을 동적으로 생성하여 게임의 예측 불가능성과 도전성을 향상시켰습니다. deleteRow 함수는 더 이상 보이지 않는 가장 오래된 행을 제거하여 게임의 성능을 최적화하고 게임 영역이 사용하지 않는 요소로 넘치지 않도록 합니다. 이러한 함수는 플레이어가 상호 작용할 수 있는 타일의 지속적인 흐름을 유지하기 위해 함께 작동합니다.

✨ 솔루션 확인 및 연습

게임 오버 로직 구현

흰색 타일을 클릭하거나 검은색 타일을 놓치는 등 게임이 종료되는 조건을 정의합니다. 플레이어의 최종 점수를 표시하고 게임을 다시 시작할 수 있는 옵션을 제공합니다.

// Continue in index.js

// End the game
function fail() {
  clearInterval(clock);
  gameStarted = false;
  confirm("Your final score is " + parseInt($("score").innerHTML));
  window.location.reload();
}

fail 함수를 정의함으로써 게임이 종료되는 조건을 설정했습니다. 이 함수는 플레이어가 잘못된 움직임을 하거나 검은색 타일을 놓쳤을 때 호출됩니다. 게임 루프를 중지하고, 플레이어의 최종 점수를 표시하며, 새로운 시작을 위해 페이지를 다시 로드합니다. 이 단계는 실수를 피하는 도전과 게임 종료의 최종성을 포함하여 완전한 게임 경험을 제공하는 데 필수적입니다.

✨ 솔루션 확인 및 연습

게임 루프 시작

타일이 화면 아래로 계속 이동하도록 하는 메인 게임 루프를 설정합니다. 난이도를 높이기 위해 플레이어의 점수에 따라 이동 속도를 조정합니다.

// Continue in index.js

// Start the game loop
function start() {
  if (!gameStarted) {
    init();
    clock = setInterval("move()", 30);
  }
}

move 함수를 사용하여 메인 게임 루프를 설정하여 게임 진행을 시뮬레이션하며 행을 화면 아래로 지속적으로 이동시켰습니다. 플레이어의 점수가 증가함에 따라 이동 속도가 증가하여 게임의 난이도가 높아집니다. 이 루프는 게임 플레이를 주도하고 증가하는 속도에 맞춰 플레이어가 따라가도록 도전하는 게임의 심장 박동과 같습니다.

✨ 솔루션 확인 및 연습

이벤트 리스너 추가

타일을 클릭하는 것과 같은 플레이어의 액션을 감지하고 응답하기 위해 게임 영역에 이벤트 리스너를 연결합니다.

// Continue in index.js

// Add event listener for the main game container
$("main").onclick = function (ev) {
  judge(ev);
};

이 단계에서는 메인 게임 영역에 이벤트 리스너를 연결하여 플레이어 클릭에 응답할 수 있도록 했습니다. 이 기능은 사용자 상호 작용을 캡처하고, 게임이 플레이어의 움직임을 처리하고 그에 따라 게임 상태를 업데이트할 수 있도록 하는 데 필수적입니다. 이것이 게임을 상호 작용적이고 플레이어의 액션에 반응하게 만드는 요소입니다.

다음 효과를 보려면 WebIDE 의 오른쪽 하단 모서리에 있는 Go Live 버튼을 클릭하고 "Web 8080" 탭으로 전환하십시오.

✨ 솔루션 확인 및 연습

요약

이 프로젝트를 완료함으로써 "Don't Step on the White Tile"이라는 제목의 기능적인 웹 기반 게임을 만들었습니다. 이 프로젝트는 HTML, CSS 및 JavaScript 가 상호 작용하는 웹 콘텐츠를 만들기 위해 어떻게 함께 작동하는지에 대한 이해를 높일 뿐만 아니라, 향후 더 복잡한 웹 기반 게임을 만드는 기반을 제공합니다. 게임을 고유하게 만들기 위해 다양한 스타일, 기능 및 기능을 실험해 보세요. 즐거운 코딩 되세요!