Strange bug in JS code (maybe some variable state caching) - javascript

I'm trying to make a small game using JS and Canvas. It is the implementation from old "Stack Attack" 2D platformer from Siemens cellphones.
So I implemented some basic logic to spawn, move around and throw boxes.
Then I came across a very strange bahaviour: sometimes boxes are thrown at the same position within a small time slice, and my special "protecting" function that checks if the column is "available" for throwing at the current moment does not help. Thus the boxes overlap and are going down partly overlapping each other.
I don't know how to efficiently debug this, so I kindly ask to help me with this error. Maybe there is a simple logical mistake in my code that I did not notice.
I made a codepen here: https://codepen.io/anon/pen/ajrqMB
Function moving the boxes down:
function moveColumnDown(pos) {
var b = []
for (var i = 0; i < boxes.length; i++) {
if (boxes[i].x / cw == pos) {
b.push(boxes[i])
}
}
for (var i = 0; i < b.length; i++) {
if (i == 0 && b[i].y < height-3-ch ||
i > 0 && b[i].y + ch < b[i-1].y) {
for (var j = i; j < b.length; j++) {
b[j].y += spd_y
}
break;
}
}
cols_state[pos] = (b.length == 0 || b[b.length-1].y >= y_offset+ch)
}
I'm looking at this code and can't unserstand how even the top overlapping box is going down: the condition i > 0 && b[i].y + ch < b[i-1].y where ch is a single box height should not be satisfied for it anyway...
Also, this line
cols_state[pos] = (b.length == 0 || b[b.length-1].y >= y_offset+ch)
in the end of the function updates the column state. When the box get dropped, column state is set to false. After the box has moved down a little bit in the function moveColumnDown() the state is updated - to false again, I suppose. But still the next box gets dropped for some unknown reason. I thought that maybe they get dropped at the same tick, when the column state is still true - but even in this case assigning false in the drop() function should have mitigated the problem. But the problem still persists.
UPDATE: It seems that the number of dropped boxes in the model doesn't match the real number of displayed boxes (it is much bigger). That's also very strange. On this picture there is 46 boxes (not on the conveyor), but the boxes[] array contains 53 elements.

Related

if (i > .length) not working inside for loop (image slider)

First thanks to all the people on this platform! I really appreciate all the help you can get to learn new stuff on the internet. My project is almost completed, I got one last thing that doesn't work properly. I have a for loop which contains code for an image slider. Every image has it's own arrows (right and left) which change by changing the current image. Here's the code inside the for loop:
for (let i = 0 ; i < insMax.length; i++) {
if (i < 1) {
document.getElementsByClassName('arrowleft')[i].removeEventListener('click' , insLeft);
} else {
document.getElementsByClassName('arrowleft')[i].addEventListener('click' , insLeft);
function insLeft() {
document.getElementById('Popup'+i).classList.add("hide");
document.getElementById('Popup'+(i - 1)).classList.remove("hide");
}
}
if (i > insMax.length) {
document.getElementsByClassName('arrowright')[i].removeEventListener('click' , insRight);
} else {
document.getElementsByClassName('arrowright')[i].addEventListener('click' , insRight);
function insRight() {
document.getElementById('Popup'+i).classList.add("hide");
document.getElementById('Popup'+(i + 1)).classList.remove("hide");
}
}
}
The weird thing again is, that the first if statement works as it should. When the first image is active, you can't click anymore on the left arrow. But the right arrow never works since 'Popup'+(i + 1) gets marked as null, which means that the if statement doesn't work. I also tried using if (i > insMax.length - 1) or if (i == insMax.length) but nothing works.
Your loop is defined as:
for (let i = 0 ; i < insMax.length; i++)
Because the condition of the loop is i < insMax.length the value of i will NEVER be greater than or equal to insMax.length. As soon as i equals insMax.length the loop will exit before doing anything inside the loop.
I would suggest you devise something outside this loop to do your check or leverage a while ... or do ... while pattern.

JavaScript && JQuery : Iterating

I have managed to get so far but for some reason, it does not match the last number and run the else command I have in the code.
My current code is:
JavaScript Fiddle
If anyone could point me in the right direction it would be very much appreciated as I've spent the last 2 hours trying to figure this problem out and only managed to get this far.
The next and Previous works fine, along with the View more/less. Its the 'View next address' that the code seems to skip the else.
This code here is always skipped, my question is does anyone know why or can point me in the direction of fixing this?
else {
$(".activee").eq(idx).addClass("hidden");
$(".activee").eq(idx).removeClass("activee").prev().addClass("activee");
alert("Sorry, there is no more addresses to show...");
num[idx]--;
}
Thanks in advance!
Change your fiddle to this:
var num = []; // <-- changed to array from object
for (i = 0; i < leng; i++) { // <-- while i < leng
num.push(i);
}
Updated fiddle
for (i = 0; i == leng; i++) {
num.push(0);
}
you're pushing the value 0 to the num array
probably meant to do
for (i = 0; i == leng; i++) {
num.push(howMany[i]);
}
but I just skimmed the code, so am not sure whether the logic is even valid.

Array values are not being read correctly inside gameloop

Im creating a program that displays random dots on a canvas, but I am running into problems when I give it rules specifying which dots are supposed to stay lit. I created a canvas with a matching array so for X number of pixels exist an object inside a 2D array. The array is created as follows:
<code>
//create array
ctx.grid = []
for (var i = 0; i < canvasSize; i++) {
ctx.grid.push([]);
for (var e = 0; e < canvasSize; e++) {
ctx.grid[i].push({light:false, clean:true})
}
}
</code>
The gameloop starts creates a random number from 0 to canvasSize*canvasSize
then maques a divicion to filter this number and get an exact location on my array ctx.grid and sets the light property to true.
the following loop finds all the objects in the array that have the property light set to true and draws a square on the canvas by calling the drawPoint() function.
<code>
setInterval(gameLoop,10);
function gameLoop() {
//Get a random number from 0 to canvasSize
var light = Math.floor(Math.random()*(canvasSize*canvasSize));
var row = parseInt(light/canvasSize);
var col = light%canvasSize;
ctx.grid[row][col].light = true;
//Find which points need to be drawn
for (var i = 0; i < ctx.grid.length; i++) {
for (var e = 0; e < ctx.grid[i].length; e++) {
if (ctx.grid[i][e].light) {
drawPoint(i,e);
findCorner(i,e);
clearPoint(i,e);
}
}
}
}
</code>
I have not included all the program's code because they are not essential to solving this problem.
Next is the beginning of what is supposed to be a set of rules,specified by findCorner(), that tell the program when some specific points are supposed to remain drawn on the canvas.
<code>
function findCorner(y,x) {
//Avoid corners
if (y != 0 || x != 0 || y != canvasSize || x != canvasSize) {
if (ctx.grid[y-1][x].light) { //Cannot read property '9' of undefined
//another set of rules
}
// console.log(ctx.grid);
// console.log(y);
// console.log(x);
// console.log(ctx.grid[y-1][x]);
</code>
When I run the program without the findCorners() function, it runs smoothly meaning my array is set up all right, but it is that if statement that is giving me problems. On the developer tools I get the following error:
Cannot read property '9' of undefined
This appears on the line I commented on my code, and the 'number' is always different.
I added the last console logs on my code because strangely enough when I run my program with those lines, the program runs without any errors though it does run very slowly and makes my browser crash after a while.
So it turns out I was wrong in my other comment.
The non-detection of edges was causing you to index into unset parts of your array causing those weird messages and was all of your problems
I scaled it back a bit to look at it
see https://jsfiddle.net/goujdwog/2/
the important thing to get from that is fixing the check at the start of findCorners():
if (y > 0 && x > 0 && y < canvasSize -1 && x < canvasSize -1)

Simple arithmetic challenge function with limited attempts

Recently began studying Javascript, trying to read out of Javascript: The Definitive Guide and Eloquent Javascript, while going off on my own to experiment with things in order to really etch them in my memory. I thought a good way to get my head around arithmetic operations and conditional statements, I'd build a series of little games based around each Math operator, and began with addition.
function beginAdditionChallenge() {
var x = Math.ceiling(Math.random()*100);
alert(x);
for (var i = 0; i < 3; i++) {
var a = Number(prompt("Provide the first addend.", ""));
var b = Number(prompt("Provide the second addend.", ""));
if (a + b === x) {
alert("Well done!");
break;
}
else if (a + b !== x && i < 3) {
alert("Please try again.");
}
else {
alert("Fail.");
}
}
}
function initChallenge() {
var button = document.getElementById("challengeButton");
button.addEventListener("click", beginAdditionChallenge);
}
window.addEventListener("load", initChallenge);
You can see the whole thing thus far on JSFiddle, here. The idea is that clicking the button generates a random number between 1 and 100, displays it to the user, then prompts them to provide two addends, giving them 3 attempts. If the sum of these addends is equal to the RNG number, it congratulates the user and ends the program. If they do not provide suitable addends, the loop prompts them to try again, until they've hit 3 attempts, at which point the program snarks at them and ends.
I know the event listener is not the failure point here, as when I change beginAdditionChallenge to simply display a test alert, it works, but I don't know what exactly is wrong with the loop I've created.
You did it correctly. However, Math.ceiling isn't a function and should be Math.ceil. In addition, your code (in jsfiddle) should be set to wrap in head. Why? Because right now you call initChallenge when the page loads. However, in your jsfiddle example, the code runs onLoad so the load event never gets called. Essentially, you're adding a load event after the page has loaded.
http://jsfiddle.net/rNn32/
Edit: In addition, you have a for loop that goes up to three. Therefore
else if (a + b !== x && i < 3) {
alert("Please try again.");
}
should be
else if (a + b !== x && i < 2) {
alert("Please try again.");
}
because when i === 2, the user's last chance has ended.
Everything is fine. Just change:-
var x = Math.ceiling(Math.random()*100);
to:-
var x = Math.ceil(Math.random()*100);

Javascript, loops infinitely and freezes

So I'm making a simple physics simulation using HTML5 canvas and javascript. I'm trying to make some realistic collisions, but whenever a collision occurs the code begins to loop infinitely and freezes the page.
I am using Google Chrome 24.0.1312.32 beta-m
When looking at the javascript console the line "console.log("I am colliding with something")" goes crazy and is printed thousands of times per second and completely breaks the page.
I'm not really sure why its' happening and I have no idea what to do. Any help and/or input would really be appreciated.
for (i = 0; i <= 3; i++) {
if (collide(i)) {
console.log("I am colliding with something");
if (typeof getCollideIndx === 'undefined') {
console.log("collide index is not undefined");
if (!getCollideIndx(i)) {
console.log("Made it past null check");
//...update object based on collision
the collide() function is:
function collide(b) {
for (i = 0; i <= 3; i++) {
//Distance between each object
var distance = (Math.sqrt(Math.pow((balls[b].x - balls[i].x), 2) + Math.pow(balls[b].y - balls[i].y, 2)));
if (distance < 32) {
//must be less than 2*radius -- all radii are the same
//makes it so that it doesn't return true when checking its own index
if (!(balls[b].mass == balls[i].mass)) {
return true;
} else {
return false;
}
}
}
}
I cannot see an infinite loop in your code , my best guess would be this statement
if (typeof getCollideIndx === 'undefined')
fails every time and whatever function the below code is in is called continuously
for (i = 0; i <= 3; i++) {
if (collide(i)) {
console.log("I am colliding with something");
if (typeof getCollideIndx === 'undefined') {
console.log("collide index is not undefined");
if (!getCollideIndx(i)) {
console.log("Made it past null check");
//...update object based on collision
also in this , I do not see the point of the for loop as the control always goes back to the calling function (in the collide() function)
Well, being trapped in that for loop implies that the index variable i is getting set incorrectly somewhere. Without being able to see the entirety of the code I cannot say for sure, but the loop for(i=0; i<3; i++){... will be assigning i to the window object because you have not explicitly scoped it (i.e. for(var i...).
See for example this jsfiddle where the first function will only run once rather than three times because the same variable i is affected in the second function.
Obviously running once != infinite loop, but if the collide function does something to i (or maybe breaks after it finds a collision?) then the value of i will be reset to 0 at the beginning of its for loop each time it's called.
So yeah without some more code I can't say for sure; but my advice in this case is: always use var in for loops or weird things can happen!

Categories

Resources