Day 4: Building a Customizable Tic Tac Toe with Socket.io - Set Your Own Board Size and Play Online!

Tanmay BhansaliTanmay Bhansali
3 min read

In the previous three posts, I discussed the journey of developing a dynamic Tic-Tac-Toe game with multiplayer support. Here’s a brief recap:

Now, in Day 4, I’ve added some UI enhancements, including two new buttons for easier room management in online play and a new custom hook, useScreenSize, to make the game responsive across various device sizes. Let’s dive into today’s changes and how they improve the user experience!

Adding Copy Room and Leave Room Buttons

To make the game more interactive and user-friendly in online mode, I added two essential buttons:

  1. Copy Room ID: This button allows players to quickly copy the room ID to their clipboard for easy sharing.

  2. Leave Room: This button lets users exit the current room if they wish to leave the game.

These buttons are only visible when the game mode is set to "online," ensuring a clean and relevant UI for the pass-and-play mode.

The following snippet shows how these buttons are incorporated into the GameBoardPage component:

<div className="btn-container">
    <button className="reset-btn" onClick={handleBoardReset}>Reset Game</button>
    {gameMode === "online" && <button className="copy-btn" onClick={(e) => copyRoomId(e)}>Copy Id</button>}
    {gameMode === "online" && <button className="leave-btn" onClick={() => handleLeave()}>Leave Room</button>}
</div>

These buttons are part of the btn-container div, keeping them visually grouped and easy to access.

Making the Game Responsive with useScreenSize

With players joining from devices of varying screen sizes, I wanted the game board to adjust automatically for an optimal experience. For instance, on smaller screens, smaller grid cells make the game easier to play, while larger cells improve readability on bigger screens.

The useScreenSize custom hook helps manage screen resizing events dynamically. It listens for window resize events and updates the screenSize state whenever the dimensions change.

Here’s the complete code for useScreenSize:

import { useState, useEffect } from 'react';

function useScreenSize() {
  const [screenSize, setScreenSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  const updateScreenSize = () => {
    setScreenSize({
      width: window.innerWidth,
      height: window.innerHeight,
    });
  };

  useEffect(() => {
    window.addEventListener('resize', updateScreenSize);
    return () => window.removeEventListener('resize', updateScreenSize);
  }, []);

  return screenSize;
}

export default useScreenSize;

The screenSize object is passed to the GameBoardPage component. Based on the screen width, it dynamically adjusts the grid cell size. Here’s how I implemented it:

<div
    style={width <= 500 ? { gridTemplateColumns: `repeat(${boardSize}, 50px)` } : { gridTemplateColumns: `repeat(${boardSize}, 100px)` }}
    className="grid-container"
>
    {board.map((content, index) => <button key={index} onClick={() => handleClick(index)}>{content}</button>)}
</div>

This setup allows the game board to seamlessly transition between devices without compromising usability.

Final Thoughts

This day wraps up the core development of my dynamic, multiplayer Tic-Tac-Toe game! The game now supports pass-and-play, online connectivity, room-based sessions, and responsive design. These features collectively create an engaging experience suitable for players on any device.

10
Subscribe to my newsletter

Read articles from Tanmay Bhansali directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Tanmay Bhansali
Tanmay Bhansali