Невозможно установить для свойства "цвет" значение undefined

Я пытаюсь сделать простую игру, похожую на candyCrush, но все время получаю эту ошибку и не знаю, что делать.

Uncaught TypeError: Cannot set property 'color' of undefined at testForClick (numbercrunch2.html:50) at update (numbercrunch2.html:62)

Чтобы воссоздать ошибку, просто введите несколько чисел в текстовые поля, нажмите кнопку запуска и щелкните случайную плитку.

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");

var tilesX = 0,
  tilesY = 0,
  tilesWidthX, tilesWidthY, space = 3;
var numb = [];

var mousepos = {
    x: 0,
    y: 0
  },
  click = false;

function init(rows, cols) {
  tilesWidthX = (canvas.height - rows * 3) / rows;
  tilesWidthY = (canvas.height - cols * 3) / cols;
  tilesX = rows;
  tilesY = cols;

  for (var i = 0; i < tilesX; i++) {
    numb[i] = [];
    for (var j = 0; j < tilesY; j++) {
      numb[i][j] = {
        val: 1 + Math.round(Math.random() * 6),
        color: "grey"
      };

      ctx.beginPath();
      ctx.fillStyle = numb[i][j].color;
      ctx.fillRect(space + i * (tilesWidthY + space), space + j * (tilesWidthX + space), tilesWidthY, tilesWidthX);
      ctx.closePath();

      ctx.beginPath();
      ctx.fillStyle = "white";
      ctx.font = "20px Arial";
      ctx.fillText(numb[i][j].val, 15 + i * (tilesWidthY + space), 30 + j * (tilesWidthY + space), 50);
      ctx.closePath();
    }
  }
}

function testForClick(x, y) {
  if (space + x * (tilesWidthX + space) <= mousepos.x && space + y * (tilesWidthY + space) <= mousepos.y && (x + 1) * (tilesWidthX + space) >= mousepos.x && (y + 1) * (tilesWidthY + space) >= mousepos.y) {
    numb[x][y].color = "green"; //line 50
  }
}

function drawTile(x, y) {

}

function update() {
  for (var i = 0; i < 9; i++) {
    numb[i] = [];
    for (var j = 0; j < 9; j++) {
      testForClick(i, j);
      drawTile(i, j);
    }
  }
}
setInterval(update, 300);

function mouseposition(e) {

}
document.getElementById("canvas").addEventListener("click", function(e) {
  mousepos.x = e.clientX;
  mousepos.y = e.clientY;
}, false);
<canvas id = "canvas" height = "600" width = "600"></canvas>
<form name = "formname">
  Rows: <input type = "text" name = "rows"> Columns: <input type = "text" name = "columns">
  <input type = "button" value = "Start" onClick = "init(this.form.rows.value, this.form.columns.value)">
</form>
<div id = "t"></div>

может быть, вы нацеливаетесь на плитку из отскока? например .. если у вас есть пугающий 2x2 ... убедитесь, что вы не нацеливаетесь на scare x position 3.

Christophe Chenel 25.10.2018 17:53

Число [x] [y] не относится к допустимому элементу. Узнай почему. Мы не можем сами продублировать проблему, так как мы не знаем HTML или числа, которые используются для вызова testForClick ().

Shilly 25.10.2018 17:54

Я сделал фрагмент вашего кода JavaScript, теперь, пожалуйста, добавьте немного HTML и любого CSS, демонстрирующего проблему, с как можно меньшим количеством разметки!

Mark Schultheiss 25.10.2018 18:30

Чего ты ждешь? вы должны изменить цвет после одного щелчка по плитке на основе рассчитанных координат?

James 25.10.2018 22:41

Что должен делать этот код? можешь подробнее рассказать о функционале игры?

James 25.10.2018 22:44
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
5
1 018
1

Ответы 1

Каждый раз, когда вы запускаете update(), вы буквально обновляете свою переменную numb, заменяя предыдущий объект пустым Array object, таким образом, при вызове testForClick() в нем нет объекта, который бросает error.

function update() {
    for (var i = 0;i < 9;i++) {
        numb[i] = [];
        for ( var j = 0;j < 9;j++) {
            testForClick(i,j);
            drawTile(i,j);
        }
    }
} setInterval(update,300);

Должно быть:

function update()
{
    for (var i = 0; i < 9; i++)
    {
        for (var j = 0; j < 9; j++)
        {
            testForClick(i, j);
            drawTile(i, j);
        }
    }
};

Я создал фрагмент, показывающий, как комментирование (или удаление) строки numb[i] = []; из update() заставит ее работать.

Я обновил ваш скрипт:

// Also, I renamed your 'c' var to 'canvas' because in your init() you are calling it canvas and not 'c'.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var tilesX = 0, tilesY = 0, tilesWidthX, tilesWidthY, space = 3;
var numb = [];

var mousepos = {x: 0, y: 0}, click = false;

function init(rows, cols)
{
    tilesWidthX = (canvas.height - rows * 3) / rows;
    tilesWidthY = (canvas.height - cols * 3) / cols;
    tilesX = rows;
    tilesY = cols;

    for (var i = 0; i < tilesX; i++)
    {
        numb[i] = [];

        for (var j = 0; j < tilesY; j++)
        {
            numb[i][j] = {
                val: 1 + Math.round(Math.random() * 6),
                color: 'grey'
            };

            ctx.beginPath();
            ctx.fillStyle = numb[i][j].color;
            ctx.fillRect(space + i * (tilesWidthY + space), space + j * (tilesWidthX + space), tilesWidthY, tilesWidthX);
            ctx.closePath();

            ctx.beginPath();
            ctx.fillStyle = 'white';
            ctx.font = '20px Arial';
            ctx.fillText(numb[i][j].val, 15 + i * (tilesWidthY + space), 30 + j * (tilesWidthY + space), 50);
            ctx.closePath();
        }
    }
}

function testForClick(x, y)
{
    // Now your 'numb' variable hasn't been changed.
    console.info('testForClick', numb);

    if (space + x * (tilesWidthX + space) <= mousepos.x && space + y * (tilesWidthY + space) <= mousepos.y && (x+1) * (tilesWidthX + space) >= mousepos.x && (y+1) * (tilesWidthY + space) >= mousepos.y)
    {
        numb[x][y].color = 'green'; //line 50
    }
}

function drawTile(x, y)
{
}

function update()
{
    for (var i = 0; i < 9; i++)
    {
        // Every time you update you replace your object with 'val' and 'color' for an empty array.
        // that is the reason why every time you call testForClick you have no object in it.
        // Just comment/delete this line so your object never disappears.
        // numb[i] = [];

        for (var j = 0; j < 9; j++)
        {
            testForClick(i, j);
            drawTile(i, j);
        }
    }
};

// Changed the interval because I didn't have enough time to enter the rows and columns.
setInterval(update, 5000);

function mouseposition(e)
{
}

document.getElementById('canvas').addEventListener('click', function(e){
    mousepos.x = e.clientX;
    mousepos.y = e.clientY;
}, false);

СНИППЕТ:

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var tilesX = 0, tilesY = 0, tilesWidthX, tilesWidthY, space = 3;
var numb = [];

var mousepos = {x: 0, y: 0}, click = false;

function init(rows, cols)
{
	tilesWidthX = (canvas.height - rows * 3) / rows;
	tilesWidthY = (canvas.height - cols * 3) / cols;
	tilesX = rows;
	tilesY = cols;

	for (var i = 0; i < tilesX; i++)
	{
		numb[i] = [];

		for (var j = 0; j < tilesY; j++)
		{
			numb[i][j] = {
				val: 1 + Math.round(Math.random() * 6),
				color: 'grey'
			};

			ctx.beginPath();
			ctx.fillStyle = numb[i][j].color;
			ctx.fillRect(space + i * (tilesWidthY + space), space + j * (tilesWidthX + space), tilesWidthY, tilesWidthX);
			ctx.closePath();

			ctx.beginPath();
			ctx.fillStyle = 'white';
			ctx.font = '20px Arial';
			ctx.fillText(numb[i][j].val, 15 + i * (tilesWidthY + space), 30 + j * (tilesWidthY + space), 50);
			ctx.closePath();
		}
	}
}

function testForClick(x, y)
{
	// Now your 'numb' variable hasn't been changed.
	console.info('testForClick', numb);

	if (space + x * (tilesWidthX + space) <= mousepos.x && space + y * (tilesWidthY + space) <= mousepos.y && (x+1) * (tilesWidthX + space) >= mousepos.x && (y+1) * (tilesWidthY + space) >= mousepos.y)
	{
		numb[x][y].color = 'green'; //line 50
	}
}

function drawTile(x, y)
{
}

function update()
{
	for (var i = 0; i < 9; i++)
	{
		for (var j = 0; j < 9; j++)
		{
			testForClick(i, j);
			drawTile(i, j);
		}
	}
};

setInterval(update, 5000);

function mouseposition(e)
{
}

document.getElementById('canvas').addEventListener('click', function(e){
	mousepos.x = e.clientX;
	mousepos.y = e.clientY;
}, false);
<!DOCTYPE html>
<html>
	<head>
		<title>numbercrunch 2</title>
		<meta charset = "utf-8">
		<style>
			canvas {
				border: 2px solid black;
			}
		</style>
	</head>
	<body>
	<canvas id = "canvas" height = "600" width = "600"></canvas>
	<form name = "formname">
		Rows: <input type = "text" name = "rows">
		Columns: <input type = "text" name = "columns">
		<input type = "button" value = "Start" onClick = "init(this.form.rows.value, this.form.columns.value)">
	</form>
	<div id = "t"></div>
	</body>
</html>

Другие вопросы по теме