Can this 2 dimensional array work? - javascript

so far ive got:
var Items = new Array(5); // this array contains the items
BodyPaint = new Array(1, 0, 1, 0, 0, 0, 0, 0, 0); // this array gives stats for the item
WolfFur = new Array(3, 0, 1, 0, 0, 0, 0, 0, 0); // ^^
BearFur = new Array(4, 0, 1, 0, 0, 0, 0, 0, 0); // ^^
WolfSkin = new Array(6, 0, 0, 0, 0, 0, 0, 0, 0); // ^^
BearSkin = new Array(7, 1, 0, 0, 0, 0, 0, 0, 0); // ^^
would this array work? im relatively new to programing and my friend suggested this is how i should do it, but i looked around and everywhere else recommends a more complex way of doing it that might make sense were they to explain it.
if this array would work please tell me how i would access values in the second array
so far to access the 1st stat for wolf fur ive got this:
var example = Items.2.1
would this (^^) work?
and if it wouldnt work, please tell me how to do it using the above names in the example and explaining why you do everything you do and what it does.
thx.
Im now using an object, ive got:
var Items = {
BodyPaint : new Array(1, 0, 1, 0, 0, 0, 0, 0, 0),
FurCloak : new Array(3, 0, 1, 0, 0, 0, 0, 0, 0),
WolfSkin : new Array(5, 0, 0, 0, 0, 0, 0, 0, 0)};
there are more arrays but i ended it here to save space
i get the following errors:
Unknown identifier: BodyPaint
Unknown identifier: FurCloak
Unknown identifier: WolfSkin
and for all of my other arrays
if i replace a name with a number the error goes but it cant be good for the code and i dont really want my items to be refered to as numbers here, i wont b able 2 know which is which

No. It's that's not how you get values from an array.
Items[2][1] would work if your array were something like this;
var BodyPaint = new Array(1, 0, 1, 0, 0, 0, 0, 0, 0); // this array gives stats for the item
var WolfFur = new Array(3, 0, 1, 0, 0, 0, 0, 0, 0); // ^^
var BearFur = new Array(4, 0, 1, 0, 0, 0, 0, 0, 0); // ^^
var WolfSkin = new Array(6, 0, 0, 0, 0, 0, 0, 0, 0); // ^^
var BearSkin = new Array(7, 1, 0, 0, 0, 0, 0, 0, 0); // ^^
Items = [BodyPaint, WolfFur, BearFur, WolfSkin, BearSkin];
Items[2][1] would return 0.
Edit: You might be interested in using an object too.
var Items = {
BodyPaint: new Array(1, 0, 1, 0, 0, 0, 0, 0, 0),
WolfFur: new Array(3, 0, 1, 0, 0, 0, 0, 0, 0),
BearFur: new Array(4, 0, 1, 0, 0, 0, 0, 0, 0),
WolfSkin: new Array(6, 0, 0, 0, 0, 0, 0, 0, 0),
BearSkin: new Array(7, 1, 0, 0, 0, 0, 0, 0, 0)
}
This would allow you to write some code like this:
Items.BearFur[1] would return 0 and is the same as Items[2][1] above.

You only have multiple 1D arrays, you should combine them into 2D, like :
var Items = new Array
BodyPaint = new Array(1, 0, 1, 0, 0, 0, 0, 0, 0);
WolfFur = new Array(3, 0, 1, 0, 0, 0, 0, 0, 0);
BearFur = new Array(4, 0, 1, 0, 0, 0, 0, 0, 0);
WolfSkin = new Array(6, 0, 0, 0, 0, 0, 0, 0, 0);
BearSkin = new Array(7, 1, 0, 0, 0, 0, 0, 0, 0);
Items[0] = BodyPaint;
alert(Items[0][2]);
In that case you have 2D, and with the alert example you can access the items

It would not work because you aren't linking Items in any way to any of the other arrays. You would have to write:
var BodyPaint = new Array(1, 0, 1, 0, 0, 0, 0, 0, 0);
var WolfFur = new Array(3, 0, 1, 0, 0, 0, 0, 0, 0);
var BearFur = new Array(4, 0, 1, 0, 0, 0, 0, 0, 0);
var WolfSkin = new Array(6, 0, 0, 0, 0, 0, 0, 0, 0);
var BearSkin = new Array(7, 1, 0, 0, 0, 0, 0, 0, 0);
var Items = new Array(BodyPaint, WolfFur, BearFur, WolfSkin, BearSkin);
Then this would work:
var example = Items[2][1];
I would recommend that you use a JavaScript Object instead of arrays. In JSON, this would be:
var Items = {
BodyPaint : Array(1, 0, 1, 0, 0, 0, 0, 0, 0),
WolfFur : new Array(3, 0, 1, 0, 0, 0, 0, 0, 0),
BearFur : new Array(4, 0, 1, 0, 0, 0, 0, 0, 0),
WolfSkin : new Array(6, 0, 0, 0, 0, 0, 0, 0, 0),
BearSkin : new Array(7, 1, 0, 0, 0, 0, 0, 0, 0)};
You can then add new items like this:
Items.AnotherItem = new Array(8, 0, 0, 0, 0, 0, 0, 0, 0);
Or:
Items['AnotherItem'] = new Array(8, 0, 0, 0, 0, 0, 0, 0, 0);
And get a property like:
var example = Items.WolfSkin[5];
JavaScript Objects are very flexible an I recommend you take some time to really get to know them.

Related

Running into Uncaught TypeError: Cannot read property of undefined

I have an algorithm that will modify a 10x10 2D array for a BattleShip game to randomly place ships down in a random direction.
The board looks like this:
var board= [
[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], // 2
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 3
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 4
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 5
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 6
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 7
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 8
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] // 9
];
The algorithm will turn the 0's into 1's and place a random ship at a random index, and at a random direction. The array is like this: var array = [5, 4, 3, 3, 2] (The numbers represent the length e.g. five 1's, four 1's, etc.) The algorithm works good most times and will run until the array is empty.
The problem is, I keep occasionally running into Uncaught TypeError: Cannot read property of <some integer> undefined ONLY when trying to place the ship in either the UP or DOWN direction as it reaches out of bounds. The error occurs for the if statements that check if the direction chosen is out of bounds like so:
// check out of bounds for UP direction
if (x - 1 < 0 || array[x - i][y] == undefined) {
break;
}
// check out of bounds for DOWN direction
if (x + 1 > 9 || array[x + i][y] == undefined) {
break;
}
I believe the error is occurring with something to do with the negative index from trying to perform array[x - i][y] and array[x + i][y]. I thought I already fixed this by adding my additional OR check with x - 1 < 0 and x + 1 > 9 but still I am running into this exception.
Per the comments, the problem is there is no bounds checking on array[x + i] and array[x - i]. Because of that, the calls to array[x +/- i][y] result in a cannot read property ... of undefined error.

HTML5 Canvas - How to get adjacent pixels position from the linearized imagedata Uint8ClampedArray?

A 5 by 5 pixel image data is something like this in linearized imagedata array-
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 0, 0, 0, 255, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
So, the 3x3 pixel data is- 0 0 0 255. How can I get the adjacent pixel positions? Left and right adjacent ones are easy, just minus 4 and plus 4 respectively.
Accessing pixel data
The pixel data from .getImageData().data is a TypedArray of type Uint8ClampedArray. When reading the values they will be in the range 0-255 and in the order Red, Green, Blue, Alpha. If the value of alpha is zero then red, green, and blue will also be zero.
To get the index of a pixel
const imageData = ctx.getImageData(0,0,ctx.canvas.width, ctx.canvas.height);
var index = (x + y * imageData.width) * 4;
const red = imageData.data[index];
const green = imageData.data[index + 1];
const blue = imageData.data[index + 2];
const alpha = imageData.data[index + 3];
To move down one pixel
index += imageData.width * 4;
To move up one
index -= imageData.width * 4;
To move left.
index -= 4;
To move right
index += 4;
If you are on the left or right edge and you move in the direction of the edge you will wrap around, on the line above and to the right if moving left and the line below and on the left if moving down.
When setting the image data the values will be floored and clamped to 0-255
imageData.data[index] = 29.5
console.log(imageData.data[index]); // 29
imageData.data[index] = -283
console.log(imageData.data[index]); // 0
imageData.data[index] = 283
console.log(imageData.data[index]); // 255
If you set an index that is outside the array size it will be ignored
imageData.data[-100] = 255;
console.log(imageData.data[-100]); // Undefined
imageData.data[imageData.data.length + 4] = 255;
console.log(imageData.data[imageData.data.length + 4]); // Undefined
You can speed up access and processing by using different array types. For example all of a pixel's channels as one value using Uint32Array
const imageData = ctx.getImageData(0,0,ctx.canvas.width, ctx.canvas.height);
const pixels = new Uint32Array(imageData.data.buffer);
var index32 = x + y * imageData.width; // note there is no 4*;
const pixel = pixels[index32];
The channels are stored in bits 31-24 Alpha, 23-16 Blue, 15-8 Green, 7-0 Red.
You can set a pixel using a hex value
pixels[x + y * imageData.width] = 0xFF0000FF; // red
pixels[x + y * imageData.width] = 0xFF00FF00; // Green
pixels[x + y * imageData.width] = 0xFFFF0000; // Blue
pixels[x + y * imageData.width] = 0xFF000000; // Black
pixels[x + y * imageData.width] = 0xFFFFFFFF; // White
pixels[x + y * imageData.width] = 0; // Transparent
You can set all the pixels in a single call
pixels.fill(0xFF000000); // all pixels black
You can copy array data onto the array with
// set 3 pixels in a row at x,y Red, Yellow, White
pixels.set([0xFF0000FF,0xFF00FFFF,0xFFFFFFFF], x+y * imageData.width);
Warning
If the canvas has any pixel/s that are from an untrusted source it will be tainted and you will not be able to read the pixel data. Trusted sources are same domain or images served with the appropriate CORS header information. Images that are on the file system can not have their pixels accessed. Once a canvas is tainted it can not be cleaned.
A tainted canvas will throw an error when you call ctx.getImageData(0,0,1,1,) MDN does not list this exception for some reason. You will see "SecurityError" DOMException; in the DevTools console and there are plenty of answered question here in StackOverflow on the subject.
You could calculate the index with the width of the matrix and the length of one unit of 4.
The access is zero based.
function getPos(array, x, y, width) {
var p = 4 * (x + y * width);
return array.slice(p, p + 4);
}
var array = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 240, 0, 0, 0, 255, 0, 0, 0, 240, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
];
// element above
console.log(JSON.stringify(getPos(array, 2, 1, 5))); // [0, 0, 0, 240]
// actual element
console.log(JSON.stringify(getPos(array, 2, 2, 5))); // [0, 0, 0, 255]
// element below
console.log(JSON.stringify(getPos(array, 2, 3, 5))); // [0, 0, 0, 241]

Setting three.js projection matrix direction

I read following codes writing for webgl, and I want rewrite it using three.js. But I could not find any way to do so, please help me.
pMatrix = mat4.create();
mat4.perspective(pMatrix,1.01,gl.drawingBufferWidth/gl.drawingBufferHeight, 10.0, 300000.0);
var eciMat = [1, 0, 0, 0,
0, 0, -1, 0,
0, 1, 0, 0,
0, 0, 0, 1
];
mat4.mul(pMatrix, pMatrix, eciMat );
Matrix classes are pretty sophisticated in Three.js, look at the docs here: http://threejs.org/docs/#Reference/Math/Matrix4
Here's how I would write it in Three.js
// Arguments are fov, aspect, near, far
var perspectiveMatrix = new THREE.Matrix4().makePerspective(30, 1, 0.01, 20);
var eciMatrix = new THREE.Matrix4();
eciMatrix.set(1, 0, 0, 0,
0, 0, -1, 0,
0, 1, 0, 0,
0, 0, 0, 1);
var resultMatrix = new THREE.Matrix4();
resultMatrix.multiply(eciMatrix);
resultMatrix.multiply(perspectiveMatrix);
resultMatrix.multiply(perspectiveMatrix);
console.log(resultMatrix);

Get rotateY() of element as variable with javascript

For an ajax animation on my website I need to check if an element has a full transform to
transform: rotateY(-90deg)
I found this code on the internet to check an elements css value
function getStyle(oElm, strCssRule){
var strValue = "";
if(document.defaultView && document.defaultView.getComputedStyle){
strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
}
else if(oElm.currentStyle){
strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
return p1.toUpperCase();
});
strValue = oElm.currentStyle[strCssRule];
}
return strValue;
}
usage:
getStyle(document.getElementById('to-transform'), "transform")
this will return a matrix3d, which can be different in many browsers like 'internet explorer' and also be different in other versions like IE7 and IE8:
matrix3d(0.00000000000000006123233995736766, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0.00000000000000006123233995736766, 0, 0, 0, 0, 1) safari
matrix3d(0.00000000000000006123233995736766, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0.00000000000000006123233995736766, 0, 0, 0, 0, 1) chrome
matrix3d(0.00000000000000006123233995736766, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0.00000000000000006123233995736766, 0, 0, 0, 0, 1) opera
matrix3d(0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 1) firefox
is there an easier way to check if an element has a rotateY(-90deg)? So the code can finish the last part of the animation
Note: it must be javascript because I haven't included jQuery

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