Related
In the image A-L is the longest path, but L-M is the heaviest
The heaviest path of the graph is the path with the most edges connected to it, for this current case the heaviest path is L-M with 19 edges: L-K, K-J, J-I, I-H, H-G, G-F, F-E, F-M, M-N, M-O, M-P, M-Q, M-R, M-S, M-T, M-U, M-V, M-W, M-X.
I am trying to create a program that will check that the inputted matrix represents a tree graph, and if it does, that returns the number of edges on the heaviest path of the graph. In other words it will return the M(d) of the graph.
For this current case the output will be the number of edges connected to L-M path which is 19.
But I can not find a way to do that. Here I created a function to find the row with the least 1s to set it as a root, but don't know how to proceed.
let matrix = [
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
//find row with least 1s
function findRowWithLeastOnes(matrix_data) {
let counter = 0;
let row = 0;
for (let i = 0; i < matrix_data.length; i++) {
for (let j = 0; j < matrix_data[i].length; j++) {
if (matrix_data[i][j] === 1) {
counter++;
}
}
if (counter < matrix_data.length) {
row = i;
console.log(row);
return row;
}
}
}
findRowWithLeastOnes(matrix);
We can use the following algorithm:
Turn the matrix into an adjacency list so to avoid scanning zeroes all the time, and to have easy access to the degree of a node, which contributes to the weight.
Choose any node to start with (e.g. 0) and find the heaviest path from it. We can use a depth-first search for that (for instance, using recursion). From all paths that are found, keep the heaviest. To avoid an edge being traversed back and forth, remember what the previous node was in the traversal: it should not be revisited. If there was a previous node, we should avoid counting the traversed edge twice in the sum of weights.
Take the last node in that path: this is the node that is the furthest away from our starting node in terms of weight. This node will be an end-point of the heaviest path we are looking for.
Use the same algorithm a second time to find the heaviest path from that node. This is the path we need.
If your question is also about determining whether a graph is a tree, you would essentially need to check there are no cycles (a depth first traversal can be used again) and that from one node all others can be reached (again depth first can serve). Maybe you'd also want to check that the graph is undirected, i.e. that the matrix is mirrored along the main diagonal.
function isUndirected(matrix) {
if (matrix.length !== matrix[0]?.length) return false; // must be square
for (let i = 0; i < matrix.length; i++) {
for (let j = i; j < matrix.length; j++) {
if (matrix[i][j] !== matrix[j][i]) return false;
}
}
return true;
}
function isTree(matrix) {
const visited = Array(matrix.length).fill(false);
function dfs(node, previous=-1) {
if (visited[node]) return false; // cycle
visited[node] = true;
const neighbors = matrix[node];
for (let neighbor = 0; neighbor < neighbors.length; neighbor++) {
if (neighbor != previous && neighbors[neighbor] && !dfs(neighbor, node)) return false;
}
return true;
}
// When no cycles were found and all nodes were reachable from node 0 => tree!
return dfs(0) && !visited.includes(false);
}
function findHeaviestPathFrom(adj, node, previous=-1) {
const neighbors = adj[node];
let heaviest = {
nodes: [],
weight: 0
};
for (let neighbor of neighbors) {
if (neighbor != previous) {
const path = findHeaviestPathFrom(adj, neighbor, node);
if (path.weight > heaviest.weight) heaviest = path;
}
}
heaviest.nodes.push(node);
heaviest.weight += neighbors.length - (previous !== -1)
return heaviest;
}
function findHeaviestPath(matrix) {
// Turn the matrix into an adjacency list
let adj = matrix.map(row => row.map((isEdge, i) => isEdge ? i : -1).filter(i => i > -1));
// Find the node that has the heaviest connection to node 0
let remote = findHeaviestPathFrom(adj, 0).nodes[0];
// Find heaviest path starting in that node
return findHeaviestPathFrom(adj, remote);
}
const matrix = [
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
];
if (!isUndirected(matrix)) console.log("The graph is directed");
else if (!isTree(matrix)) console.log("The graph is not a tree");
else console.log("Heaviest path: ", JSON.stringify(findHeaviestPath(matrix)));
function generator(x, y) {
matrix[x][y] = 1;
var arr = [1,2,3,4]; //randomizes the generator
arr = shuffle(arr);
for (i = 0; i < 4; i++) {
if (arr[i] === 1 && matrix[x - 1] && matrix[x - 1][y] === 0) {
generator(x - 1, y);
}
if (arr[i] === 2 && matrix[x + 1] && matrix[x + 1][y] === 0) {
generator(x + 1, y);
}
if (arr[i] === 3 && matrix[x][y - 1] === 0) {
generator(x, y - 1);
}
if (arr[i] === 4 && matrix[x][y + 1] === 0) {
generator(x, y + 1);
}
}
return 0;
}
The results are bad. After execution most of the time on a 3x3 matrix gives back a 0 in the right or left corner up or even a row of zeroes.
As the matrix grows in size it is even worse.
Here is the result for a 15x15 matrix:
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[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, 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, 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]
The matrix is initialized using this code
for (var i = 0; i < h; i++) {
matrix[i] = [];
for (var j = 0; j < w; j++) {
matrix[i][j] = 0;
}
}
And the first call is generate(0,0);
I was trying to do the 6th day of AdventOfCode.com, when I stumbled upon an annoying problem, that I don't know the cause of. I
var input = ["turn on 7,6 through 9,6","turn on 1,3 through 6,9"];
var grid = 0;
function Create2Darray(dimension) {
var arr = [0];
var arr2 = [0];
for (i=0; i<dimension; i++) {
arr2[i] = 0;
}
for (k=0; k<dimension; k++) {
arr[k] = arr2;
}
return arr;
}
grid = Create2Darray(10);
const p = grid; // THIS IS WHAT IT IS ALL ABOUT
temp = grid[4];
temp[5] = 3;
grid[4] = temp;
p; // outputs [[0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0]] to console.
// Although we said: const p = grid;
// And at that time, grid was equal to [[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, 3, 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]]
Secondly
this:
temp = grid[4];
temp[5] = 3;
grid[4] = temp;
What I expected was 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, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 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]]
but I got:
[[0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0]]
What am I doing wrong?
so the core questions:
Why did CONSTANT p change?
Why did ALL the "sub-arrays" within the main arrays change while I only selected the 5th value in the 4th "sub-array"?
About reference/copy
Javascript works "by reference", not "by copy" like C++. This means that after:
var a = [1, 2, 3];
var b = [a, a];
b is an array containing two references to the same array a, not two copies of a. For example after
b[0][0] = 99;
also b[1][0] will be 99 because b[0] and b[1] are references to the very same object.
If you want to build a matrix you need to build each row separately... for example:
var grid = [];
for (var i=0; i<100; i++) {
grid.push(new Array(100));
}
// Now grid is a matrix of 100x100 undefined elements
About const
Declaring a const reference to an array doesn't prevent the array content from being modified, you're only prevented from reassigning grid to reference something else.
A quick way to create a copy of an array is to use slice(0), for example instead of
for (k=0; k<dimension; k++) {
arr[k] = arr2;
}
you could have
for (k=0; k<dimension; k++) {
arr[k] = arr2.slice(0);
}
and then the code works as expected: every row of 2D array has the same content but the rows can be modified independently. See also: What's the point of .slice(0) here?
I'm making a simple platformer game using canvas, my problem is that I can't seem to clear the canvas while using an array to create the level.
If I use ctx.clearRect(0, 0, canvas.width, canvas.height); the player can then move correctly and the path behind it is cleared, but the canvas goes completely white. What is the best way to redraw my level from my array?
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
/* Game Variables and Constants */
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// level colors
var color = {
darkBlue: '#2c3e50',
blue: '#2980b9',
green: '#1abc9c'
}
// add level colors to array
var colors = [color.darkBlue, color.blue, color.green];
// Level Plan
var levelArray = [
[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, 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, 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, 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, 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, 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, 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, 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, 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],
[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, 1, 1, 1, 1, 0, 0, 0, 0, 1, 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, 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, 1, 1, 1],
[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, 1, 1, 1, 1, 1]
];
// Images/Tiles for level
var sky = new Image();
var floor = new Image();
sky.src = "Tiles/bg-tile.png";
floor.src = "Tiles/floor-tile.png";
var levelPosX = 0;
var levelPosY = 0;
// Player Object
var player = {
width: 20,
height: 20,
posX: 5,
posY: canvas.height - 40,
speed: 5,
velX: 0,
velY: 0
}
// empty keys array to store value of pressed keys
var keys = [];
// Update Function - player controls etc
function update() {
// move right
if(keys[39]) {
player.velX++;
}
player.posX += player.velX;
}
function drawLevel() {
// take values from levelArray and assign them colors to canvas
for(var i = 0; i < levelArray.length; i++) {
for(var j = 0; j < levelArray[i].length; j++) {
if(levelArray[i][j] == 0) {
ctx.drawImage(sky, levelPosX, levelPosY, 20, 20);
}
if(levelArray[i][j] == 1) {
ctx.drawImage(floor, levelPosX, levelPosY, 20, 20);
}
levelPosX += 20;
}
levelPosX = 0;
levelPosY += 20;
}
}
function render() {
draw();
requestAnimationFrame(render);
}
// Draw Function - draw the level, player
function draw() {
update();
drawLevel();
// Draw the player
ctx.fillStyle = color.green;
ctx.fillRect(player.posX, player.posY, player.width, player.height);
}
// Event listeners - stores the value of whatever key was pressed in the keys array
document.body.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
});
window.addEventListener("load", function(){
render();
});
The purpose of ctx.clearRect is to remove all content from the canvas--probably leaving you with the white background of the webpage showing through the now fully transparent & empty canvas.
You cannot "move" anything you've drawn on the canvas.
Instead canvas animates content by erasing the canvas and redraw everything in its new position. That's the way canvas works...
Draw all content (background & players),
Give the user time to view the content,
Clear the canvas,
Update the positions of the new content,
Redraw all the new content in their new positions,
Repeat, repeat, repeat...
I think the best way to do this with performance is by creating another superposed canvas below the first with the same dimensions and drawing on it only the background so that when you refresh the top one, we see the background.
Though I have been able to create and use animations for small demos in the past using the CreateJS library, i'm currently stumped in trying to understand why Nothing is displaying to the canvas even though I have verified that my animation tiles are all being added. I'm going senile from stepping through the debugger and seeing everything work properly, but getting a completely blank page on reloads.
Any ideas are much appreciated!
var stage, loader;
function tick() {
stage.update();
}
function generateMap(rekeyed_array, spriteSheet, row_length, col_length, tilesize) {
for (var x = 0; x < col_length; x++) {
for (var y = 0; y < row_length; y++) {
// z is a onedimentional value mapped from x and y iterators
spriteInstance = new createjs.Sprite(spriteSheet, rekeyed_array[z]);
var z = x * row_length + y;
spriteInstance.x = tilesize * x;
spriteInstance.y = tilesize * y;
spriteInstance.gotoAndPlay(rekeyed_array[z]);
spriteInstance = spriteInstance.clone();
stage.addChild(spriteInstance);
}
}
console.groupEnd();
stage.update();
}
//Replace Tiled's map data numbers with the actual Game Object's Names
function rekeyTiledMapData(spritemappings, array_to_reindex, rows, cols) {
var reindexedArray = new Array();
for (var y = 0; y < cols; y++) {
for (var x = 0; x < rows; x++) {
// z is a onedimentional value mapped from x and y iterators
var z = y * rows + x;
var currentItem = array_to_reindex[z];
if (typeof spritemappings[currentItem] === "string") {
reindexedArray.push(spritemappings[currentItem]);
} else {
reindexedArray.push(currentItem);
}
}
}
return reindexedArray;
}
function getSpriteData(loadedimg) {
var data = {
framerate: 60,
images: [loadedimg],
frames: [
/*middlearth*/
[592, 654, 70, 70, 0, 0, 0],
/*water*/
[562, 434, 70, 70, 0, 0, 0],
/*doormid*/
[146, 290, 70, 70, 0, 0, 0],
/*doortop*/
[218, 290, 70, 70, 0, 0, 0],
/*grass*/
[736, 362, 70, 70, 0, 0, 0]
],
animations: {
"sand": {
frames: 0,
next: "sand",
speed: 1
},
"water": {
frames: 1,
next: "water",
speed: 1
},
"doormid": [2, 2, "doormid", 1],
"doortop": [3, 3, "doortop", 1],
"grass": [4, 4, "grass", 1],
}
};
return data;
}
var mapdata = [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, 11, 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, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 7, 7, 7, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5];
var spritemappings = {
'0': "water",
'8': "water",
'7': "water",
'5': "sand",
'6': "grass",
'10': "doortop",
'11': "doormid"
};
function loadLevel(event) {
var tileimage = loader.getResult("tiles");
levelanimations = rekeyTiledMapData(spritemappings, mapdata, 16, 10);
var spritesheet = new createjs.SpriteSheet(getSpriteData(tileimage));
generateMap(levelanimations, spritesheet, 16, 10, 70);
}
function init() {
stage = new createjs.Stage("gameCanvas");
createjs.Ticker.on("tick", tick);
createjs.Ticker.setFPS(60);
loader = new createjs.LoadQueue(false);
loader.addEventListener("complete", loadLevel)
loader.loadManifest({
id: "tiles",
src: "assets/images/level_tiles.png"
});
}
init();
</script>
</head>
<body>
<canvas id="gameCanvas" width="1600" height="900"></canvas>
</body>
If that script is a copy and paste, the script in the head is executed before the body is being created. Thats why you are seeing that it is executing correctly, but nothing is actually happening.
I would copy and paste the script tag in the header down below the canvas element.