I have a Javascript question, that might be obvious, but I just can't seem to find the solution for it, and I don't know how to solve it.
(Also, I'm still pretty new to coding)
So I'm writing a patrol function for squares in my game, and for now I started out with just making the square move one way. Later on I will make it patrol back and forth. That's why I put the move function in the draw function.
I want the move function to be reusable for several squares, but I can't seem to make a general move function work. However, I can make a move function specifically for a certain square, work.
Can anyone tell me why this works:
var square = 16;
var posX = 32;
var posY = 32;
function moveSquare() {
for (i = 0; i < 10; i++) {
posX++;
}
}
function draw() {
var redSquare = { x: posX, y: posY, w: square, h: square, color: "red" };
ctx.fillStyle = redSquare.color;
rect(redSquare.x,redSquare.y,redSquare.w,redSquare.h);
moveSquare();
}
And this doesn't:
var square = 16;
var posX = 32;
var posY = 32;
function move(pos) {
for (i = 0; i < 10; i++) {
pos++;
}
}
function draw() {
var redSquare = { x: posX, y: posY, w: square, h: square, color: "red" };
ctx.fillStyle = redSquare.color;
rect(redSquare.x,redSquare.y,redSquare.w,redSquare.h);
move(posX);
}
By the way, I defined the rect function elsewhere, but I figured it wasn't important to include.
Hope you can help
The value passed to the function move is being passed by value, not by reference.
So the pos inside move is private to the move function.
The pos variable will be a copy of posX, so no matter what you do to it in the move function, the global posX will not be affected.
Consider the code:
var x = 5;
function move(x)
{
x++;
console.log("In function x is: " + x);
}
console.log("Outside function, before call x is: " + x);
move(x);
console.log("Outside function, after call x is: " + x);
This outputs:
"Outside function, before call x is: 5"
"In function x is: 6"
"Outside function, after call x is: 5"
The function move has it's own private copy x.
Look into pass by reference, pass by value and variable scope.
Related
I'm trying to make a basic 2d game with p5js and p5.play. An issue that seems to cause issues every time I try to do anything is the keyIsDown function. Is there a way to determine if a key is down before pressing it? If I used
upKey = keyIsDown(UP_ARROW);
upKey will show as undefined until I press the up arrow. Is there any way to assign the respective boolean values to these types of things prior to pressing them?
As of now, my game will not properly work until I have pressed every involed key one time.
The keyIsDown() function checks if the key is currently down, i.e. pressed. It can be used if you have an object that moves, and you want several keys to be able to affect its behaviour simultaneously, such as moving a sprite diagonally.
Note that the arrow keys will also cause pages to scroll so you may want to use other keys for your game.. but if you want to use arrow keys this is the code snippet from the reference page
let x = 100;
let y = 100;
function setup() {
createCanvas(512, 512);
}
function draw() {
if (keyIsDown(LEFT_ARROW)) {
x -= 5;
}
if (keyIsDown(RIGHT_ARROW)) {
x += 5;
}
if (keyIsDown(UP_ARROW)) {
y -= 5;
}
if (keyIsDown(DOWN_ARROW)) {
y += 5;
}
clear();
fill(255, 0, 0);
ellipse(x, y, 50, 50);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
To implement similar logic without the use of arrow keys you will need to determine the key code of the keys you want to use.
Here is an example that uses awsd keys and also logs out the key code of the currently pressed key.
let x = 50;
let y = 50;
function setup() {
createCanvas(512, 512);
}
function keyPressed(){
console.log(keyCode);
}
function draw() {
if (keyIsDown(65)) {
x -= 5;
if (x < 0) x = 0;
}
if (keyIsDown(68)) {
x += 5;
if (x > width) x = width;
}
if (keyIsDown(87)) {
y -= 5;
if (y < 0) y = 0;
}
if (keyIsDown(83)) {
y += 5;
if ( y > height) y = height;
}
clear();
fill(255, 0, 0);
ellipse(x, y, 50, 50);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 4 years ago.
I'm fairly new to JavaScript though I do have some programming experience with Python.
My problem is, that I do not seem understand the concept of namespace in JS since it appears to be different than in Python. This is my code:
function snake(x, y) {
// x and y coordinate of square (topleft)
this.x = x;
this.y = y;
// reference to div object 'box2'
this.boxid = "#box";
this.box = document.getElementById(this.boxid);
// attempts to move the box by args
this.move = function (speedx, speedy) {
var m = 50;
// check if the box is within the container, moves if true
if ((this.x+(speedx*m))<=150 && (this.y+(speedy*m))<=150 &&
(this.y+(speedy*m))>=0 && (this.x+(speedx*m))>=0) {
this.x = this.x + speedx*m;
this.y = this.y + speedy*m;
}
}
// called every frame to update position of the box
this.update = function () {
$(this.boxid).css({top: this.y, left: this.x});
}
}
var snakeObj = new snake(100, 100);
var t = setInterval(s.update, 100);
When hitting one of the four arrow keys, the move() function is being executed with the correct parameters.
Now the way code is shown up there, JS tells me that the x and y values in the update() function are "undefined". But as soon as I change them from this.x and this.y to snakeObj.x and snakeObj.y, as well as this.boxid to "#box", everything works perfectly.
I would like to understand why the update() function can't "access" the values from the object while the move() function is perfectly fine with it.
Just for clarification, the working code looks like this:
function snake(x, y) {
// x and y coordinate of square (topleft)
this.x = x;
this.y = y;
// reference to div object 'box2'
this.boxid = "#box";
this.box = document.getElementById(this.boxid);
// attempts to move the box by args
this.move = function (speedx, speedy) {
var m = 50;
// check if the box is within the container, moves if true
if ((this.x+(speedx*m))<=150 && (this.y+(speedy*m))<=150 &&
(this.y+(speedy*m))>=0 && (this.x+(speedx*m))>=0) {
this.x = this.x + speedx*m;
this.y = this.y + speedy*m;
}
}
// called every frame to update position of the box
this.update = function () {
$("#box).css({top: snakeObj.y, left: snakeObj.x});
}
}
var snakeObj = new snake(100, 100);
var t = setInterval(s.update, 100);
It's because you've got another this value; the one for the inside function.
In JavaScript, every function gets its own this value. Functions are bound at call-time, which means that if you don't call them via the attribute access they're called without the correct this value. A common workaround is to set var that = this; in your object's constructor so you can use the original value via closure from a function defined in the constructor.
Another workaround, if you don't mind dropping support for IE11, is to use an ES6 arrow function like so:
function snake(x, y) {
// x and y coordinate of square (topleft)
this.x = x;
this.y = y;
// reference to div object 'box2'
this.boxid = "#box";
this.box = document.getElementById(this.boxid);
// attempts to move the box by args
this.move = (speedx, speedy) => (function (speedx, speedy) {
var m = 50;
// check if the box is within the container, moves if true
if ((this.x+(speedx*m))<=150 && (this.y+(speedy*m))<=150 &&
(this.y+(speedy*m))>=0 && (this.x+(speedx*m))>=0) {
this.x = this.x + speedx*m;
this.y = this.y + speedy*m;
}
}).call(this, speedx, speedy);
// called every frame to update position of the box
this.update = () => $("#box").css({top: this.y, left: this.x});
}
var snakeObj = new snake(100, 100);
var t = setInterval(s.update, 100);
as the title said i'm trying to animate on a java canvas but i'm not sure how to add on to the vector class of my objects current position
I've been told to use this:
Bus.prototype.update = function()
{
this.getPosition().add(new Vector(10.0));
}
but it doesn't recognize the .add function and comes up with an error when i use my setInterval function
I'll include my get/set functions aswell just incase
Bus.prototype.getPosition = function() {
return this.mPosition;
};
Bus.prototype.setPosition = function (pPosition) {
this.mPosition = pPosition;
};
I'm pretty new at coding so i apologize if this is very vague or badly written
jsFiddle : https://jsfiddle.net/CanvasCode/41z9o10p/1/
javascript
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var Bear = function(xSet, ySet)
{
this.XPos = xSet;
this.YPos = ySet;
}
Bear.prototype.updatePosition = function(xValue, yValue)
{
this.XPos += xValue;
this.YPos += yValue;
}
var bear = new Bear(0,0);
setInterval( function()
{
ctx.fillStyle = "#000";
ctx.fillRect(0,0,c.width,c.height);
ctx.fillStyle = "#0F0";
ctx.fillRect(bear.XPos, bear.YPos, 50,50);
bear.updatePosition(0.2, 0.4);
} ,1);
Bear is a custom "class". All bear has is a X position and a Y position, the constructor can take in two values which will set the X and Y value. I then add a new method to Bear which is called updatePosition. All updatePosition does it take in two values and add them to the original X position and Y position (you can also provide negative numbers to move the opposite way). Now with our Bear we can create one and then use its updatePosition function and move it.
I am trying to draw a line in a canvas. I am trying to make the line moving with time. I am using the following code to do so
var ctx = mycanvas.getContext('2d');
ctx.beginPath();
for (var x = 0; x < 200; x++) {
setInterval(draw(x, 0, ctx), 3000);
x = x++;
}
And here is the draw function
function draw(x, y, ctx) {
ctx.moveTo(10 + x, 400);
ctx.lineTo(11 + x, 400);
ctx.lineWidth = 10;
ctx.strokeStyle = "#ff0000";
ctx.stroke();
}
But the setInterval() function is not working and the line is being drawn instantly. Its not waiting for 3s to proceed to next pixel.
Am I making a mistake?
setInterval needs a function as the first parameter. Right now you are just calling draw(x,0,ctx) and it returns undefined. So your code is equivalent to setTimeout(undefined, 3000).
Instead you need to provide a callable function and invoke draw from it. Try this:
setInterval(function() {
draw(x, 0, ctx);
}, 3000);
Another problem is due to typical closure in loop behavior. You will need to create separate scope to be able to work with individual values of x:
for (var x = 0; x < 200; x++) {
(function(x) {
setInterval(function() {
draw(x, 0, ctx);
}, 3000 * x);
})(x);
x = x++;
}
Also check this question for more examples how to fix situations like this.
I'm trying to draw a line using ctx.lineTo in loop.
I have small function in my prototype
this.draw = function(ctx)
{
ctx.beginPath();
trace(trail.join(' '));
for(var i=0;i<trail.length;i++)
{
// ctx.lineTo(trail[i].x,trail[i].y);
}
ctx.stroke();
}
When I run this, I receive some points traced ([389.272, 722.798] [392.583, 25.069]...) but I see nothing (very surprising)
When I remove the comment from ctx.lineTo, it fails and my trace returns [NaN, NaN] [NaN, NaN].... Constants in drawing function works perfectly (and my points doesn't change), but I need value from variables...
What's wrong? Problem occurs only on Firefox
edit:
trace is simple text assignment to html object
trail is an array of points which are simple objects
function point(x,y)
{
this.x = x;this.y = y;
this.toString = function()
{
var xs=this.x.toFixed(3);
var ys=this.y.toFixed(3);
var xs=" ".substring(0,8-xs.length)+xs;
var ys=" ".substring(0,8-ys.length)+ys;
return "["+xs+","+ys+"]";
}
}
There's still not enough information to really answer this, so I'm going to just hazard a guess: change the "point" constructor as follows:
function point(x,y)
{
this.x = x - 0; this.y = y - 0;
this.toString = function()
{
var xs=this.x.toFixed(3);
var ys=this.y.toFixed(3);
var xs=" ".substring(0,8-xs.length)+xs;
var ys=" ".substring(0,8-ys.length)+ys;
return "["+xs+","+ys+"]";
}
}
The idea is to make sure that "x" and "y" are actually numbers and not strings. You could also do this:
this.x = x - 0; this.y = y - 0;
if (isNaN(this.x) || isNaN(this.y)) {
alert("NaN! NaN! x is " + x + " y is " + y);