I'm trying to make a simple candyCrush-like game but I keep getting this error and don't know what to do.
Uncaught TypeError: Cannot set property 'color' of undefined
at testForClick (numbercrunch2.html:50)
at update (numbercrunch2.html:62)
To recreate the error just put some numbers into the text boxes, hit the starting button and click on a random tile.
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>
Every time you run update() you literally update your numb variable by replacing the previous object for an empty Array object thus when calling testForClick() it has no object in it throwing the 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);
Should be:
function update()
{
for (var i = 0; i < 9; i++)
{
for (var j = 0; j < 9; j++)
{
testForClick(i, j);
drawTile(i, j);
}
}
};
I created a snippet showing how commenting (or removing) the numb[i] = []; line from update() will make it work.
I updated your script:
// 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.log('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);
SNIPPET:
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.log('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>
Related
I've written this quick script for random moving lines for the background for my portfolio. It works smoothly alone but when I start working with other CSS animations and stuff, there's a frame drop at the beginning (later it runs smooth). At least on my PC, struggles on low-end PC.
Some tips to optimize it would be helpful.
Here's my code:
/*Random Line Render Script aka Mini Browser Crasher */
/*XD Can't Revise This Script. Rofl Drains Memory. May crash low-end pc :V */
var c = document.getElementById("graph");
var dimension = [document.documentElement.clientWidth, document.documentElement.clientHeight];
c.width = dimension[0];
var ctx = c.getContext("2d");
var ctx2 = c.getContext("2d");
var posx = [100, 200, 150, 100, 0];
var posy = [100, 200, 300, 100, -100];
var posx2 = [600, 400, 200, 600];
var posy2 = [500, 200, 100, 150, 500, 500];
var posx3 = [];
var posy3 = [];
/*Generate random values for array( random starting point ) */
for (var i = 0; i < 2; i++) {
posx2.push(500 + Math.round(Math.random() * 700));
posy2.push(Math.round(Math.random() * 900));
}
for (var i = 0; i < 5; i++) {
posx3.push(1000 + Math.round(Math.random() * 300));
posy3.push(0 + Math.round(Math.random() * 1000));
}
var posx_len = posx.length;
var posx2_len = posx2.length;
var posx3_len = posx3.length;
var xa, ya;
var opa = 1;
var amount = 0.01;
var sinang = 0;
var distance1 = 0;
var distance2 = 0;
document.body.addEventListener('mousemove', (function(event) {
xa = event.clientX;
ya = event.clientY;
}));
/*Render Lines */
function draw() {
ctx.clearRect(0, 0, 10000, 10000);
ctx.beginPath();
ctx.moveTo(posx[0], posy[0]);
for (var i = 0; i < posx_len; i++) {
ctx.lineTo(posx[i], posy[i]);
ctx.strokeStyle = 'rgba(255,255,255,' + opa + ')';
ctx.stroke();
ctx.arc(posx[i], posy[i], 5, 0, 2 * Math.PI, false);
}
if (opa > 1) {
amount = -0.01 * Math.random();
}
if (opa < 0) {
amount = 0.01 * Math.random();
}
opa = opa + amount;
ctx.moveTo(posx2[0], posy2[0]);
for (var i = 0; i < posx2_len; i++) {
ctx.lineTo(posx2[i], posy2[i]);
ctx.strokeStyle = 'rgba(255,255,255,' + opa + ')';
ctx.stroke();
ctx.arc(posx2[i], posy2[i], 5, 0, 2 * Math.PI, false);
}
ctx.moveTo(posx3[0], posy3[0]);
for (var i = 0; i < posx3_len; i++) {
ctx.lineTo(posx3[i], posy3[i]);
ctx.strokeStyle = 'rgba(255,255,255,' + opa + ')';
ctx.stroke();
ctx.arc(posx3[i], posy3[i], 5, 0, 2 * Math.PI, false);
}
sinang = sinang + 0.01;
/*Frame Render Ends here*/
/*Calculation for next frame*/
for (var i = 0; i < posx_len; i++) {
posx[i] = posx[i] + (Math.cos(sinang) * i) / 2; /* Sin curve for smooth value transition. Smooth assss Butter */
posy[i] = posy[i] + (Math.cos(sinang) * i) / 2;
/* Can't believe Distance Formula is useful ahaha */
distance1 = Math.sqrt(Math.pow((posx[i] - xa), 2) + Math.pow((posy[i] - ya), 2));
if (distance1 <= 500) {
ctx.moveTo(posx[i], posy[i]);
ctx.lineTo(xa, ya);
}
for (var j = 0; j < posx2_len; j++) {
distance12 = Math.sqrt(Math.pow((posx[i] - posx2[j]), 2) + Math.pow((posy[i] - posy2[j]), 2));
if (distance12 <= 500) {
ctx.moveTo(posx[i], posy[i]);
ctx.lineTo(posx2[j], posy2[j]);
}
}
for (var j = 0; j < posx3_len; j++) {
distance13 = Math.sqrt(Math.pow((posx[i] - posx3[j]), 2) + Math.pow((posy[i] - posy3[j]), 2));
if (distance13 <= 500) {
ctx.moveTo(posx[i], posy[i]);
ctx.lineTo(posx3[j], posy3[j]);
}
}
}
posx[posx.length - 1] = posx[0];
posy[posy.length - 1] = posy[0];
/*Repeat Above Steps. Should have done this in Multi-dimensional array. Ugh I feel sad now*/
for (var i = 0; i < posx2_len; i++) {
posx2[i] = posx2[i] + (Math.sin(sinang) * i) / 2;
posy2[i] = posy2[i] - (Math.sin(sinang) * i) / 2;
distance2 = Math.sqrt(Math.pow((posx2[i] - xa), 2) + Math.pow((posy2[i] - ya), 2));
if (distance2 <= 500) {
ctx.moveTo(posx2[i], posy2[i]);
ctx.lineTo(xa, ya);
}
for (var j = 0; j < posx3_len; j++) {
distance22 = Math.sqrt(Math.pow((posx2[i] - posx3[j]), 2) + Math.pow((posy2[i] - posy3[j]), 2));
if (distance22 <= 500) {
ctx.moveTo(posx2[i], posy2[i]);
ctx.lineTo(posx3[j], posy3[j]);
}
}
}
posx2[posx2.length - 1] = posx2[0];
posy2[posy2.length - 1] = posy2[0];
for (var i = 0; i < posx3_len; i++) {
posx3[i] = posx3[i] - (Math.sin(sinang) * i) / 1.2;
posy3[i] = posy3[i] - (Math.sin(sinang) * i) / 1.2;
distance2 = Math.sqrt(Math.pow((posx3[i] - xa), 2) + Math.pow((posy3[i] - ya), 2));
if (distance2 <= 500) {
ctx.moveTo(posx3[i], posy3[i]);
ctx.lineTo(xa, ya);
}
}
posx3[posx3.length - 1] = posx3[0];
posy3[posy3.length - 1] = posy3[0];
ctx.restore();
ctx.stroke();
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
body {
background: #1f1f1f;
}
<canvas height="1080px" width="1100px" id="graph">
</canvas>
So, what I've done is used square colliders instead of circular(distance formula) and it has faster runtime now. (not much but still)
<html>
<head>
</head>
<style>
body{
background: #1f1f1f;
}
canvas{
}
</style>
<body >
<canvas height="1080px" width="1100px" id="graph">
</canvas>
</body>
<script>
/*Random Line Render Script aka Mini Browser Crasher */
/*XD Can't Revise This Script. Rofl Drains Memory. May crash low-end pc :V */
var c = document.getElementById("graph");
var dimension = [document.documentElement.clientWidth, document.documentElement.clientHeight];
c.width = dimension[0];
var ctx = c.getContext("2d");
var posx = [100,200,150,100,0];
var posy = [100,200,300,100,-100];
var posx2 = [600,400,200,600];
var posy2 = [500,200,100,150,500,500];
var posx3 = [];
var posy3 = [];
/*Generate random values for array( random starting point ) */
for(var i=0; i<2;i++){
posx2.push(500+Math.round(Math.random()*700));
posy2.push(Math.round(Math.random()*900));
}
for(var i=0; i<5;i++){
posx3.push(1000+Math.round(Math.random()*300));
posy3.push(0+Math.round(Math.random()*1000));
}
var posx_len = posx.length;
var posx2_len = posx2.length;
var posx3_len = posx3.length;
var xa,ya;
var opa =1;
var amount = 0.01;
var sinang = 0;
var distance1 = 0;
var distance2 = 0;
var t1, t2;
document.body.addEventListener('mousemove', (function (event) {
xa = event.clientX;
ya = event.clientY;
}));
/*Render Lines */
function draw(){
t1 =performance.now();
ctx.clearRect(0, 0, 1920,1080);
ctx.beginPath();
ctx.moveTo(posx[0], posy[0]);
for(var i= 0; i<posx_len;i++){
ctx.lineTo(posx[i], posy[i]);
ctx.arc(posx[i],posy[i], 5, 0, 2 * Math.PI, false);
}
if(opa>1){
amount = -0.01*Math.random();
}
if(opa<0){
amount =0.01*Math.random();
}
opa =opa +amount;
ctx.moveTo(posx2[0], posy2[0]);
for(var i = 0; i<posx2_len;i++){
ctx.lineTo(posx2[i], posy2[i]);
ctx.arc(posx2[i],posy2[i], 5, 0, 2 * Math.PI, false);
}
ctx.moveTo(posx3[0], posy3[0]);
for(var i = 0; i<posx3_len;i++){
ctx.lineTo(posx3[i], posy3[i]);
ctx.arc(posx3[i],posy3[i], 5, 0, 2 * Math.PI, false);
}
sinang = sinang+0.01;
/*Frame Render Ends here*/
/*Calculation for next frame*/
for(var i = 0;i<posx_len;i++){
posx[i] = posx[i]+ (Math.cos(sinang)*i)/2;/* Sin curve for smooth value transition. Smooth assss Butter */
posy[i] = posy[i]+ (Math.cos(sinang)*i)/2;
/* Can't believe Distance Formula is useful ahaha */
if(Math.abs(posx[i]-xa)<500 && Math.abs(posy[i]-ya)<500){
ctx.moveTo(posx[i],posy[i]);
ctx.lineTo(xa, ya);
}
for(var j = 0;j<posx2_len;j++){
if(Math.abs(posx[i]-posx2[j])<500 && Math.abs(posy[i]-posy2[j])<500){
ctx.moveTo(posx[i],posy[i]);
ctx.lineTo(posx2[j], posy2[j]);
}
}
for(var j = 0;j<posx3_len;j++){
if(Math.abs(posx[i]-posx3[j])<500 && Math.abs(posy[i]-posy3[j])<500){
ctx.moveTo(posx[i],posy[i]);
ctx.lineTo(posx3[j], posy3[j]);
}
}
}
posx[posx.length-1]=posx[0];
posy[posy.length-1] = posy[0];
/*Repeat Above Steps. Should have done this in Multi-dimensional array. Ugh I feel sad now*/
for(var i = 0;i<posx2_len;i++){
posx2[i] = posx2[i]+ (Math.sin(sinang)*i)/2;
posy2[i] = posy2[i]-(Math.sin(sinang)*i)/2;
if(Math.abs(posx2[i]-xa)<500 && Math.abs(posy2[i]-ya)<500){
ctx.moveTo(posx2[i],posy2[i]);
ctx.lineTo(xa, ya);
}
for(var j = 0;j<posx3_len;j++){
if(Math.abs(posx2[i]-posx3[j])<500 && Math.abs(posy2[i]-posy3[j])<500){
ctx.moveTo(posx2[i],posy2[i]);
ctx.lineTo(posx3[j], posy3[j]);
}
}
}
posx2[posx2.length-1]=posx2[0];
posy2[posy2.length-1] = posy2[0];
for(var i = 0;i<posx3_len;i++){
posx3[i] = posx3[i]- (Math.sin(sinang)*i)/1.2;
posy3[i] = posy3[i]-(Math.sin(sinang)*i)/1.2;
if(Math.abs(posx3[i]-xa)<500 && Math.abs(posy3[i]-ya)<500){
ctx.moveTo(posx3[i],posy3[i]);
ctx.lineTo(xa, ya);
}
}
posx3[posx3.length-1]=posx3[0];
posy3[posy3.length-1] = posy3[0];
ctx.restore();
ctx.strokeStyle = 'rgba(255,255,255,'+opa+')';
ctx.stroke();
window.requestAnimationFrame(draw);
t2=performance.now();
console.log(t2-t1);
}
window.requestAnimationFrame(draw);
</script>
</html>
Made a small game, the main goal is to remove all the pieces by jumping over the checkers. The first time it is possible to remove the checker, the second time it gives an error?
Uncaught TypeError: Cannot read property 'theRow' of undefined
On line 180. I looked at the line, here it is.
Code:
Point = function(x, y) {
this.x = x;
this.y = y;
}
window.onload = function() {
var canvas;
var context;
var BB;
var offsetX;
var offsetY;
var dragok = false;
var startX;
var startY;
var oldX, oldY;
var fieldArray = [
[1, 0, 1, 1, 0, 0],
[1, 0, 0, 1, 1, 0],
[0, 0, 0, 0, 0, 0]
];
var shapes = [];
var possibleLandings = [];
var localX, localY;
var pickedMonster;
var sx = 0;
var sy = 0;
var i1 = 0;
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.save();
for (var i = 0; i < fieldArray.length; i++) {
for (var j = 0; j < fieldArray[i].length; j++) {
context.lineWidth = 1;
context.strokeRect(j * 60, i * 60, 60, 60);
context.fillRect(j * 60, i * 60, 60, 60);
}
}
for (var i = 0; i < shapes.length; i++) {
circle(shapes[i]);
}
context.restore();
if (possibleLandings.length > 0) {
context.save();
context.fillStyle = "#4CFF00";
context.fillRect(oldX, oldY, 20, 20);
context.restore();
} else {
context.save();
context.fillStyle = "#FF0000";
context.fillRect(oldX, oldY, 20, 20);
context.restore();
}
}
function circle(c) {
context.fillStyle = c.fill;
context.beginPath();
context.arc(c.x, c.y, c.r, 0, Math.PI * 2);
context.closePath();
context.fill();
}
function myDown(e) {
e.preventDefault();
e.stopPropagation();
var mx = parseInt(e.clientX - offsetX);
var my = parseInt(e.clientY - offsetY);
dragok = false;
for (var i = 0; i < shapes.length; i++) {
var s = shapes[i];
var dx = s.x - mx;
var dy = s.y - my;
if (dx * dx + dy * dy < s.r * s.r) {
dragok = true;
s.isDragging = true;
pickedMonster = {
x: s.x,
y: s.y,
i: i,
theRow: s.theRow,
theCol: s.theCol
};
oldX = s.x;
oldY = s.y;
localX = mx - s.x + (30 / 2);
localY = my - s.y + (30 / 2);
checkMonster(s);
canvas.onmousemove = moveMonster;
canvas.onmouseup = dropMonster;
}
}
startX = mx;
startY = my;
}
function moveMonster(e) {
if (dragok) {
e.preventDefault();
e.stopPropagation();
var mx = parseInt(e.clientX - offsetX);
var my = parseInt(e.clientY - offsetY);
var dx = mx - startX;
var dy = my - startY;
for (var i = 0; i < shapes.length; i++) {
var s = shapes[i];
if (s.isDragging) {
s.x += dx;
s.y += dy;
pickedMonster.x = e.clientX - localX;
pickedMonster.y = e.clientY - localY;
}
}
draw();
startX = mx;
startY = my;
}
}
function dropMonster(e) {
e.preventDefault();
e.stopPropagation();
var legalMove = false;
var dropX = Math.floor((pickedMonster.x + 30) / 60);
var dropY = Math.floor((pickedMonster.y + 30) / 60);
console.log(dropX);
for (var i = 0; i < possibleLandings.length; i++) {
if (possibleLandings[i].x == dropY && possibleLandings[i].y == dropX) {
legalMove = true;
break;
}
}
if (!legalMove) {
shapes[pickedMonster.i].x = oldX;
shapes[pickedMonster.i].y = oldY;
} else {
var rowOffset = (dropY - pickedMonster.theRow) / 2;
var colOffset = (dropX - pickedMonster.theCol) / 2;
fieldArray[pickedMonster.theRow][pickedMonster.theCol] = 0;
fieldArray[pickedMonster.theRow + rowOffset][pickedMonster.theCol + colOffset] = 0;
fieldArray[pickedMonster.theRow + 2 * rowOffset][pickedMonster.theCol + 2 * colOffset] = 1;
for (i = 0; i < 5; i++) {
var currentMonster = shapes[i];
if (currentMonster.theRow == pickedMonster.theRow + rowOffset &&
currentMonster.theCol == pickedMonster.theCol + colOffset) {
shapes.splice(i, 1);
}
}
}
dragok = false;
for (var i = 0; i < shapes.length; i++) {
shapes[i].isDragging = false;
}
draw();
}
function checkMonster(s) {
for (var i = 0; i < 4; i++) {
var deltaRow = (1 - i) * (i % 2 - 1);
var deltaCol = (2 - i) * (i % 2);
if (checkField(s, deltaRow, deltaCol)) {
possibleLandings.push(new Point(s.theRow + 2 * deltaRow, s.theCol + 2 * deltaCol));
}
}
}
function checkField(s, rowOffset, colOffset) {
if (fieldArray[s.theRow + 2 * rowOffset] != undefined &&
fieldArray[s.theRow + 2 * rowOffset][s.theCol + 2 * colOffset] != undefined) {
if (fieldArray[s.theRow + rowOffset][s.theCol + colOffset] == 1 &&
fieldArray[s.theRow + 2 * rowOffset][s.theCol + 2 * colOffset] == 0) {
return true;
}
}
return false;
}
function main() {
canvas = document.getElementById("drawingCanvas"),
context = canvas.getContext("2d");
canvas.style.background = "#A0A0A0"
BB = canvas.getBoundingClientRect();
context.fillStyle = 'rgb(150,190,255)';
context.globalAlpha = 0.7;
offsetX = BB.left;
offsetY = BB.top;
for (var i = 0; i < fieldArray.length; i++) {
for (var j = 0; j < fieldArray[i].length; j++) {
if (fieldArray[i][j] == 1) {
shapes.push({
x: j * 60 + 30,
y: i * 60 + 30,
r: 30,
theRow: i,
theCol: j,
fill: "#444444",
isDragging: false
});
}
}
}
draw();
canvas.onmousedown = myDown;
}
main();
}
<canvas id="drawingCanvas" width="500" height="500">
How to fix?
At the end of the game shapes is empty but you are getting shapes[i]. That would return undefined. And that's what the error means undefined doesn't have a property theRow.
You should maybe rerun main() or only rerun this:
for (var i = 0; i < fieldArray.length; i++) {
for (var j = 0; j < fieldArray[i].length; j++) {
if (fieldArray[i][j] == 1) {
shapes.push({
x: j * 60 + 30,
y: i * 60 + 30,
r: 30,
theRow: i,
theCol: j,
fill: "#444444",
isDragging: false
});
}
}
}
I need some expert help. When I make canvas background transparent the line colors the whole canvas (shown in code below).
How do I stop/fix this? I want the line stay as a single line that doesn't color the canvas.
Math.clamp = function(x, min, max) {
return x < min ? min : (x > max ? max : x);
};
// canvas settings
var viewWidth = window.innerWidth,
viewHeight = window.innerHeight,
drawingCanvas = document.getElementById("drawing_canvas"),
ctx,
timeStep = (10 / 100),
time = 0;
var lineTension = 0.067,
lineDamping = 0.068,
waveSpreadFactor = 0.1;
var previousMousePosition = {
x: 0,
y: 0
},
currentMousePosition = {
x: 0,
y: 0
},
actualMousePosition = {
x: 0,
y: 0
};
var line,
lineSegmentCount = 64,
lineMaxForce = 32,
lineStrokeGradient;
var audioCtx,
nodeCount = 64,
oscillatorNodes = [],
gainNodes = [];
var segmentsPerNode = lineSegmentCount / nodeCount;
function initGui() {
}
function goBananas() {
lineTension = 0.2;
line.anchors[Math.floor(Math.random() * line.anchors.length)].
vel = lineMaxForce;
}
function resetLine() {
line.reset();
for (var i = 0; i < nodeCount; i++) {
oscillatorNodes[i].detune.value = 100;
gainNodes[i].gain.value = 0;
}
lineTension = 0.0025;
lineDamping = 0.05;
waveSpreadFactor = 0.1;
}
function initDrawingCanvas() {
drawingCanvas.width = viewWidth;
drawingCanvas.height = viewHeight;
window.addEventListener('resize', resizeHandler);
window.addEventListener('mousemove', mouseMoveHandler);
setInterval(updateMousePosition, (1000 / 30));
ctx = drawingCanvas.getContext('2d');
ctx.lineWidth = 5;
line = new Line(0, viewHeight * 0.5, viewWidth, lineSegmentCount);
// line.anchors[0].vel = viewHeight * 0.25;
lineStrokeGradient = ctx.createLinearGradient(0, 0, 0, viewHeight);
lineStrokeGradient.addColorStop(0, '#0ff');
}
function initWebAudio() {
audioCtx = new(window.AudioContext || window.webkitAudioContext)();
for (var i = 0; i < nodeCount; i++) {
var oscillatorNode = audioCtx.createOscillator();
var gainNode = audioCtx.createGain();
oscillatorNode.connect(gainNode);
gainNode.connect(audioCtx.destination);
gainNode.gain.value = 0;
oscillatorNode.type = 'saw';
oscillatorNode.detune.value = 200;
oscillatorNode.frequency.value = 1200 * (i / 60);
oscillatorNode.start();
oscillatorNodes[i] = oscillatorNode;
gainNodes[i] = gainNode;
}
}
function resizeHandler() {
drawingCanvas.width = viewWidth = window.innerWidth;
drawingCanvas.height = viewHeight = window.innerHeight;
if (ctx) {
ctx.lineWidth = 4;
line.resize(viewWidth, viewHeight * 0.5);
}
}
function mouseMoveHandler(event) {
actualMousePosition.x = Math.floor(event.clientX);
actualMousePosition.y = Math.floor(event.clientY);
}
function updateMousePosition() {
previousMousePosition.x = currentMousePosition.x;
previousMousePosition.y = currentMousePosition.y;
currentMousePosition.x = actualMousePosition.x;
currentMousePosition.y = actualMousePosition.y;
}
function update() {
var px = Math.min(previousMousePosition.x, currentMousePosition.x),
py = Math.min(previousMousePosition.y, currentMousePosition.y),
pw = Math.max(1, Math.abs(previousMousePosition.x - currentMousePosition.x)),
ph = Math.max(1, Math.abs(previousMousePosition.y - currentMousePosition.y)),
force = Math.clamp(currentMousePosition.y -
previousMousePosition.y, -lineMaxForce, lineMaxForce);
var pixels = ctx.getImageData(px, py, pw, ph),
data = pixels.data;
for (var i = 0; i < data.length; i += 3) {
var r = data[i + 0],
g = data[i + 1],
b = data[i + 2],
x = (i % ph) + px;
if (r + g + b > 0) {
line.ripple(x, force);
}
}
line.update();
for (var j = 0; j < gainNodes.length; j++) {
var anchor = line.anchors[j * segmentsPerNode],
gain = Math.clamp(Math.abs(anchor.vel) / viewHeight * 0.5, 0, 3),
detune = Math.clamp(anchor.pos / viewHeight * 100, 0, 300);
gainNodes[j].gain.value = gain;
oscillatorNodes[j].detune.value = detune;
}
}
function draw() {
ctx.strokeStyle = lineStrokeGradient;
line.draw();
}
window.onload = function() {
initDrawingCanvas();
initWebAudio();
initGui();
requestAnimationFrame(loop);
};
function loop() {
update();
draw();
time += timeStep;
requestAnimationFrame(loop);
}
Line = function(x, y, length, segments) {
this.x = x;
this.y = y;
this.length = length;
this.segments = segments;
this.segmentLength = this.length / this.segments;
this.anchors = [];
for (var i = 0; i <= this.segments; i++) {
this.anchors[i] = {
target: this.y,
pos: this.y,
vel: 0,
update: function() {
var dy = this.pos - this.target,
acc = -lineTension * dy - lineDamping * this.vel;
this.pos += this.vel;
this.vel += acc;
},
reset: function() {
this.pos = this.target;
this.vel = 0;
}
};
}
};
Line.prototype = {
resize: function(length, targetY) {
this.length = length;
this.segmentLength = this.length / this.segments;
for (var i = 0; i <= this.segments; i++) {
this.anchors[i].target = targetY;
}
},
reset: function() {
for (var i = 0; i <= this.segments; i++) {
this.anchors[i].reset();
}
},
ripple: function(origin, amplitude) {
var i = Math.floor((origin - this.x) / this.segmentLength);
if (i >= 0 && i <= this.segments) {
this.anchors[i].vel = amplitude;
}
},
update: function() {
var lDeltas = [],
rDeltas = [],
i;
for (i = 0; i <= this.segments; i++) {
this.anchors[i].update();
}
for (i = 0; i <= this.segments; i++) {
if (i > 0) {
lDeltas[i] = waveSpreadFactor * (this.anchors[i].pos - this.anchors[i - 1].pos);
this.anchors[i - 1].vel += lDeltas[i];
}
if (i < this.segments) {
rDeltas[i] = waveSpreadFactor * (this.anchors[i].pos - this.anchors[i + 1].pos);
this.anchors[i + 1].vel += rDeltas[i];
}
}
for (i = 0; i <= this.segments; i++) {
if (i > 0) {
this.anchors[i - 1].pos += lDeltas[i];
}
if (i < this.segments) {
this.anchors[i + 1].pos += rDeltas[i];
}
}
},
draw: function() {
ctx.beginPath();
for (var i = 0; i <= this.segments; i++) {
ctx.lineTo(
this.x + this.segmentLength * i,
this.anchors[i].pos
);
}
ctx.stroke();
}
};
From the code you posted, the problem seems to be a missing
ctx.clearRect(0, 0, viewWidth, viewHeight)
at the beginning of your "draw" function.
See a working example here
This is something a kid can try with markers and graph paper. Area estimation with tiles and it led me to this question: https://math.stackexchange.com/questions/978834/area-estimation-with-tiling
I wrote a simple code in <canvas> which looks at the top-left pixel of a tile, if the color is not red, it turns the tile blue.
Question: How to improve the AI so that it discards only tiles that contains less then 50% red color? Do I need an average (color density) function to determine this?
Here's my fiddle code, with black borders. The actual area is 3750 units. Naturally if I reduce the tile size, it gets closer to the actual area (read: calculus - too advance for a kid).
var sourceHeight = 90;
var sourceWidth = 300;
var pixelation = 10;
var tile_count = 0;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
ctx.moveTo(50, 75);
ctx.lineTo(200, 75);
ctx.lineTo(100, 25);
ctx.lineTo(50, 75);
ctx.fill();
ctx.fillStyle = 'lightgreen';
ctx.rect(0, 0, sourceWidth, sourceHeight);
ctx.fill();
var imgData = ctx.getImageData(0, 15, sourceWidth, sourceHeight);
var data = imgData.data;
for (var y = 0; y < sourceHeight; y += pixelation) {
for (var x = 0; x < sourceWidth; x += pixelation) {
var red = data[((sourceWidth * y) + x) * 4];
var green = data[((sourceWidth * y) + x) * 4 + 1];
var blue = data[((sourceWidth * y) + x) * 4 + 2];
if (red > 200) {
red = 255;
blue = 0;
green = 0;
tile_count += 1;
} else {
red = 135;
green = 206;
blue = 235;
}
for (var n = 0; n < pixelation; n++) {
for (var m = 0; m < pixelation; m++) {
if (x + m < sourceWidth) {
data[((sourceWidth * (y + n)) + (x + m)) * 4] = red;
data[((sourceWidth * (y + n)) + (x + m)) * 4 + 1] = green;
data[((sourceWidth * (y + n)) + (x + m)) * 4 + 2] = blue;
}
}
}
}
}
ctx.putImageData(imgData, 0, 115);
ctx.fillStyle = "black";
ctx.font = "14px Georgia";
ctx.fillText("Tile Size: " + pixelation, 200, 140);
ctx.fillText("Total Tiles: " + tile_count, 200, 155);
<canvas id="myCanvas" width="300" height="200" style="border:1px solid #d3d3d3;"></canvas>
I'd simply count the number of red pixels in the tile vs. the number of non-red ones:
var redcnt = 0, nonredcnt = 0, red, green, blue;
for (var n = 0; n < pixelation; n++) {
for (var m = 0; m < pixelation; m++) {
if (x + m < sourceWidth) {
red = data[((sourceWidth * (y + n)) + (x + m)) * 4];
if (red > 200)
++redcnt;
else
++nonredcnt
}
}
}
if (redcnt >= nonredcnt) {
var sourceHeight = 90;
var sourceWidth = 300;
var pixelation = 10;
var tile_count = 0;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
ctx.moveTo(50, 75);
ctx.lineTo(200, 75);
ctx.lineTo(100, 25);
ctx.lineTo(50, 75);
ctx.fill();
ctx.fillStyle = 'lightgreen';
ctx.rect(0, 0, sourceWidth, sourceHeight);
ctx.fill();
var imgData = ctx.getImageData(0, 15, sourceWidth, sourceHeight);
var data = imgData.data;
for (var y = 0; y < sourceHeight; y += pixelation) {
for (var x = 0; x < sourceWidth; x += pixelation) {
var redcnt = 0, nonredcnt = 0, red, green, blue;
for (var n = 0; n < pixelation; n++) {
for (var m = 0; m < pixelation; m++) {
if (x + m < sourceWidth) {
red = data[((sourceWidth * (y + n)) + (x + m)) * 4];
if (red > 200)
++redcnt;
else
++nonredcnt
}
}
}
if (redcnt >= nonredcnt) {
red = 255;
blue = 0;
green = 0;
tile_count += 1;
} else {
red = 135;
green = 206;
blue = 235;
}
for (var n = 0; n < pixelation; n++) {
for (var m = 0; m < pixelation; m++) {
if (x + m < sourceWidth) {
data[((sourceWidth * (y + n)) + (x + m)) * 4] = red;
data[((sourceWidth * (y + n)) + (x + m)) * 4 + 1] = green;
data[((sourceWidth * (y + n)) + (x + m)) * 4 + 2] = blue;
}
}
}
}
}
ctx.putImageData(imgData, 0, 115);
ctx.fillStyle = "black";
ctx.font = "14px Georgia";
ctx.fillText("Tile Size: " + pixelation, 200, 140);
ctx.fillText("Total Tiles: " + tile_count, 200, 155);
<canvas id="myCanvas" width="300" height="200" style="border:1px solid #d3d3d3;"></canvas>
I am trying to calculate Moore neighborhood.
If I set the loop to execute 10 times each (10x10 dimension), it works but when I change them to 20 times each (20x20 dimension), it froze the browser.
Why did it freeze?
var c_canvas = document.getElementById("c");
var context = c_canvas.getContext("2d");
var step = 20;
var n = 20,
m = 20;
var population = [];
var MIN_X = 0;
var MIN_Y = 0;
var MAX_X = 19;
var MAX_Y = 19;
for (var i = 0; i < m; i++) {
population[i] = [];
for (var j = 0; j < n; j++) {
population[i][j] = 0;
}
}
for (var x = 0; x < step; x++) {
context.beginPath();
context.moveTo(x * step, 0);
context.lineTo(x * step, step * step);
context.closePath();
}
for (var y = 0; y < step; y++) {
context.beginPath();
context.moveTo(0, y * step);
context.lineTo(step * step, y * step);
context.closePath();
}
function redrawGrid() {
for (var r = 0; r < step; r++) {
for (var z = 0; z < step; z++) {
var temp = population[r][z]
if (temp == 0) {
context.beginPath();
context.rect(r * step, z * step, step, step);
context.fillStyle = 'white';
context.fill();
context.closePath();
};
if (temp == 1) {
context.beginPath();
context.rect(r * step, z * step, step, step);
context.fillStyle = 'red';
context.fill();
context.closePath();
};
if (temp == 2) {
context.beginPath();
context.rect(r * step, z * step, step, step);
context.fillStyle = 'black';
context.fill();
context.closePath();
};
}
}
}
for (var r = 0; r < step; r++) {
for (var z = 0; z < step; z++) {
var temp = randomIntFromInterval(0, 2);
population[r][z] = temp;
if (temp == 0) {
context.beginPath();
context.rect(r * step, z * step, step, step);
context.fillStyle = 'white';
context.fill();
context.closePath();
};
if (temp == 1) {
context.beginPath();
context.rect(r * step, z * step, step, step);
context.fillStyle = 'red';
context.fill();
context.closePath();
};
if (temp == 2) {
context.beginPath();
context.rect(r * step, z * step, step, step);
context.fillStyle = 'black';
context.fill();
context.closePath();
};
}
}
var startPosX;
var startPosY;
var endPosX;
var endPosY;
var ownColor;
var otherColor;
function moor(i, j) {
ownColor = 0;
otherColor = 0;
startPosX = (i - 1 < MIN_X) ? i : i - 1;
startPosY = (j - 1 < MIN_Y) ? j : j - 1;
endPosX = (i + 1 > MAX_X) ? i : i + 1;
endPosY = (j + 1 > MAX_Y) ? j : j + 1;
for (var rowNum = startPosX; rowNum <= endPosX; rowNum++) {
for (var colNum = startPosY; colNum <= endPosY; colNum++) {
if (rowNum == i && colNum == j) {} else {
if (population[rowNum][colNum] == 1)
ownColor++;
if (population[rowNum][colNum] == 2)
otherColor++;
}
}
}
if (ownColor == 0) {
return 0;
} else
return otherColor / ownColor;
}
function randomIntFromInterval(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
context.strokeStyle = "#ddd";
context.stroke();
//population[0][0] = 0;
//setTimeout("redrawGrid()", 500);
var rand1;
var rand2;
var temp;
var i;
var j;
for (i = 0; i < 10; i++) {
for (j = 0; j < 10; j++) {
if (moor(i, j) > moor(i + 1, j)) {
temp = population[i][j];
rand1 = randomIntFromInterval(0, 19);
rand2 = randomIntFromInterval(0, 19);
population[i][j] = population[rand1, rand2];
population[rand1][rand2] = temp;
}
}
}
<canvas id="c"></canvas>