Practicing 2D Arrays - javascript

I'm writing a script that will generate a square room within a larger map. The code looks like this:
var mapSize = 10;
var map = [];
for (var x = 0; x < mapSize; x++) {
map[x] = [];
for (var y = 0; y < mapSize; y++) {
map[x][y] = 0
};
};
//Make square room within map
var roomSize = 3;
var roomType = "Kitchen"
var paintRoom = function(mapX, mapY) {
for (var j = 0; j < roomSize; j++) {
map[mapX + j][mapY] = roomType;
map[mapX][mapY + j] = roomType;
};
};
paintRoom(3, 4);
console.log(map);
The result that I want is this:
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, "Kitchen", "Kitchen", "Kitchen", 0, 0, 0],
[0, 0, 0, 0, "Kitchen", "Kitchen", "Kitchen", 0, 0, 0],
[0, 0, 0, 0, "Kitchen", "Kitchen", "Kitchen", 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
But instead I end up with this:
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, "Kitchen", "Kitchen", "Kitchen", 0, 0, 0],
[0, 0, 0, 0, "Kitchen", 0, 0, 0, 0, 0],
[0, 0, 0, 0, "Kitchen", 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
What am I missing here? I'm just starting out, and would like to figure out as much as possible on my own, so if anyone could give me a hint instead of answering outright, I would really appreciate it.

It is doing what you've asked, if you follow the code carefully. It just needs an extra loop. Since what you're doing is 2 dimensional then you'll need 2 loops as well...
var paintRoom = function(mapX, mapY) {
for (var x = 0; x < roomSize; x++) {
for (var y = 0; y < roomSize; y++) {
map[mapX + x][mapY + y] = roomType;
}
};
};

you a missing 1 loop:
var mapSize = 10;
var map = [];
for (var x = 0; x < mapSize; x++) {
map[x] = [];
for (var y = 0; y < mapSize; y++) {
map[x][y] = 0
};
};
//Make square room within map
var roomSize = 3;
var roomType = "Kitchen"
var paintRoom = function(mapX, mapY) {
for (var j = 0; j < roomSize; j++) {
for (var k = 0; k < roomSize; k++) {
map[mapX + j][mapY + k] = roomType;
}
};
};
paintRoom(3, 4);
console.log(map);
https://jsfiddle.net/nfnpesmd/

Related

Why fillText doesn't show up in canvas?

Tried changing the fillStyle color to many different ones, also different positions but nothing. No errors in console either. I already have tileset and sprites drawn on the canvas, does that has anything to do with it? I just need to print out a simple text on every character move on key press.
Here is the code:
function move(e) {
if (e.keyCode == 39) {
boatPosX += 5;
view.x -= 5
moveCount++;
context.fillStyle = "red";
context.fillText(theArray[0].question, 0, 0);
console.log(theArray[0].question);
}
The rest of the code:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var view = {x: 0, y: 0};
var questionsArray = [];
var moveCount = 0;
var mapArray = [
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 2, 2, 0],
[0, 0, 1, 1, 1, 0, 0, 2, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 2, 2, 0],
[0, 0, 1, 1, 1, 0, 0, 2, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
];
function isPositionWall(ptX, ptY) {
var gridX = Math.floor(ptX / 36)
var gridY = Math.floor(ptY / 36)
if(gridX < 0 || gridX >= mapArray[0].length)
return true;
if(gridY < 0 || gridY >= mapArray.length)
return true;
return mapArray[gridX][gridY];
}
var theArray = [];
var Question = function(question, answer1, answer2, correctAnswer) {
this.question = question;
this.answer1 = answer1;
this.answer2 = answer2;
this.correctAnswer = correctAnswer;
this.addToArray = function(){
theArray.push(this);
};
this.addToArray();
}
Question.prototype.checkAnswer = function() {
return answer1 || answer2 == correctAnswer;
}
var question1 = new Question("Taip ar ne?", "Taip", "Ne", "Taip");
var question2 = new Question("Jo ar ne?", "Ne", "Jo", "Jo");
var question3 = new Question("Aha ar ne?", "Aha", "Ne", "Ne");
var question4 = new Question("Ja ar ne?", "Taip", "Ne", "Taip");
var question5 = new Question("Jojo ar ne?", "Taip", "Ne", "Taip");
var question6 = new Question("Taip ar ne?", "Taip", "Ne", "Taip");
var question7 = new Question("Taip ar ne?", "Taip", "Ne", "Taip");
var StyleSheet = function(image, width, height, x, y) {
this.image = image;
this.width = width;
this.height = height;
this.x = x;
this.y = y
this.draw = function(image, sx, sy, swidth, sheight, x, y, width, height) {
context.drawImage(image, sx, sy, swidth, sheight, x, y, width, height);
};
this.drawimage = function(image, x, y, width, height) {
context.drawImage(image, x, y, width, height);
};
};
/* Initial Sprite Position */
var boatPosX = canvas.height/2 - 50;
var boatPosY = canvas.height/2 - 50;
function render(viewport) {
context.save();
context.translate(view.x, view.y);
requestAnimationFrame(render);
var oldPosX = boatPosX;
var oldPosY = boatPosY;
for (let i = 0; i < mapArray.length; i++) {
for (let j = 0; j < mapArray[i].length; j++) {
if (mapArray[i][j] == 0) {
this.sprite.draw(
background,
190,
230,
26,
26,
i * this.sprite.width,
j * this.sprite.height,
this.sprite.width,
this.sprite.height
);
}
if (mapArray[i][j] == 1) {
this.sprite.draw(
background,
30,
30,
26,
26,
i * this.sprite.width,
j * this.sprite.height,
this.sprite.width,
this.sprite.height
);
}
if (mapArray[i][j] == 2) {
this.sprite.draw(
background,
200,
20,
26,
26,
i * this.sprite.width,
j * this.sprite.height,
this.sprite.width,
this.sprite.height
);
}
}
}
this.ship.drawimage(boat, boatPosX, boatPosY, 50, 50);
//console.log(boatPosX + ship.width)
if(isPositionWall(boatPosX, boatPosY)) {
boatPosX = oldPosY;
console.log("collision");
}
context.restore();
};
function move(e) {
if (e.keyCode == 39) {
boatPosX += 5;
//canvas.width += 2;
view.x -= 5
moveCount++;
console.log(moveCount);
console.log("right");
context.fillStyle = "red";
context.fillText(theArray[0].question, 0, 0);
console.log(theArray[0].question);
}
if (e.keyCode == 37) {
boatPosX -= 5;
view.x += 5
moveCount++;
console.log(moveCount);
console.log("left");
}
if (e.keyCode == 38) {
boatPosY -= 5;
view.Y += 5
moveCount++;
console.log(moveCount);
console.log("up");
}
if (e.keyCode == 40) {
boatPosY += 5;
view.Y += 5
moveCount++;
console.log(moveCount);
console.log("down");
}
}
document.onkeydown = move;
var background = new Image();
background.src = "ground.png";
var sprite = new StyleSheet(background, 36, 36, 16, 16);
var boat = new Image();
boat.src = "ship.png";
var ship = new StyleSheet(boat, 90, 100, 16, 16);
console.log(Math.floor(boatPosX / 36));
console.log(mapArray[Math.floor(boatPosX / 36)]);
render();
Seems to be because you are trying to put the text at 0,0. By default the text will be drawn above the Y position of 0 (so off the top of the canvas which is why you don't see anything). If you made it 0,10 or 0,20 then you will probably see some text.
It is possible to change the text base line like this, so at 0,0 you will see something..
context.textBaseline = "top";

How to check canvas element (pixel matrix) contains another canvas element inside

I have 2 matrix, which are the result of several arrays of pixels from 2 images.
I need to detect when the canvas element of matrix 2 is inside or steps on the edge of element 1 (rectangle of matrix 1), at this moment it must notify the user "match detected!"
My code to create matrix 1 and 2:
var matrix = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
];
var matrix2 = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 1, 1, 1, 0, 0, 0],
[1, 1, 0, 1, 0, 0, 0, 1, 0, 0],
[1, 0, 0, 1, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 1, 0, 0],
[0, 0, 0, 1, 0, 0, 1, 1, 1, 0],
[0, 0, 0, 1, 0, 0, 0, 1, 1, 0],
[0, 0, 0, 1, 1, 0, 0, 1, 1, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
];
var contFilas = matrix.length;
var contColumnas = matrix[0].length;
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
var sz = 20;
var regions = [];
var regionCollection = [];
canvas.width = sz * contColumnas;
canvas.height = sz * contColumnas;
ctx.fillStyle = "silver";
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (var y = 0; y < contFilas; y++) {
var regionline = [];
regions.push(regionline);
for (var x = 0; x < contColumnas; x++) {
var pixelRegion = 0;
regionline[x] = 0;
if (matrix[y][x] === 1) {
// check previous row
if (y) {
if (matrix[y - 1][x]) {
pixelRegion = regions[y - 1][x];
} else if (x && matrix[y - 1][x - 1]) {
pixelRegion = regions[y - 1][x - 1];
} else if (x + 1 < contColumnas && matrix[y - 1][x + 1]) {
pixelRegion = regions[y - 1][x + 1];
}
}
// check current row
if (x && matrix[y][x - 1]) {
pixelRegion = regions[y][x - 1];
}
// if not connected, start a new region
if (!pixelRegion) {
regionCollection.push([]);
pixelRegion = regionCollection.length;
}
// remember region
regionline[x] = pixelRegion;
regionCollection[pixelRegion - 1].push([x, y]);
// paint it
ctx.fillStyle = "black";
ctx.fillRect(x * sz + 1, y * sz + 1, sz - 2, sz - 2);
}
ctx.fillStyle = "white";
ctx.fillText(pixelRegion, x * sz + 8, y * sz + 13);
}
}
document.querySelector("#result").innerHTML = JSON.stringify(regionCollection);
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>getUserMedia</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
</head>
<body>
<canvas></canvas>
<div id="result"></div>
<div id="result2"></div>
</body>
</html>
How can I do this? detect when there is an element inside or touching rectangle 1 (matrix)?

requestanimationframe drawing with for loop issue

I'm working on a tetris game - still - and am trying to use requestAnimationFrame to draw my T piece on the black board.
This is the problem. the requestAnimationFrame draws the piece 2 times, then stops drawing even though the for loop is still running. That is, after two times, I only see the black background. When I comment out the black background the piece shows up/animates just fine.
I really am at a loss why this is happening.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
const T = [
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 1, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]
],
]
var piece = T[0];
const player = {
position: {x: 5, y: -1},
piece: piece,
}
function colorPiece(piece, offset) {
for(y = 0; y < piece.length; y++) {
for(x = 0; x < piece.length; x++) {
if (piece[y][x] !== 0) {
ctx.fillStyle = "red";
ctx.fillRect(x + offset.x, y + offset.y, 1, 1);
}
}
}
}
function drawCanvas() {
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.scale(20, 20);
colorPiece(player.piece, player.position);
}
function update() {
drawCanvas();
requestAnimationFrame(update);
}
update();
OK - working version, with a fiddle here. A number of changes. The biggest are:
Don't use canvas.scale(), since it's cumulative per this (see "More Examples"). Instead, use 20*x and 20*y for blocks 20x20.
Edit Based on a further test, it looks like this was the most significant change.
Rename so that piece is not used as all of a variable, a field name in player, and a parameter of colorPiece
Move the ctx creation into update() (now called doUpdate()) per this fiddle example. Pass ctx as a parameter to other functions.
Move the red fillStyle assignment out of the loop, since you only need to do it once, and then you can draw all the rectangles without changing it.
In the loops:
for(var y = 0; y < thePiece.length; ++y) {
for(var x = 0; x < thePiece[y].length; ++x) { ... } }
Keep x and y in the local scope, using var.
When you are ready to go across a row, that's thePiece[y].length, i.e., the length of the row. Using thePiece.length there would have broken for non-square elements of T.
Added a <p id="log"/> and a javascript framenum so that I could see that doUpdate() was indeed being called.
If you haven't already, make sure to open the console while you're testing so you can see error messages. If drawCanvas causes an error, it will prevent requestAnimationFrame from being called again. I think that's why the fiddle I linked above calls requestAnimationFrame at the beginning rather than the end of the frame-draw function.
Hope this helps!
Code
const T = [
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 1, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]
],
]
const player = {
position: {x: 5, y: -1},
piece: T[0]
}
function colorPiece(ctx, thePiece, offset) {
ctx.fillStyle = "red";
for(var y = 0; y < thePiece.length; ++y) {
for(var x = 0; x < thePiece[y].length; ++x) {
if (thePiece[y][x] !== 0) {
ctx.fillRect(20*(x + offset.x), 20*(y + offset.y), 20, 20);
}
}
}
}
function drawCanvas(ctx) {
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, canvas.width, canvas.height);
colorPiece(ctx, player.piece, player.position);
}
var framenum=0;
function doUpdate(timestamp) {
document.getElementById("log").innerHTML = framenum.toString();
++framenum;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
drawCanvas(ctx);
window.requestAnimationFrame(doUpdate);
}
doUpdate();

Calculate percentage from an array

I'm trying to fill a jqPlot Chart with percentage values for a stacked bar chart. I get the data via mysql and COUNT. For example, if I have 4 categories and 12 months, I am able to produce:
var s1 = [0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s2 = [0, 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, ];
var s3 = [0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s4 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, ];
Which produces a stacked bar chart with numbers, every number of each variable is a months value.
Now I want to show a stacked bar chart where the values of each month are percentages. I must somehow be able to make a percentage calculation with the values of the array. For example: add all values from position two (February) (100/(2+5+3+3)) and then multiply with positon two.
I am nowhere near a solution.
EDIT: Well, thanks for the fast answers.
I will try to explain better. I get the data from the 'MySQL' query, then to a PHP array, then convert it to a string to paste it to the JavaScript for plotting:
Try a for loop to calculate the percent you wanted to get and put it inside an array again
$(document).ready(function(){
var s1 = [0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s2 = [0, 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, ];
var s3 = [0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s4 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, ];
var s5 = new Array();
for (var i = 0; i < s1.length; i++){
//Or use your own formula on getting the value you wanted.
s5.push(100/(s1[i]+s2[i]+s3[i]+s4[i]);
}
// Can specify a custom tick Array.
// Ticks should match up one for each y value (category) in the series.
var ticks = ['January','February','March','April','May','June','July','August','September','October','November','December'];
var plot1 = $.jqplot('chart1', [s1, s2, s3, s4, s5], {
// The "seriesDefaults" option is an options object that will
// be applied to all series in the chart.
seriesDefaults:{
renderer:$.jqplot.BarRenderer,
rendererOptions: {fillToZero: true}
},
// Custom labels for the series are specified with the "label"
// option on the series option. Here a series option object
// is specified for each series.
series:[
{label:'Hotel'},
{label:'Event Regristration'},
{label:'Airfare'}
],
// Show the legend and put it outside the grid, but inside the
// plot container, shrinking the grid to accomodate the legend.
// A value of "outside" would not shrink the grid and allow
// the legend to overflow the container.
legend: {
show: true,
placement: 'outsideGrid'
},
axes: {
// Use a category axis on the x axis and use our custom ticks.
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks
},
// Pad the y axis just a little so bars can get close to, but
// not touch, the grid boundaries. 1.2 is the default padding.
yaxis: {
pad: 1.05,
tickOptions: {formatString: '$%d'}
}
}
});
});
<script>
/* are there to be more than 4 arrays? */
var s1 = [0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s2 = [0, 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, ];
var s3 = [0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s4 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, ];
/* add new arrays to this array */
var arrs=[s1,s2,s3,s4];
var pc=[];
for( var i=0; i < arrs[0].length; i++ ){
var a=0;
for( var j=0; j < arrs.length; j++ ){
if( !isNaN( arrs[ j ][ i ] ) ) a+=arrs[ j ][ i ];
}
console.log( 'i=%d, j=%d, a=%d', i, j, a );
/* confused by the `then multiply with positon two` */
pc.push( a > 0 ? Math.round( 100 / a ) : 0 );
}
alert( pc );
</script>
If I understood correctly, it will work in your case :
function getPercent(array){
var return_array = [];
var total_sum = 0; // total sum of data
for(var i = 0; i < array.length; i++){
total_sum += array[i].reduce(function(pv, cv) { return pv + cv; }, 0);
}
for( var i=0; i < array[0].length; i++ ){
var sum = 0; // month sum
for( var j=0; j < array.length; j++ ){
sum += array[j][i];
}
return_array[i] = sum*100/total_sum; // percent calculation of the month
}
return return_array;
}
var s1 = [0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s2 = [0, 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, ];
var s3 = [0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s4 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, ];
var data=[s1,s2,s3,s4];
var percent = getPercent(data);
console.log(percent);
And results are :
[0, 61.904761904761905, 4.761904761904762, 4.761904761904762, 19.047619047619047, 9.523809523809524, 0, 0, 0, 0, 0, 0]

HTML5 Canvas drawImage only draws after second refresh

OK, I have a HTML5 canvas... and it draws images from .png tiles (32x32). It works. Sort of. It only draws on the canvas after the second refresh. For example, if you were to load it up... al you would see is a red canvas (the background for #canvas is red) then if you were to refresh it... it would be successfully draw the images... why is that?
Here is the code. (All you need is two images. t0.png and t1.png in line_tiles folder) But I am sure you can spot the error right away that I can't :P
game.js
// HTML5 JS Tile Example
var canvas, context, board, imageObj, tiles;
var currentMap = 1;
var upMap = 0;
var rightMap = 0;
var leftMap = 0;
var downMap = 3;
var NUM_OF_TILES = 1; // starting from ZERO
// Set return 2D array of map
function loadMap(map) {
if (map == 1) {
return [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]];
}
}
// On load...
window.onload = function () {
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
imageObj = new Image();
tiles = [];
board = loadMap(1);
canvas.width = 512;
canvas.height = 352;
// 2. SET UP THE MAP TILES
for (x = 0; x <= NUM_OF_TILES; x++) {
imageObj = new Image(); // new instance for each image
imageObj.src = "line_tile/t" + x + ".png";
tiles.push(imageObj);
}
var theX;
var theY;
// 3. DRAW MAP BY ROWS AND COLS
for (x = 0; x <= 10; x++) {
for (y = 0; y <= 15; y++) {
theX = x * 32;
theY = y * 32;
context.drawImage(tiles[board[x][y]], theY, theX, 32, 32);
}
}
};
index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>HTML5</title>
<script type="text/javascript" src="game.js"></script>
<style type="text/css">
<!--
#canvas {
background:red;
z-index:0;
position:relative;
}
.container {
width: 512px;
position: relative;
}
-->
</style>
</head>
<body>
<div class="container">
<canvas id="canvas"></canvas>
</div>
</body>
</html>
You need to add onload hooks on your images (the tiles) and draw only when all images are loaded.
Here's a suggestion :
// HTML5 JS Tile Example
var canvas, context, board, imageObj, tiles;
var currentMap = 1;
var upMap = 0;
var rightMap = 0;
var leftMap = 0;
var downMap = 3;
var NUM_OF_TILES = 1; // starting from ZERO
// Set return 2D array of map
function loadMap(map) {
if (map == 1) {
return [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]];
}
}
// On load...
window.onload = function () {
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
imageObj = new Image();
tiles = [];
board = loadMap(1);
canvas.width = 512;
canvas.height = 352;
var draw = function() {
var theX;
var theY;
// 3. DRAW MAP BY ROWS AND COLS
for (x = 0; x <= 10; x++) {
for (y = 0; y <= 15; y++) {
theX = x * 32;
theY = y * 32;
context.drawImage(tiles[board[x][y]], theY, theX, 32, 32);
}
}
}
var loadedImagesCount = 0;
// 2. SET UP THE MAP TILES
for (x = 0; x <= NUM_OF_TILES; x++) {
var imageObj = new Image(); // new instance for each image
imageObj.src = "line_tile/t" + x + ".png";
imageObj.onload = function() {
loadedImagesCount++;
if (loadedImagesCount==NUM_OF_TILES) draw();
};
tiles.push(imageObj);
}
};
And be careful not to forget the var keyword (look at the loop).

Categories

Resources