So I have an array (of length 1 for the moment) in Javascript. It contains an Image object for the moment. Basically, I made an animation that works perfectly with this code :
ants[0]._x = 5;
ants[0]._y = 5;
and then, in my updating function :
function animate() {
context.drawImage(ants[0], 0, 0, 158, 160, ants[0]._x, ants[0]._y, 158, 160);
ants[0]._x += 5;
ants[0]._y += 5;
}
The problem is, when I change _x and _y to x and y (like so :
ants[0].x = 5;
ants[0].y = 5;
and everywhere else in the code)
The animation won't work. Moreover, x and y equal to 0 even if I initialized them to 5.
So my question is, is it because my images are Images objects and to add new attributes to a built-in object, you have to add underscores ?
An Image object already has it's own readonly x and y properties. These correspond to the image width and height. Edit: actually corresponds to the position on the page If you're trying to set arbitrary values in your image, you need to create new variables. Previously you were doing this with the underscore character (_x), but you can do it with other characters too
For example:
ants[0].myProperty = 'stackoverflow';
console.log(ants[0].myProperty); // will print 'stackoverflow
You can view all the properties contained in an object with
var ants = new Image;
for (var p in ants) {
console.log(p);
}
MDN has more information on the Image element
There is nothing stopping you from assigning x and y under regular circumstances (ie: if you're using home-made objects, and not built-in language/browser objects).
When you start playing with reserved properties of protected objects, there are all kinds of weird things that can happen, from a browser letting you break the page completely until you refresh, or a browser letting you try for hours to change the definition of window.
It all comes down to how you assign them, how you use them after, whether you're swapping objects out of your array...
...and it's an Image object, so you need to make sure that the image is actually loaded before you can do much with it.
There's really nothing stopping you from doing things like:
var my_character = {
x : 0,
y : 0,
width : 32,
height : 64,
sprite_sheet : loadedImage,
current_frame : 6,
update : function () {
my_character.current_frame += 1;
my_character.x += 3;
my_character.y -= 2;
}
};
context.drawImage(
my_character.sprite_sheet,
x - my_character.width/2,
y - my_character.height/2,
my_character.width,
my_character.height,
my_character.width * current_frame,
0,
my_character.width,
my_character.height
);
That's not a particularly elegant way of doing it, but seriously, if you wanted to then add a my_character.$ = "35.99";, you could.
It's something more than "x" and "y".
If you wanted to use something like my_character.° = 32.5; I believe you'd have to use my_character["°"] = 32.5;
Yes, there's a convention, called Custom Data Attributes. Attributes that begin with data- are reserved for the application, they're guaranteed never to affect the semantics of the elements in the browser.
ant[0].setAttribute("data-x", 5);
ant[0].setAttribute("data-y", 5);
See the official W3C documentation and this blog post by John Resig summarizing it.
Related
Based on the matterjs demo I also created a set of bodies that live within an area. Just like in the demo the area is defined by four static bodies that together define a box.
When wildly moving bodies with the box they somehow seem to escape by going through the walls. Is there a way to prevent this escaping form happening? Maybe an alternative way to define the box?
This is actually a problem with all of these of collision detection algorithms.
What I ended up doing was adding code that knows about the box's boundaries and checks every 300 msecs if any of the bodies is outside of it. If so it uses Matter.Body.translate to put them back into the box again.
Notice that this code does not use the game loop but rather events for its check mechanism execution trigger. It would be nicer to do this using the matterjs game loop (run the retrieval every so many ticks), but I did not realise that at the time.
This is the code I ended up using (in my case the box is as big as the canvas itself):
/* `allBodies` is a variable that contains all the bodies that can
* escape. Use something like `Composite.allBodies(world)` to get
* them all but beware to not include the box's borders which are
* also bodies.
* `startCoordinates` is an object that contains the x and y
* coordinate of the place on the canvas where we should move escaped
* bodies to.
*/
function initEscapedBodiesRetrieval(allBodies, startCoordinates) {
function hasBodyEscaped(body) {
var x = body.position.x;
var y = body.position.y;
return x < 0 || x > _canvasWidth || y < 0 || y > _canvasHeight;
}
setInterval(function() {
var i, body;
for (i = 0; i < allBodies.length; i++) {
body = allBodies[i];
if (hasBodyEscaped(body)) {
Matter.Body.translate(body, { x: (startCoordinates.x - body.position.x), y: (startCoordinates.y - body.position.y) });
}
}
}, 300); /* We do this every 300 msecs */
}
I am trying to initialise an array of Image() objects, with each having a different x position. However all the objects in the array seems to end up with the same x position. I have tried searching for a solution and it seems that it is related to 'closure' however I am not sure how to fix it.
This is my code:
function initPieces(){
for (var i = 0; i<8; i++) {
var piece = new Image();
piece.x = 5 + i*50;
piece.y = 5;
piece.src = "images/piece.png";
piecesArray.push(piece);
alert(i + ", " + piecesArray[i].x);
}
}
I have even tried initialising the piecesArray without a loop by manually declaring a new Image() and setting the x position manually for each of the 8 pieces. However it gives me the same problem.
Anyone's help finding a solution will be greatly appreciated.
I couldn't find a definitive reference for the HTMLImageElement.x and HTMLImageElement.y properties (because that's what you are creating with new Image()), but MDN says they are read-only and experimental, not to be used in production code.
And they are indeed read-only: in a quick test I did they could be set, but reading the value afterwards simply produces 0.
If you want to move the elements around in the page after they have been inserted into the DOM, use standard techniques such as manipulating piece.style.top.
You have not yet added those Images to the DOM and so the x, y, offsetLeft, and offsetTop properties have no context (default to zer0).
Either add image to the DOM first before manipulating those, or use a different property:
var piecesArray = [];
function initPieces(){
for (var i = 0; i<8; i++) {
var piece = new Image();
piece.tempX = (i*50 + 5); // temporary place holder for X
piece.y= 5; // this will not work; allows set, but does not change value
piece.src = "images/piece.png";
piecesArray.push(piece);
alert(i + ": " + piecesArray[i].tempX);
}
}
initPieces();
See a demo Fiddle here: http://jsfiddle.net/87xff3fy/1/
A reference for Image.x: http://help.dottoro.com/ljkvjhbq.php (don't use it! Use style or a temporary variable that will set the style.top and style.left at render-time)
I'm trying to make a game in JavaScript using OOP and html5 canvas.
I can not move on with the game beacuse I'm stuck in one place.
My question is how can I change the value of method xPosition that is returning a value from a function.
Below you find some code.
var myObject = {
//placing object in start position
xPosition : function(){
return Canvas.width / 2;
},
//if keycode pressed move myObject to the left
move : function(){
xPosition -= 10; //I know this wont work
}
};
You can't change the return values without changing (ie. overwriting) the xPosition method itself.
However, you can easily get a value and then change that:
… move: function(){
var xval = this.xPosition();
xval -= 10; // this works, reassigning to the "xval" variable (xval=xval-10)
// or in one step:
var xval = this.xPosition() - 10;
}
Or you change the input value of the function. Let it compute the current position from canvas size and a relative position stored in a variable (or easier: in a property) and then change only that variable/property from the move function:
var myObject = {
// placing object in start position
xPos: 0,
getXPosition: function() { // compute value from canvas and position
return Canvas.width / 2 + this.xPos; // or something similar
},
move : function() {
// change relative position
this.xPos -= 10;
}
};
You need to reference the correct scope of the object. The this keyword will reference the myObject scope.
You are also calling a function so need to add the brackets.
Your other issue is that you are calling a function and trying to update the value. You either need to assign xPosition as a variable or pass in the new value.
move : function(){
this.xPosition(-10);
}
Have a look at these articles in structuring javascript
Part 1
Part 2
Part 3
Part 4
If you are dealing with x,y positions and as you say you are making a game, I would use vectors to manage your game objects. The vecotr library will handle all the maths for you. Adding, subtracting, multiplying etc.
There are a lot of vector libraries out there or you can build your own.
Vector Maths
consider this code:
var deSaturated = deSaturate(greyscaleCtx.getImageData(0, 0, canvasWidth, canvasHeight));
imageData comes from getImageData canvas function.
function deSaturate (imageData) {
var theData = imageData.data;
var dataLength = theData.length;
var i = dataLength-1;
var lightLevel;
// Iterate through each pixel, desaturating it
while ( i >= 0) {
// To find the desaturated value, average the brightness of the red, green, and blue values
theData[i] = theData[i+1] = theData[i+2] = (theData[i] + theData[i + 1] + theData[i + 2]) / 3;
// Fully opaque
theData[i+3] = 255;
// returning an average intensity of all pixels. Used for calibrating sensitivity based on room light level.
lightLevel += theData[i]; //combining the light level in the samefunction
i -= 4;
}
imageData.data = theData; //bring back theData into imageData.data - do I really need this?
var r = [lightLevel/dataLength,imageData]
return r;
}
during the writing and optimizing of this code I found out I don't really understand how js is treating for example "theData" variable. is working with it just a short way to reference imageData.data in which case I don't need the following code in the end:
imageData.data = theData
but then do I pay in degraded performance ( a lot of DOM I/O)?
or is doing theData = imageData.data actually copying the original array (represented as Uint8ClampedArray) and then I have to reassign the modified data to imageData.data.
I guess this is basic javascript, but I found contradictory code examples in MDN and other developer resources and I would really like to understand this properly.
thanks for the help!
Just ran a quick test:
var idata = ctx.getImageData(0,0,300,300);
var data = idata.data;
for(var i=0;i<data.length;i++){
data[i]=0;
}
ctx.putImageData(idata,0,0);
And that properly blanks out part of the screen as expected. However without putImageData nothing will happen. So changing the data object, whether stored in a different variable or not, will be reflected in that imageData object. However this will not affect the canvas until putImageData has been called.
So, yes, you can remove that final assignment and it will work as desired.
However I will warn that it is not a valid assumption that it is a Uint8ClampedArray. Yes, that is how Chrome handles it (last I checked), and it is indeed what the official specification uses. However some browsers have no notion of Uint8ClampedArray, while still supporting canvas through the now deprecated CanvasPixelArray.
So all you are guaranteed to get is something with the some array-like interface. I had to learn this the hard way when I tried to cache interesting features of image data by creating a new Uint8ClampedArray, which failed in some browsers.
See: https://developer.mozilla.org/en-US/docs/DOM/CanvasPixelArray
In javascript, assigning either an array or an object just assigns a reference to that array or object - it does not make a copy of the data. A copy is only made if you physically create a new array and copy the data over or call some function that is designed to do that for you.
So, if imageData.data is an array, then assigning it to theData just makes a shortcut for referring to the same data. It does not make a new copy of the data. Thus, after modifying the data pointed to by theData, you don't have to assign it back to imageData.data because there is only one copy of the data and both theData and imageData.data point already point to that same copy of the data.
So, in direct answer to your question, this line is unnecessary:
imageData.data = theData;
I am currently trying to create a sudoku grid in javascript, to do this I need to set up a loop so one line re-appears 10 times with a gap of 20 pixels between each one. So far I have:
var canvas;
canvas = openGraphics();
var x;
var y;
var gap;
x = 20;
y = 20;
gap = 25;
canvas.drawLine(20, 20, 20, 245);
canvas.paint();
How would you recommend to do this?
As you already stated, you have to use a looping construct.
The Mozilla Developer Network has good documentation on these.
But honestly, I think you should rather read their JavaScript Guide before trying to write a Game, otherwise you'll end up bumping into a ton of dead ends and you will soon loose the interest in making the game at all.
Also, please stay on MDN when searching looking JavaScript help, since there are a lot of sites on the Internet that have bad, old, broken code example and help.
Especially stay away from w3schools.
There are various looping constructs available to programmers, the 2 most common ones are the for loop and the while loop.
The for loop is good for "looping" a number of times and the while loop is for looping while some value is "true".
In this case, you know the number of lines that you need to draw so the for loop is best matched
This is example code for the for loop. What happens is that the code between the { and } is run multiple time. Each time the loop runs, variable i gets larger by 1, starting from 0. This continues until the condition i<numberTimesToLoop becomes false.
for(var i=0;i<numberTimesToLoop;i++)
{
document.write("i = " + i);
document.write("<br />");
}
Not that I want to do your assignment for you, but in a lot of cases its easier to learn from seeing actual code. (I demonstrate and I find plenty of students who on seeing an answer can immediately recognise it in the future. Of course I give them the theory first and if it doesn't click I try this method...)
This modification to your current code will draw your vertical lines.
var canvas;
canvas = openGraphics();
var x;
var y;
var gap;
x = 20;
y = 20;
gap = 25;
var currentX = 20;
for(var i=0;i<10;i++)
{
canvas.drawLine(currentX, 20, currentX, 245);
currentX = currentX + gap;
}
canvas.paint();
(Not really sure what the problem with the w3schools website is)