چگونه یک بازی تیک تاک با جاوا اسکریپت وانیلی بسازیم

چگونه یک بازی تیک تاک با جاوا اسکریپت وانیلی بسازیم

در اینجا بازی tic-tac-toe است که ما قصد داریم کدنویسی کنیم. برای قرار دادن قطعات روی هر مربع کلیک کنید و سعی کنید سه قطعه را پشت سر هم به دست آورید:

ساختار HTML

ساختار HTML از عناصر زیر تشکیل خواهد شد:

  • تابلویی که دارای 9 خواهد بود div عناصر نشان دهنده شبکه 3×3
  • هنگامی که بازی به پایان می رسد، یک مدال بوت استرپ نشان داده می شود. مدال برنده را نشان می دهد.
  • دکمه ای که با کلیک روی آن بازی مجددا راه اندازی می شود

یک ظرف حاوی برد و دکمه راه اندازی مجدد با بوت استرپ ایجاد کنید.

1

class="container">

2
  
3
  

class="board" id="board">

4
    

class="cell" data-cell>

5
    

class="cell" data-cell>

6
    

class="cell" data-cell>

7
    

class="cell" data-cell>

8
    

class="cell" data-cell>

9
    

class="cell" data-cell>

10
    

class="cell" data-cell>

11
    

class="cell" data-cell>

12
    

class="cell" data-cell>

13
  
14
  
17
  

class="text-center mt-3">

18
    
19
  
20

در زیر ظرف، مودال نتایج را اضافه کنید.

1
2
  class="modal fade"
3
  id="resultModal"
4
  tabindex="-1"
5
  aria-labelledby="resultModalLabel"
6
  aria-hidden="true"
7
>
8
  

class="modal-dialog">

9
    

class="modal-content">

10
      

class="modal-header">

11
        
class="modal-title" id="resultModalLabel">Game Over
12
        
13
          type="button"
14
          class="close"
15
          data-dismiss="modal"
16
          aria-label="Close"
17
        >
18
           aria-hidden="true">×
19
        
20
      
21
      

class="modal-body" id="results">

22
      

class="modal-footer">

23
        
24
          type="button"
25
          class="btn btn-primary"
26
          data-dismiss="modal"
27
          id="playBtn"
28
        >
29
          Play Again
30
        
31
      
32
    
33
  
34

استایل دهی با CSS

برای اطمینان از

elements in the board are arranged in a 3×3 grid, apply the following styles:

1
.board {
2
    display: grid;
3
    grid-template-columns: repeat(3, 1fr);
4
    gap: 10px;
5
    max-width: 300px;
6
    margin: 50px auto;
7
  }

For each cell in the grid, add the following styles.

1
.cell {
2
    width: 100px;
3
    height: 100px;
4
    display: flex;
5
    align-items: center;
6
    justify-content: center;
7
    font-size: 2rem;
8
    cursor: pointer;
9
    border: 1px solid #000;
10
  }

Create the styles which will add the X and O in the board cells. When it’s player O’s turn, we will add the circle class; when it’s player X’s turn, we will add the x class.

1
.x::before {
2
    content: "X";
3
    color: blue;
4
    position: absolute;
5
  }
6
  .circle::before {
7
    content: "O";
8
    color: red;
9
    position: absolute;
10
  }

JavaScript functionality

Let’s define some variables:

1
const X_CLASS = "x";
2
const CIRCLE_CLASS = "circle";
3
const WINNING_COMBINATIONS = (
4
(0, 1, 2),
5
(3, 4, 5),
6
(6, 7, 8),
7
(0, 3, 6),
8
(1, 4, 7),
9
(2, 5, 8),
10
(0, 4, 8),
11
(2, 4, 6),
12
);

X_CLASS کلاس CSS را تعریف می کند که در نوبت بازیکن X اضافه می شود CIRCLE_CLASS نشان دهنده کلاس CSS است که وقتی نوبت به بازیکن CIRCLES برسد به هر سلول اضافه می شود.

هر آرایه در ترکیب های برنده نمایانگر یک ردیف برنده به صورت افقی، عمودی یا مورب است.

عناصر را با استفاده از DOM (مدل شیء سند) انتخاب کنید

1
const cellElements = document.querySelectorAll("(data-cell)");
2
const board = document.getElementById("board");

با تعریف نوبت اولیه بازیکن شروع کنید.

سپس یک تابع به نام ایجاد کنید starGame() که شبیه این است:

1
 function startGame() {
2
    cellElements.forEach((cell) => {
3
      cell.classList.remove(X_CLASS);
4
      cell.classList.remove(CIRCLE_CLASS);
5
      cell.removeEventListener("click", handleClick);
6
      cell.addEventListener("click", handleClick, { once: true });
7
    });
8
  
9
  
10
 startGame();

این تابع با حذف هر X یا O از سلول‌ها، بازی را بازنشانی می‌کند و در نتیجه صفحه را پاک می‌کند.

1
cell.classList.remove(X_CLASS);
2
cell.classList.remove(CIRCLE_CLASS);

همچنین هرگونه رویداد کلیکی موجود را حذف می کند تا اطمینان حاصل شود که هنگام شروع بازی هیچ کنترل کننده رویداد در هیچ سلولی وجود ندارد. این عملکرد همچنین تضمین می کند که پس از شروع بازی، هر سلول فقط یک بار با استفاده از آن می توان کلیک کرد { once: true } گزینه ای که وظیفه جابجایی بازیکنان و اضافه کردن O و X را بر روی تخته خواهد داشت.

سپس یک تابع به نام ایجاد کنید handleClick()، که منطق اتفاقاتی که وقتی بازیکن روی یک سلول کلیک می کند را کنترل می کند.

1
function handleClick(e) {
2
    const cell = e.target;
3
    const currentClass = circleTurn ? CIRCLE_CLASS : X_CLASS;
4
    cell.classList.add(currentClass);
5
    circleTurn = !circleTurn;
6
}

در handleClick تابع، زیرا به هر عنصر سلول اختصاص داده شده است handleClick عملکرد از طریق شنوندگان رویداد، e.target به عنصر سلول خاصی اشاره دارد که روی آن کلیک شده است.

  • const currentClass=circleTurn?CIRCLE_CLASS:X_CLASS; این کلاس تعیین می کند که نوبت چه کسی است. اگر circleTurn درست است، currentClass به نوبت O اختصاص داده خواهد شد. در غیر این صورت، X_CLASS استفاده خواهد شد. این اطمینان حاصل می کند که کلاس ها در هر موردی تغییر می کنند.
  • cell.classList.add(currentClass); را اضافه خواهد کرد currentClass به سلول
  • circleTurn=!circleTurn; نوبت بین دو بازیکن تغییر می کند.

اکنون باید برنده را بررسی کنیم. ایجاد یک checkWin() تابعی که در currentClass و از ترکیب های برنده بررسی کنید، آیا مسابقه ای در هیئت مدیره وجود دارد.

1
 function checkWin(currentClass) {
2
    return WINNING_COMBINATIONS.some((combination) => {
3
      return combination.every((index) => {
4
        return cellElements(index).classList.contains(currentClass);
5
      });
6
    });
7
  }

در اینجا، ما از .some() روش، که بررسی می کند که آیا حداقل یک آرایه در WINNING_COMBINATIONS آرایه برای شرایط داخل true برمی گرداند every().را .every() متد بررسی می کند که آیا هر شاخص در آرایه داخلی حاوی است یا خیر currentClass، به این معنی که همه عناصر در آن آرایه توسط یک بازیکن مشخص شده اند. اگر این شرط برای هر ترکیبی صادق باشد، بازیکن نشان داده شده توسط currentClass برنده بازی است

برای بررسی اینکه آیا بازی مساوی است یا خیر، isDraw() تابع بررسی می کند که آیا هر سلول روی برد دارای یکی از این دو است X_CLASS یا CIRCLE_CLASS کلاس اگر یکی از بازیکنان تمام سلول ها را علامت گذاری کند، بازی مساوی در نظر گرفته می شود.

1
function isDraw() {
2
    return (...cellElements).every((cell) => {
3
      return (
4
        cell.classList.contains(X_CLASS) ||
5
        cell.classList.contains(CIRCLE_CLASS)
6
      );
7
    });
8
  }

اکنون به روز رسانی کنید handleClick() تابع برای نشان دادن نتایج مناسب اگر checkWin() یا isDraw() توابع true را برمی گرداند.

1
function handleClick(e) {
2
    const cell = e.target;
3
    const currentClass = circleTurn ? CIRCLE_CLASS : X_CLASS;
4
    console.log(currentClass);
5

6
    cell.classList.add(currentClass);
7
    circleTurn = !circleTurn;
8

9
    if (checkWin(currentClass)) {
10
      showResult(`${currentClass.toUpperCase()} wins`);
11
    } else if (isDraw()) {
12
      showResult(`It's a Draw`);
13
    }
14
  }

حالا بیایید ایجاد کنیم theshowResult() تابع، که نتایج را نمایش می دهد.

1
const resultModal = new bootstrap.Modal(
2
    document.getElementById("resultModal"),
3
    {
4
      keyboard: false,
5
    }
6
);
7
 function showResult(message) {
8
    resultMessage.textContent = message;
9
    resultModal.show();
10

11
  }

در کد بالا، یک نمونه مودال بوت استرپ را مقداردهی اولیه می کنیم resultModal برای مدال با شناسه “resultModal”. سپس از showResult(message) عملکرد به روز رسانی محتوای متنی بدنه مودال (resultMessage.textContent) با پارامتر پیام و نمایش مدال با استفاده از resultModal.show().

هنگامی که بازی به پایان می رسد، مدال مانند شکل زیر نمایش داده می شود:

برای بستن مدال، یک شنونده رویداد به هر دو بسته و PlayAgain دکمه ها هنگامی که هر دکمه کلیک می شود، بازی باید با فراخوانی بازنشانی شود startGame() تابع مدال نیز پنهان خواهد شد.

1
const closeButton = document.querySelector(".modal .close");
2
document.getElementById("playBtn").addEventListener("click", startGame);
3
closeButton.addEventListener("click", () => {
4
    resultModal.hide();
5
    startGame();
6
  });

آخرین قسمت این بازی اضافه کردن شاخص های بصری است که نشان می دهد نوبت چه کسی است. کلاس های CSS را برای اینها اضافه کنید.

1
.board.hover-x (data-cell):hover:not(.x):not(.circle) {
2
    background-color: lightblue;
3
  }
4

5
  .board.hover-circle (data-cell):hover:not(.x):not(.circle) {
6
    background-color: lightcoral;
7
  }

در بالای فایل، این متغیرها را که نشان دهنده کلاس های شناور هستند، تعریف کنید.

1
const HOVER_X_CLASS = "hover-x";
2
const HOVER_CIRCLE_CLASS = "hover-circle";

سپس یک تابع به نام ایجاد کنید setBoardHoverClass()، که هدف آن افزودن یک افکت رنگ شناور بسته به نوبت آن است. این اطمینان حاصل می‌کند که بازیکنان می‌دانند وقتی روی سلول‌های تخته می‌روند، نوبت چه کسی است.

در setBoardHoverClass، ابتدا هر کلاس موجود را حذف می کنیم.

1
function setBoardHoverClass() {
2
  board.classList.remove(HOVER_X_CLASS);
3
  board.classList.remove(HOVER_CIRCLE_CLASS);
4
  
5
}

سپس، یک دستور if-else ایجاد می‌کنیم که بررسی می‌کند نوبت چه کسی است و کلاس‌های مناسب را در سلول‌های برد اعمال می‌کند.

1
function setBoardHoverClass() {
2
  board.classList.remove(HOVER_X_CLASS);
3
  board.classList.remove(HOVER_CIRCLE_CLASS);
4
  if (circleTurn) {
5
    board.classList.add(HOVER_CIRCLE_CLASS);
6
  } else {
7
    board.classList.add(HOVER_X_CLASS);
8
  }
9
}

در نهایت به handleClick() عملکرد و آن را به صورت زیر به روز کنید:

1
function handleClick(e) {
2
  const cell = e.target;
3
  const currentClass = circleTurn ? CIRCLE_CLASS : X_CLASS;
4
  console.log(currentClass);
5

6
  cell.classList.add(currentClass);
7
  circleTurn = !circleTurn;
8

9
  if (checkWin(currentClass)) {
10
    showResult(`${currentClass.toUpperCase()} wins`);
11
  } else if (isDraw()) {
12
    showResult(`It's a Draw`);
13
  } else {
14
    setBoardHoverClass();
15
  }
16
}

وقتی بعد از شروع بازی روی هر سلولی می روید، باید اثر آن را ببینید.

نتیجه نهایی

بیایید به خود یادآوری کنیم که چه ساخته ایم!

نتیجه گیری

در این آموزش نحوه ایجاد یک بازی tic-tac-toe در جاوا اسکریپت توضیح داده شده است. مفاهیم تحت پوشش به عنوان پایه ای محکم برای ساخت بازی های پیچیده تر عمل می کند.

منبع: https://webdesign.tutsplus.com/tic-tac-toe-game-with-vanilla-javascript–cms-108863t