Multidimensional Array problems - javascript
I've been trying to fix this for about 3 days now, and I can't seem to find why it doesn't work.
I've got this function, which loads an image, and loads through all the pixels to create a grid of walls for A* pathfinding. I'm using CraftyJS to create this game, maybe it is that?
However, it seems to load perfectly fine, but when I try to use it in my game, it gives me loads of undefined values on most of the tiles. In fact, I feel like it only fills one row, instead of all 45.
This is the function that fills the GRID:
var babyStart = 0, babyNodes = [], grid = new Array(new Array());
function getGridFromImage(img, worldWidth, worldHeight) {
var image = new Image(); //maak een image object
var c = document.getElementById("mapLoader");
var context = c.getContext("2d");
image.src = img; //pak het plaatje erbij
image.onload = function () {
context.drawImage(image, 0, 0);
var data = context.getImageData(0, 0, worldWidth, worldHeight); //Verkrijg de Pixeldata
console.log(data);
var count = 0, tmr = null, length = data.data.length, x = 0, y = 0;
babyNodes = [];
while(count <= length) {
grid[y] = new Array();
//Verkrijg de kleuren DATA
var r = data.data[count]; //Rood channel
var g = data.data[count + 1]; //Groen channel
var b = data.data[count + 2]; //Blauw channel
//console.log(data[0]);
//console.log("Count/length: " + count + "/" + length + ";r: " + r + ";g: " + g + ";b: " + b);
if (r == 0 && g == 0 && b == 0) {
grid[y][x] = 1;
} else {
grid[y][x] = 0;
}
if (b > 0) {
babyNodes[b - 255] = count;
}
if (g == 255) {
babyStart = count;
}
count += 4;
x++;
if (x >= worldWidth) {
y += 1;
x = 0;
}
}
loading = false;
};
};
Sorry the comments are dutch, but I think most of you don't even need these comments anyways :P.
I try to collect the data in another function in another JS file, it looks a little like this:
Crafty.scene("lvlWoonkamer", function () {
Crafty.sprite("images/levels/Woonkamer.png", {
achtergrond: [0,0,1280,720]
});
Crafty.e("2D, DOM, achtergrond").attr({x: 0, y: 0});
console.log("Starting grid count");
for (var i = 0; i < 45; i++) {
var str = "";
for(var ii = 0; ii <= 80; ii++) {
str += grid[i][ii] + ",";
console.log("[" + i + "][" + ii + "]");
}
str += ";";
}
console.log(str);
});
This is the output I receive:
undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,0,undefined,;
Sorry for the bad code blocks and stuff, I have no idea how it works XD (Just pressed ctrl + K and copy paste).
I have no idea why it's doing this, I tried all kinds of things with the multi-dimensional arrays, looked up a lot, copy pasted a lot but it just doesn't seem to work...
(I'm already glad it loads the image tbh XD).
I'm kinda new to JavaScript and HTML5 and all that, so please be easy on me.
Sem Wong.
Edit: So I found out that I was clearing the Array everytime I did grid[y] = new Array();, so I changed it to if (grid[y] == null) grid[y] = new Array();. Now it works partly better, still getting some undefines but I'll get to the bottom of it :).
Edit 2: I fixed it completely and pathfinding is working also (A* OP). Thanks everyone for helping! It was the getGridFromImage function that was failing me, because it constantly cleared my grid[y]. I got a fixed version below for those who had the same problem as I did (Don't think there's anyone as stupid as me , but I guess new developers might have the same issue)
var babyStartX = 0, babyStartY = 0, babyNodes = [], grid = new Array(new Array());
function getGridFromImage(img, worldWidth, worldHeight) {
var image = new Image(); //maak een image object
var context = document.getElementById("mapLoader").getContext("2d");
image.src = img; //pak het plaatje erbij
image.onload = function() {
context.drawImage(image, 0, 0);
var data = context.getImageData(0, 0, worldWidth, worldHeight); //Verkrijg de Pixeldata
console.log(data);
var count = 0, length = data.data.length, x = 0, y = 0;
while(count <= length) {
if (grid[x] == null) grid[x] = new Array();
//Verkrijg de kleuren DATA
var r = data.data[count]; //Rood channel
var g = data.data[count + 1]; //Groen channel
var b = data.data[count + 2]; //Blauw channel
//console.log(data[0]);
//console.log("Count/length: " + count + "/" + length + ";r: " + r + ";g: " + g + ";b: " + b);
if (r == 0 && g == 0 && b == 0) {
grid[x][y] = 1;
} else {
grid[x][y] = 0;
}
if (b > 0 && g == 0 && r == 0) {
babyNodes[b - 254] = [x,y];
}
if (g == 255 && b == 0 && r == 0) {
babyStartX = x;
babyStartY = y;
babyNodes[0] = [x,y];
}
count += 4;
x++;
if (x >= worldWidth) {
y += 1;
x = 0;
}
}
loading = false;
}; };
I am not familiar with Crafty, so sorry if I am wrong, but I suppose Scott Sauyet is right. JavaScript is by default asynchronous, so perhaps you are calling the second function before the first one finished?
There is some background information on callbacks here: http://recurial.com/programming/understanding-callback-functions-in-javascript/
The concept behind callbacks is that you can call a module inside another so they are always ran sequentially.
function build(argument1, argument2) {
// Do things
check;
}
function check() {
// Do things
}
Your case would probably be something like this, but I can't really tell from your code.
function getGridFromImage(img, worldWidth, worldHeight) {
// Rest of your function
check;
}
function check() {
Crafty.scene("lvlWoonkamer", function () {
Crafty.sprite("images/levels/Woonkamer.png", {
achtergrond: [0,0,1280,720]
});
Crafty.e("2D, DOM, achtergrond").attr({x: 0, y: 0});
console.log("Starting grid count");
for (var i = 0; i < 45; i++) {
var str = "";
for(var ii = 0; ii <= 80; ii++) {
str += grid[i][ii] + ",";
console.log("[" + i + "][" + ii + "]");
}
str += ";";
}
console.log(str);
});
}
// Actually start the first function here;
getGridFromImage(img, worldWidth, worldHeight);
Related
Paint bucket getting "Maximum Call Stack Size Exceeded" error
This is the code of the paint bucket tool in my drawing app using the p5.js library. The function self.floodFill always get "Maximum Call Stack Size Exceeded" because of recursion and I want to know the way to fix it. I am thinking if changing the function to a no recursion function would help or not. Any help would be appreciated. function BucketTool(){ var self = this; //set an icon and a name for the object self.icon = "assets/bucket.jpg"; self.name = "Bucket"; var d = pixelDensity(); var oldColor; var searchDirections = [[1,0],[-1,0],[0,1],[0,-1]]; var pixelsToFill = []; var positionArray = new Array(2); self.checkBoundary = function(currentX, currentY, localOldColor) { if (self.getPixelAtXYPosition(currentX,currentY).toString() != localOldColor.toString() || currentX < 0 || currentY < 0 || currentX > width || currentY > height || pixelsToFill.indexOf(currentX+" "+currentY) != -1) { return false; } return true; }; self.floodFill = function(currentX, currentY, localOldColor, localSearchDirections) { if (self.checkBoundary(currentX, currentY, localOldColor)){ pixelsToFill.push(currentX+" "+currentY); } else { return; } for (var i = 0; i < searchDirections.length; i++){ self.floodFill(currentX + searchDirections[i][0], currentY + searchDirections[i][1], localOldColor, localSearchDirections); } }; self.getPixelAtXYPosition = function(x, y) { var colour = []; for (var i = 0; i < d; i++) { for (var j = 0; j < d; j++) { // loop over index = 4 * ((y * d + j) * width * d + (x * d + i)); colour[0] = pixels[index]; colour[1] = pixels[index+1]; colour[2] = pixels[index+2]; colour[3] = pixels[index+3]; } } return colour; } self.drawTheNeededPixels = function(){ for(var i = 0; i < pixelsToFill.length; i++){ positionArray = pixelsToFill[i].split(" "); point(positionArray[0],positionArray[1]); } } self.draw = function () { if(mouseIsPressed){ pixelsToFill = []; loadPixels(); oldColor = self.getPixelAtXYPosition(mouseX, mouseY); self.floodFill(mouseX, mouseY, oldColor, searchDirections); self.drawTheNeededPixels(); } }; }
This problem is well documented on the wikipedia page and the shortfalls of the different types of algorithms to perform flood filling. You've gone for the stack-based recursive implementation. To prevent a stackoverflow — Maximum Call Stack Exceeded — the first step would be to use a data structure. Using queues/stacks rather than having the function call itself. The code below creates an empty stack where we put a new object containing the x and y where the user has chosen to fill. This is then added to the pixelsToFill array. We then loop the stack until it's completely empty, at which point we are ready to display the filled pixels. In the while loop we pop an element off the stack and then find its children — the directions up, down, left, right denoted by the searchDirections array you created. If we've not seen the child before and it's within the boundary we add it to the pixelsToFill array and add it to the stack to repeat the process: self.floodFill = function (currentX, currentY, localOldColor, localSearchDirections) { let stack = []; stack.push({ x: currentX, y: currentY }); pixelsToFill.push(currentX + " " + currentY); while (stack.length > 0) { let current = stack.pop(); for (var i = 0; i < searchDirections.length; i++) { let child = { x: current.x + searchDirections[i][0], y: current.y + searchDirections[i][1], localOldColor, }; if (self.checkBoundary(child.x, child.y, localOldColor)) { pixelsToFill.push(child.x + " " + child.y); stack.push(child); } } } }; This code may stop the stackoverflow but there are still a lot of optimisations that can be made. Once again, it's worth checking out the Wikipedia page and potentially take a look at Span filling. let bucketTool; function setup() { createCanvas(400, 400); bucketTool = new BucketTool(); } function draw() { background(220); strokeWeight(5); circle(width / 2, height / 2, 100); frameRate(1); bucketTool.draw(); } function BucketTool() { var self = this; //set an icon and a name for the object // self.icon = "assets/bucket.jpg"; // self.name = "Bucket"; var d = pixelDensity(); var oldColor; var searchDirections = [ [1, 0], [-1, 0], [0, 1], [0, -1], ]; var pixelsToFill = []; var positionArray = new Array(2); self.checkBoundary = function (currentX, currentY, localOldColor) { if ( self.getPixelAtXYPosition(currentX, currentY).toString() != localOldColor.toString() || currentX < 0 || currentY < 0 || currentX > width || currentY > height || pixelsToFill.indexOf(currentX+" "+currentY) != -1 ) { return false; } return true; }; self.floodFill = function (currentX, currentY, localOldColor, localSearchDirections) { let stack = []; stack.push({ x: currentX, y: currentY }); pixelsToFill.push(currentX + " " + currentY); while (stack.length > 0) { let current = stack.pop(); for (var i = 0; i < searchDirections.length; i++) { let child = { x: current.x + searchDirections[i][0], y: current.y + searchDirections[i][1], localOldColor, }; if (self.checkBoundary(child.x, child.y, localOldColor)) { pixelsToFill.push(child.x + " " + child.y); stack.push(child); } } } }; self.getPixelAtXYPosition = function (x, y) { var colour = []; for (var i = 0; i < d; i++) { for (var j = 0; j < d; j++) { // loop over index = 4 * ((y * d + j) * width * d + (x * d + i)); colour[0] = pixels[index]; colour[1] = pixels[index + 1]; colour[2] = pixels[index + 2]; colour[3] = pixels[index + 3]; } } return colour; }; self.drawTheNeededPixels = function () { for (var i = 0; i < pixelsToFill.length; i++) { positionArray = pixelsToFill[i].split(" "); point(positionArray[0], positionArray[1]); } }; self.draw = function () { if (mouseIsPressed) { pixelsToFill = []; loadPixels(); oldColor = self.getPixelAtXYPosition(mouseX, mouseY); self.floodFill(mouseX, mouseY, oldColor, searchDirections); console.log(pixelsToFill.length); self.drawTheNeededPixels(); } }; } html, body { margin: 0; padding: 0; } canvas { display: block; } <!DOCTYPE html> <html lang="en"> <head> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/addons/p5.sound.min.js"></script> <link rel="stylesheet" type="text/css" href="style.css"> <meta charset="utf-8" /> </head> <body> <main> </main> <script src="sketch.js"></script> </body> </html> Shameless plug, but relevant: I've created a blog comparing the different flood fill algorithms using p5.js.
FabricJS automatically adding new lines to textboxes causes text cursor to move backwards
I have a function that wraps textboxes in FabricJS so that they don't become too wide, (it is automatically line breaking when the the maximum width is reached). However it is causing the text cursor to get pushed behind by 1 character every time it adds a new line. Look at this gif to fully see the problem in play a gif I am using the following function to automatically line break the text box. To give some context, it checks if the length of a textLine exceeds the maxWidth, and if it is the case with the last word included but doesn't exceed if the last word is not included, then it adds a new line by entering \n and somewhere here it causes the problem. function wrapCanvasText(t, canvas, maxW, maxH) { let initialFormatted = t.text if (typeof maxH === "undefined") { maxH = 0; } var words = t.text.split(" ") var formatted = ''; // clear newlines var sansBreaks = t.text.replace(/(\r\n|\n|\r)/gm, ""); // calc line height var lineHeight = new fabric.Text(sansBreaks, { fontFamily: t.fontFamily, fontSize: t.fontSize }).height; // adjust for vertical offset var maxHAdjusted = maxH > 0 ? maxH - lineHeight : 0; var context = canvas.getContext("2d"); context.font = t.fontSize + "px " + t.fontFamily; var currentLine = ""; var breakLineCount = 0; for (var n = 0; n < words.length; n++) { console.log(words[n]) var isNewLine = currentLine == " "; var testOverlap = currentLine + ' ' + words[n] + ' '; // are we over width? var w = context.measureText(testOverlap).width; if (w < maxW) { // if not, keep adding words currentLine += words[n] + ' '; formatted += words[n] += ' '; } else { // if this hits, we got a word that need to be hypenated if (isNewLine) { var wordOverlap = ""; // test word length until its over maxW for (var i = 0; i < words[n].length; ++i) { wordOverlap += words[n].charAt(i); var withHypeh = wordOverlap + "-"; if (context.measureText(withHypeh).width >= maxW) { // add hyphen when splitting a word withHypeh = wordOverlap.substr(0, wordOverlap.length - 2) + "-"; // update current word with remainder words[n] = words[n].substr(wordOverlap.length - 1, words[n].length); formatted += withHypeh; // add hypenated word break; } } } n--; // restart cycle if (words[n+1] !== '') { formatted += '\n'; breakLineCount++; } currentLine = ""; } if (maxHAdjusted > 0 && (breakLineCount * lineHeight) > maxHAdjusted) { // add ... at the end indicating text was cutoff formatted = formatted.substr(0, formatted.length - 3) + "...\n"; break; } } // get rid of empy newline at the end formatted = formatted.substr(0, formatted.length - 1); return formatted; } You can try out this snippet it is an approximate version of what I have, most importantly, it does have the same cursor problem. To try out the problem, edit the text directly in the canvas after initialization. var canvas = new fabric.Canvas('c'); canvas.backgroundColor = "#F5F5F5"; var textArea = document.getElementById('addNote'); function checkForChange() { var activeObject = canvas.getActiveObject(); let formatted1 = wrapCanvasText(activeObject, canvas, 400, 2000); activeObject.text = formatted1; } function wrapCanvasText(t, canvas, maxW, maxH) { let initialFormatted = t.text if (typeof maxH === "undefined") { maxH = 0; } var words = t.text.split(" ") var formatted = ''; // clear newlines var sansBreaks = t.text.replace(/(\r\n|\n|\r)/gm, ""); // calc line height var lineHeight = new fabric.Textbox(sansBreaks, { fontFamily: t.fontFamily, fontSize: t.fontSize }).height; // adjust for vertical offset var maxHAdjusted = maxH > 0 ? maxH - lineHeight : 0; var context = canvas.getContext("2d"); context.font = t.fontSize + "px " + t.fontFamily; var currentLine = ""; var breakLineCount = 0; for (var n = 0; n < words.length; n++) { console.log(words[n]) var isNewLine = currentLine == " "; var testOverlap = currentLine + ' ' + words[n] + ' '; // are we over width? var w = context.measureText(testOverlap).width; if (w < maxW) { // if not, keep adding words currentLine += words[n] + ' '; formatted += words[n] += ' '; } else { // if this hits, we got a word that need to be hypenated if (isNewLine) { var wordOverlap = ""; // test word length until its over maxW for (var i = 0; i < words[n].length; ++i) { wordOverlap += words[n].charAt(i); var withHypeh = wordOverlap + "-"; if (context.measureText(withHypeh).width >= maxW) { // add hyphen when splitting a word withHypeh = wordOverlap.substr(0, wordOverlap.length - 2) + "-"; // update current word with remainder words[n] = words[n].substr(wordOverlap.length - 1, words[n].length); formatted += withHypeh; // add hypenated word break; } } } n--; // restart cycle if (words[n + 1] !== '') { formatted += '\n'; breakLineCount++; } currentLine = ""; } if (maxHAdjusted > 0 && (breakLineCount * lineHeight) > maxHAdjusted) { // add ... at the end indicating text was cutoff formatted = formatted.substr(0, formatted.length - 3) + "...\n"; break; } } // get rid of empy newline at the end formatted = formatted.substr(0, formatted.length - 1); return formatted; } $("#addNote").keyup(function(e) { var activeObject = canvas.getActiveObject(); if (activeObject && activeObject.type == 'textbox') { activeObject.text = textArea.value let formatted1 = wrapCanvasText(activeObject, canvas, 400, 2000); activeObject.text = formatted1; while (activeObject.textLines.length > 1 && canvas.getWidth() * 0.8 >= activeObject.width) { activeObject.set({ width: activeObject.getScaledWidth() + 1 }) } canvas.renderAll(); } else { var textSample = new fabric.Textbox(textArea.value, {}); textSample.left = 0 textSample.splitByGrapheme = true textSample.lockRotation = true textSample.editable = true textSample.perPixelTargetFind = false textSample.hasControls = true textSample.width = canvas.getWidth() * 0.8 textSample.height = canvas.getHeight() * 0.8 textSample.maxWidth = canvas.getWidth() * 0.8 textSample.maxHeight = canvas.getHeight() * 3 canvas.add(textSample); canvas.setActiveObject(textSample); canvas.renderAll(); } canvas.on('text:changed', checkForChange) }); <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.5.0/fabric.min.js"></script> <textarea id="addNote"></textarea> <canvas id="c" width="400" height="400"></canvas>
Processes for optimizing canvas animations
I've got a small web app in development to simulate the Ising model of magnetism. I've found that the animation slows down considerably after a few seconds of running, and it also doesn't loop after 5 seconds like I want it to with the command: setInteval(main, 500) I've added start and stop buttons. When I stop the animation, and then restart it, it begins fresh at the usual speed, but again slows down. My question is: what steps can I take to troubleshoot and optimize the performance of my canvas animation? I hope to reduce or mitigate this slowing effect. JS code: window.onload = function() { var canvas = document.getElementById("theCanvas"); var context = canvas.getContext("2d"); var clength = 100; var temperature = 2.1; var playAnim = true; canvas.width = clength; canvas.height = clength; var imageData = context.createImageData(clength, clength); document.getElementById("stop").addEventListener("click",function(){playAnim=false;}); document.getElementById("start").addEventListener("click",function(){playAnim=true;}); function init2DArray(xlen, ylen, factoryFn) { //generates a 2D array of xlen X ylen, filling each element with values defined by factoryFn, if called. var ret = [] for (var x = 0; x < xlen; x++) { ret[x] = [] for (var y = 0; y < ylen; y++) { ret[x][y] = factoryFn(x, y) } } return ret; } function createImage(array, ilen, jlen) { for (var i = 0; i < ilen; i++) { for (var j = 0; j < jlen; j++) { var pixelIndex = (j * ilen + i) * 4; if (array[i][j] == 1) { imageData.data[pixelIndex] = 0; //r imageData.data[pixelIndex+1] = 0; //g imageData.data[pixelIndex+2] = 0; //b imageData.data[pixelIndex+3] = 255; //alpha (255 is fully visible) //black } else if (array[i][j] == -1) { imageData.data[pixelIndex] = 255; //r imageData.data[pixelIndex+1] = 255; //g imageData.data[pixelIndex+2] = 255; //b imageData.data[pixelIndex+3] = 255; //alpha (255 is fully visible) //white } } } } function dU(i, j, array, length) { var m = length-1; //periodic boundary conditions if (i == 0) { //top row var top = array[m][j]; } else { var top = array[i-1][j]; } if (i == m) { //bottom row var bottom = array[0][j]; } else { var bottom = array[i+1][j]; } if (j == 0) { //first in row (left) var left = array[i][m]; } else { var left = array[i][j-1]; } if (j == m) { //last in row (right) var right = array[i][0]; } else { var right = array[i][j+1] } return 2.0*array[i][j]*(top+bottom+left+right); //local magnetization } function randInt(max) { return Math.floor(Math.random() * Math.floor(max)); } var myArray = init2DArray(clength, clength, function() {var c=[-1,1]; return c[Math.floor(Math.random()*2)]}); //creates a 2D square array populated with -1 and 1 function main(frame) { if (!playAnim){return;} // stops window.requestAnimationFrame(main); createImage(myArray, clength, clength); context.clearRect(0,0,clength,clength); context.beginPath(); context.putImageData(imageData,0,0); for (var z = 0; z < 10*Math.pow(clength,2); z++) { i = randInt(clength-1); j = randInt(clength-1); var deltaU = dU(i, j, myArray, clength); if (deltaU <= 0) { myArray[i][j] = -myArray[i][j]; } else { if (Math.random() < Math.exp(-deltaU/temperature)) { myArray[i][j] = -myArray[i][j]; } } } } var timer = setInterval(main, 500); }
How to count the number of section tags in an article tag?
I have been trying to write code that would use an embedded for loop to calculate the number of sections inside of each article (there is more than one so I can't use getID) in a document. When the button is clicked the code works but the numbers it calculates are completely off which means something isn't counting correctly. Here is my function: <script> function Calculations() { var a = document.getElementsByTagName("article"); var s = 0; var z = 0; var x; for (x = 0; x < a.length; x++) { var cn = a[x].childNodes; z++ for (i = 0; i < cn.length; i++) { if (cn[i].nodeType == 1) { if (cn[i].tagName == "P"); { s++; } } } alert("Article " + z + " has " + s + " section.") s = 0 } alert("There are " + a.length + " total articles.") } </script> Thank you so much for your help!
I'm using raphael.js for a visual interface on my Battleship game. I'm having some problems
I'm using raphael.js as a visual interface of my Battleship game. I have a function called createCanvas() which creates a grid (10x10). That way the user can see where to aim. The problem is, the grid doesn't appear until after the code of the game (putting in coordinates etc) has finished. Anyone know how to solve this? Here's the entire code. Below, the code of createCanvas() and of game(). function createCanvas() { $(function() { var canvas = Raphael(0, 0, 2000, 2000); for(var i = 0; i != (BOARD_WIDTH); i++) { canvas.text((60+70*i), 15, i+1); } for(var i = 0; i != (BOARD_HEIGHT); i++) { canvas.text(15, (60+70*i), i+1); } for(var i = 0; i != (BOARD_WIDTH+1); i++) { canvas.path( "M" + (25+(70*i)) + ",25 L" + (25 + (70*i)) + ",725" ); } for(var i = 0; i != (BOARD_HEIGHT+1); i++) { canvas.path( "M25," + (25+(70*i)) + " L725," + (25+(70*i)) ); } }); } function game(){ inputArray = [4,3,2]; var boats = randomBoats(inputArray); var currentBoat = 0; var sunkenBoat = 0; var numberOfTurns = 0; while(sunkenBoat !== inputArray.length ) { var hit= false; var target = "(" + prompt("Enter targetcoordinate (x,y)") + ")"; var targetString = target.replace(/\s+/g, ''); for(var i = 0; i !== inputArray.length; i++) { for(var j = 0; j !== boats[i].usedPositions().length; j++) { console.log(targetString) if(targetString === boats[i].usedPositions()[j].toString()) { hit = true; boats[i].hits[j] = 1; console.log(boats[i].hits); currentBoat = boats[i]; fillSquare(targetString, "red"); break; } } } console.log(currentBoat.hits); console.log(allEquals(currentBoat.hits, 1)); if(hit) alert ("Hit!"); else { fillSquare(targetString, "blue"); alert ("Miss!"); } if(allEquals(currentBoat.hits, 1)) { alert("Boat with length " + currentBoat.hits.length + " has sunken!"); sunkenBoat++; } numberOfTurns++ } alert("You've won! You did it in " + numberOfTurns + " turns.") } In my code I call createCanvas(); game(); so I would think the canvas is drawn first...
The issue is the While loop. You're not giving anything else a chance to get in and do anything. This will just keep going around and around as fast as possible until you're done. You should take a stab at putting a Input box on the page and and detecting key events looking for the enter key with something like this. document.onkeypress = function(evt) { evt = evt || window.event; var charCode = evt.keyCode || evt.which; var charStr = String.fromCharCode(charCode); alert(charStr); }; That way the animations and other stuff your're going to need later can run without being blocked, you don't burn CPU cycles like crazy, and you only check for a hit when the user has actually entered a value Then you will maybe even write some code display "Hit" or "Miss" on canvas (may be animated) and that way you can remove all the alert and message boxes that keep popping up.