Is there a way to overlay a 'secret' grid on top of a canvas that features a background image?

I am currently working on developing an HTML/JS turn-based game, where I have implemented a canvas element using JavaScript. The canvas has a repeated background image to resemble a 10x10 squared board. However, I want to overlay a grid on top of it so that each square can be clickable for characters to move and for squares to light up upon hover.

Could someone please suggest the simplest way to achieve this?

Thank you in advance.

Below is the code snippet that I used to create the canvas in JavaScript:

const myGameArea = {
    canvas: document.createElement("canvas"),
    start: function() {
        this.canvas.width = 480;
        this.canvas.height = 480;
        this.canvas.style.cursor = "default"; 
        this.context = this.canvas.getContext("2d");
        document.body.append(this.canvas, document.body.childNodes[0]);
        this.frameNo = 0;
        this.interval = setInterval(updateGameArea, 20);
        window.addEventListener('onclick()', function(e) {
            myGameArea.x = e.pageX;
            myGameArea.y = e.pageY;
        });

Answer №1

To create a grid on an image, you have the option of either creating an image with the grid overlaid or using the lineTo method to draw lines directly on the grid. You can repeat this process to generate the entire grid.

let canvas = <link to canvas>;
let context = canvas.getContext('2d');
let gridSize = 10;
let canvasSize = {
    width:400;
    height:400;
}
for(let i=0;i<canvasSize.height;i+=gridSize){
    context.beginPath();
    context.moveTo(i,0);
    context.lineTo(i,canvasSize.height);
    context.strokeStyle = "#222222";
    context.stroke();
}

for(let i=0;i<canvasSize.width;i+=gridSize){
    context.beginPath();
    context.moveTo(0,i);
    context.lineTo(canvasSize.width,i);
    context.strokeStyle = "#222222";
    context.stroke();
}

If you need further guidance, I suggest exploring the resources available at . It's a valuable source for mastering canvas manipulations.

Answer №2

To create a grid overlay that allows your game to determine which grid cell was clicked, you can generate separate DOM elements for each cell aligned with the grid dimensions. Using CSS, define styling rules for each grid cell and use the ":hover" selector for hover effects:

/* Styling for each tile in grid with absolute 
position against relative wrapper */
.gameAreaWrapper a {
  display: block;
  position: absolute;
  width: 10%;
  height: 10%;
}

/* Hover effect to highlight cell on mouseover */
.gameAreaWrapper a:hover {
  background: rgba(255, 255, 0, 0.5);
}

A JavaScript function with nested loops can then be used to populate cells for a 10x10 grid like this:

function generateGameBoardSquares(wrapper) {

  for (let x = 0; x < 10; x++) {
    for (let y = 0; y < 10; y++) {

      const cell = document.createElement("a");
      cell.style.left = `${x * 10}%`;
      cell.style.top = `${y * 10}%`;

      wrapper.append(cell);
    }
  }
}

Below is a complete demo showcasing these concepts:

/* Helper function to generate square grid within a given wrapper */
function generateGameBoardSquares(wrapper) {

  function onClick(x, y) {
    alert(`You clicked ${x}, ${y}`);
  }

  for (let x = 0; x < 10; x++) {
    for (let y = 0; y < 10; y++) {

      const tile = document.createElement("a");
      tile.style.left = `${x * 10}%`;
      tile.style.top = `${y * 10}%`;
      tile.addEventListener("click", () => onClick(x, y));

      wrapper.append(tile);
    }
  }
}

var myGameArea = {
  canvas: document.createElement("canvas"),
  start: function() {
    this.canvas.width = 480;
    this.canvas.height = 480;
    this.canvas.style.cursor = "default";
    this.context = this.canvas.getContext("2d");

    const gameAreaWrapper = document.querySelector(".gameAreaWrapper");
    gameAreaWrapper.append(this.canvas);

    gameAreaWrapper.style.width = `${this.canvas.width}px`;
    gameAreaWrapper.style.height = `${this.canvas.height}px`;

    generateGameBoardSquares(gameAreaWrapper);

    this.frameNo = 0;

    window.addEventListener('click', function(e) {
      myGameArea.x = e.pageX;
      myGameArea.y = e.pageY;
    })
  }
}

myGameArea.start()
/* Highlight grid boundary */
canvas {
  background: rgba(255, 0, 0, 0.1);
}

/* Wrapper style for positioning grid cells */
.gameAreaWrapper {
  position: relative;
}

/* Styling for each grid cell with absolute positioning */
.gameAreaWrapper a {
  display: block;
  position: absolute;
  width: 10%;
  height: 10%;
}

/* Hover effect for grid cells */
.gameAreaWrapper a:hover {
  background: rgba(255, 255, 0, 0.5);
}
<div class="gameAreaWrapper">
  <!--
  Canvas and grid populated by script
  <canvas />
-->
</div>

I hope this explanation helps!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Verification of Radiobox Groups in AngularJS

Could you please help me with validating a radiogroup using AngularJS, which is instantiated within an additional directive? The validation requirement is that the User must not be able to submit unless one of the radio buttons has been selected. This is ...

Determining when a message has been ignored using php

One of the features I am working on for my app is adding announcements, which are essentially personalized messages to users. Once a user receives a message and dismisses it, I want to ensure that specific message does not appear again. Here is the PHP co ...

Creating a JQuery statement to conditionally change CSS values

Is there a way to determine if a div element with a CSS class of "x" has a height set to "auto"? If so, I would like a jQuery script to remove the CSS class "a" from all elements with the class "y". If not, the script can remain unchanged. Thank you. ...

How to trigger a force reload on a VueJS route with a different query parameter?

Is there a method to refresh the page component when two pages utilize the same Component? I have encountered an issue where the router does not reload and the previous edit values persist. { path: "/products/new", component: ProductPage, meta: { ...

Retrieve the index of the item that has been selected in a dropdown list

<select ng-click="getIndex($index)" size="14" ng-model="playlist.fileSelected" ng-options="saveFile for saveFile in playlist.playlist"></select> When I try to access $index, it shows up as undefined. Is there a way to retrieve the index of the ...

An async/await global variable in Javascript is initially defined, then ultimately becomes undefined

As I work on establishing a mongoDB endpoint with NodeJS and implementing this backend, I encounter an issue within the code. In particular, the function static async injectDB sets a global variable let restaurants that is then accessed by another function ...

What is the correct method in CSS to resize an image while maintaining its proportions within a div container?

I've been struggling to properly insert images into a <div> element on my website. I've experimented with various techniques, such as setting max-width and max-height to 100%, changing the display property of the parent element to flex, and ...

Filter an array in Angular 2 and add additional data to it

Quick query: I have 2 arrays/objects. The first one contains all items, while the second contains selected IDs from the first array. My question is, what is the most efficient way to iterate through both arrays, identify selected items from the second arr ...

Learn the simple steps to duplicate events using ctrl, drag, and drop feature in FullCalendar v5 with just pure JavaScript

My goal is to incorporate CTRL + Drag & Drop functionality in FullCalendar v5 using nothing but pure JavaScript. I delved into the topic and discovered that this feature has been discussed as a new UI feature request on the FC GitHub repository. There ...

What is the best way to make a JSONP request using jQuery?

Whenever I try to access this API through the browser, everything works fine and I receive the correct response. However, when I attempt to call the API using jQuery AJAX, I encounter an error. *The script is being refused execution from 'http://api ...

Show a modal component from another component in Angular 2

As a newcomer to Angular, I'm working on a modal component that changes from hiding to showing when a button with (click) is clicked. The goal is to integrate this modal into my main component, allowing me to display the modal on top of the main conte ...

Is it possible to customize the background color of the 'rows per page' selector box in Bootstrap 4 bootstrap-table?

The text is set in white on a dark grey background by default and appears just below the formatted table. Best regards, Phil Please refer to the attached image:Section of table showing rows per page selector box ...

A guide on using the patch API and Multer package to update files and images

After reviewing my code, I have successfully created a user model and imported it into the controller. Additionally, I have also imported an upload middleware from another directory where the code is written for uploading files/images using the multer pack ...

Guidelines for incorporating a router into the title of a Vuetify.js toolbar

I am currently utilizing vuetify.js in my project and I encountered an issue. I wanted the application title to link to the top menu, but when navigating to /route shop and /discount, the HogeHoge button's state changed unexpectedly. Is there a soluti ...

Is it possible in Vue.js to create a reactive functionality for a button using a watcher for "v-if" condition?

I have a userlist page with various profiles, including my own. A button is supposed to appear only when viewing my own profile. The issue arises when switching from a different profile to my own (changing the router parameter) - the button should show up ...

What are the steps to create parallel curves in three.js for road markings?

My goal is to create parallel curved lines that run alongside each other. However, when I try to adjust their positions in one axis, the outcome is not what I expected. The code I am using is fairly simple - it involves a bezier curve as the central path ...

When the Angular UI Bootstrap typeahead ng-model is cleared, it displays as null

The filter is performing admirably, however, after deleting the entered text, the {{filterlist.name}} displays null. This leads to the tables appearing empty due to the presence of null. Check out the demo here: https://plnkr.co/edit/1QVdctw1hr4ggJOtFHUZ? ...

Bootstrap is an outdated page template that lacks responsiveness

My code below features a page designed using Bootstrap HTML and CSS, but it doesn't look right on all devices. For example, on mobile devices, the grid appears zoomed in and unresponsive. I tried removing grid-template-columns: auto auto;, which fixed ...

Managing collapsible content in Bootstrap 4: A comprehensive guide

How can I customize collapsible content in Bootstrap 4? For instance, take a look at this navbar: https://i.sstatic.net/UYbMQ.png https://i.sstatic.net/OuVdw.png https://i.sstatic.net/lXvYt.png I'm looking to modify the behavior of this example. ...

Creating a website without access to the internet

When I'm working on my laptop in locations without internet access, I need to build a website. How can I assess the progress of my pages without an active browser? ...