How to make a Tick Tech Monday game with Phaser Dot JS

by SkillAiNest

Tick Tech toe is a huge project for the starters who want to learn how to build sports. It’s easy to understand but gives you the opportunity to know about the game estate, player turn, winning logic, and user input.

In this tutorial, you will learn how to prepare TIC-TAC-TOE by using phaser.jsA sharp, entertainment and open source framework to make 2D games in the browser.

If you are new to Phaser.js, don’t worry. We will go through everything by step. Finally, you will have a working game that you can play, distribute or build.

You can Play the game here To get the realization of what you are going to build.

The table of content

What is phaser.js?

Phaser.js is a free and open source javascript game framework. This helps developers to make HTML5 games that work in web browsers. Handle things such as presenting a physic graphics, detection, and running a game loop.

You can use a phase to create an easy game like Pong and Tick Tech or Modern Plateframers and Roll players. It supports both canvas and web GL rendering, so your games will easily run on most devices.

Project Setup

Create a folder for your project and add two files: index.html And game.js. The HTML loads the file feaser and the Javascript file contains the game logic. Here is the storage With the created code.

What is here index.html File should look like:

html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>Tic Tac Toe — Phaser 3title>
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <style>
    html, body { height: 100%; margin: 0; background: #0f172a; display: grid; place-items: center; }
    #game { box-shadow: 0 10px 30px rgba(0,0,0,.35); border-radius: 12px; overflow: hidden; }
    .hint { color: #e2e8f0; margin-top: 10px; font-size: 14px; text-align: center; opacity: .85; }
  style>
  <script src="https://cdn.jsdelivr.net/npm/phaser@3.60.0/dist/phaser.min.js">script>
head>
<body>
  <div id="game">div>
  <div class="hint">Click a cell to play. Tap “Restart” to start over.div>
  <script src="./game.js">script>
body>
html>

It sets a simple HTML page, loads the CDN from CDN, and indicates you game.js File #game The container is the place where the Phaser Game Canvas will enter.

How to configure the game configuration

Faser Games are created from a configuration object that explains things like width, height, background color, and which works to load, create and update the game.

(() => {
  const GRID = 3;
  const CELL = 120;
  const BOARD = GRID * CELL;
  const HUD = 72;
  const WIDTH = BOARD;
  const HEIGHT = BOARD + HUD;

  let scene;
  let board;
  let currentPlayer;
  let gameOver;

  let gridGfx;
  let overlayGfx;
  let marks = ();
  let statusText;
  let restartText;

  const config = {
    type: Phaser.AUTO,
    parent: "game",
    width: WIDTH,
    height: HEIGHT,
    backgroundColor: "#ffffff",
    scale: { mode: Phaser.Scale.FIT, autoCenter: Phaser.Scale.CENTER_BOTH },
    scene: { preload, create, update }
  };

  new Phaser.Game(config);

We begin to explain permanently for grid size and cell size. config Objects tells the phaser that they make and use a game with these dimensions preloadFor, for, for,. createAnd update We will explain the functions.

Method to pre -load assets

Since we are pulling everything with the Physeria’s graphics and text tools, we do not need to load any external images or sounds.

  function preload() {
    
  }

This is a place holder that lets call the Phaser preload Before the game begins.

How to make a game scene

create The function runs once at the beginning of the scene. Here we draw the grid, set up early state, and add UI elements.

  function create() {
    scene = this;

    gridGfx = scene.add.graphics({ lineStyle: { width: 4, color: 0x000000 } });
    overlayGfx = scene.add.graphics();
    drawGrid();

    initGame();

    statusText = scene.add.text(WIDTH / 2, BOARD + 12, "Player X's turn", {
      fontSize: "20px",
      color: "#111",
      fontFamily: "Arial, Helvetica, sans-serif"
    }).setOrigin(0.5, 0);

    restartText = scene.add.text(WIDTH / 2, BOARD + 38, "Restart", {
      fontSize: "18px",
      color: "#2563eb",
      fontFamily: "Arial, Helvetica, sans-serif"
    }).setOrigin(0.5, 0).setInteractive({ useHandCursor: true });

    restartText.on("pointerup", hardReset);

    scene.input.on("pointerdown", onPointerDown, scene);
  }

We created two Graphics Object: One for a static grid and the other for one line. Then we called drawGrid() And initGame() To set the gameboard. Status text and reacher buttons are placed under the grid. We also heard with clicks in the board pointerdown.

How to pull the grid

The grid is made of two vertical and two horizontal lines.

  function drawGrid() {
    gridGfx.strokeLineShape(new Phaser.Geom.Line(CELL, 0, CELL, BOARD));
    gridGfx.strokeLineShape(new Phaser.Geom.Line(CELL * 2, 0, CELL * 2, BOARD));
    gridGfx.strokeLineShape(new Phaser.Geom.Line(0, CELL, BOARD, CELL));
    gridGfx.strokeLineShape(new Phaser.Geom.Line(0, CELL * 2, BOARD, CELL * 2));
  }

We use Phaser.Geom.Line To describe the start and end points of each line and then stretch with them strokeLineShape.

How to start the game and reset

initGame Function compiles a new game, and hardReset It is said when the start button is clicked again.

  function initGame() {
    board = Array.from({ length: GRID }, () => Array(GRID).fill(""));
    currentPlayer = "X";
    gameOver = false;
    overlayGfx.clear();
    for (const t of marks) t.destroy();
    marks = ();
    setStatus("Player X's turn");
  }

  function hardReset() {
    initGame();
  }

  function setStatus(msg) {
    statusText && statusText.setText(msg);
  }

The board is represented by 2D array full of empty wires. Begins as the current Player X, and marks The arrows look at the text object so we can clean them on the reset.

How to handle the player input

When the player clicks on a cell, we determine its row and column and check if the move is correct or not.

  function onPointerDown(pointer) {
    if (gameOver) return;
    if (pointer.y > BOARD) return;

    const col = Math.floor(pointer.x / CELL);
    const row = Math.floor(pointer.y / CELL);
    if (!inBounds(row, col)) return;
    if (board(row)(col) !== "") return;

    placeMark(row, col, currentPlayer);

    const win = checkWin(board);
    if (win) {
      gameOver = true;
      drawWinLine(win);
      setStatus(`Player ${currentPlayer} wins!`);
      return;
    }

    if (isFull(board)) {
      gameOver = true;
      setStatus("Draw! No more moves.");
      return;
    }

    currentPlayer = currentPlayer === "X" ? "O" : "X";
    setStatus(`Player ${currentPlayer}'s turn`);
  }

This ensures that we only work only if the game does not end, the click is inside the board, and the selected cell is empty. After marking, we test the win or draw before bending.

How to make marks on the board

We display an X or O in the center of the Click Cell.

  function inBounds(r, c) {
    return r >= 0 && r < GRID && c >= 0 && c < GRID;
  }

  function placeMark(row, col, player) {
    board(row)(col) = player;
    const cx = col * CELL + CELL / 2;
    const cy = row * CELL + CELL / 2;
    const t = scene.add.text(cx, cy, player, {
      fontSize: Math.floor(CELL * 0.66) + "px",
      color: "#111111",
      fontFamily: "Arial, Helvetica, sans-serif"
    }).setOrigin(0.5);
    marks.push
  }

The points are calculated so that the text is focused in the cell. We store the text Object in this marks So array, so it can be removed when resetting.

How to test a winner

We check the rows, columns and the Akhtar to see if the current player has three consecutive consecutive consecutive.

  function checkWin(b) {
    for (let r = 0; r < GRID; r++) {
      if (b(r)(0) && b(r)(0) === b(r)(1) && b(r)(1) === b(r)(2)) {
        return { kind: "row", index: r };
      }
    }
    for (let c = 0; c < GRID; c++) {
      if (b(0)(c) && b(0)(c) === b(1)(c) && b(1)(c) === b(2)(c)) {
        return { kind: "col", index: c };
      }
    }
    if (b(0)(0) && b(0)(0) === b(1)(1) && b(1)(1) === b(2)(2)) {
      return { kind: "diag" };
    }
    if (b(0)(2) && b(0)(2) === b(1)(1) && b(1)(1) === b(2)(0)) {
      return { kind: "anti" };
    }
    return null;
  }

If one wins, we return an item by describing the winning line so that it can be drawn.

How to detect drawbacks

If every cell is full and there is no winner, the game ends in draw.

  function isFull(b) {
    for (let r = 0; r < GRID; r++) {
      for (let c = 0; c < GRID; c++) {
        if (b(r)(c) === "") return false;
      }
    }
    return true;
  }

It looses on every cell and if one is empty, it returns wrong.

How to pull the winning line

A red line has been drawn on the winning cells.

  function drawWinLine(res) {
    overlayGfx.clear();
    overlayGfx.lineStyle(6, 0xef4444, 1);
    const pad = 14;
    const half = CELL / 2;

    if (res.kind === "row") {
      const y = res.index * CELL + half;
      overlayGfx.strokeLineShape(new Phaser.Geom.Line(pad, y, BOARD - pad, y));
    } else if (res.kind === "col") {
      const x = res.index * CELL + half;
      overlayGfx.strokeLineShape(new Phaser.Geom.Line(x, pad, x, BOARD - pad));
    } else if (res.kind === "diag") {
      overlayGfx.strokeLineShape(new Phaser.Geom.Line(pad, pad, BOARD - pad, BOARD - pad));
    } else if (res.kind === "anti") {
      overlayGfx.strokeLineShape(new Phaser.Geom.Line(BOARD - pad, pad, pad, BOARD - pad));
    }
  }
})();

Coordinator is calculated based on a type of win to ensure that the line goes through the right cells.

Great Now open index.html And you can start playing games!

The last game

The final views

Now you have made a full -fledged tech toe game in Phaser.com. This includes 3×3 grid, turn turn, win the win with a feature line, draw the draw, and resume button. The code uses basic game development concepts such as input handling, game estate management, and rendering, which you can use in major projects.

If you enjoy online games, check out Game BoostThe final market for concerts. You can find Fortnite accounts With special skins, with other famous sports options such as Guru a Garden, Kalash of Klens, and more.

You may also like

Leave a Comment

At Skillainest, we believe the future belongs to those who embrace AI, upgrade their skills, and stay ahead of the curve.

Get latest news

Subscribe my Newsletter for new blog posts, tips & new photos. Let's stay updated!

@2025 Skillainest.Designed and Developed by Pro