js game freezes with no error - javascript

I am working on a javascript game that involves building, destroying, and survival.
It has been working fine but after adding trees the game would randomly freeze after breaking blocks.
The code is here:
for (var bl in blocks) {
if (mouse.x >= blocks[bl].x-camera.x && mouse.y >= camera.y+blocks[bl].y && mouse.x <= blocks[bl].x-camera.x+64 && mouse.y <= camera.y+blocks[bl].y+64) {
document.body.style.cursor = "pointer";
if (mouse.down) {
if (!blocks[bl].d && blocks[bl].d !== 0) {
blocks[bl].d = 32;
} else if (blocks[bl].d > 0) {
blocks[bl].d -= 0.5;
if (tools[player.tool].n === 'axe') {
blocks[bl].d -= 1;
}
} else {
var fb = false;
for (var i in inventory) {
if (inventory[i].n === blocks[bl].n) {
inventory[i].a ++;
fb = true;
}
}
if (!fb) {
inventory.push({n: blocks[bl].n, a: 1});
}
blocks.splice(bl, 1);
}
}
}
}
I don't see any way there could be an infinite loop and no errors show up when it happens.
EDIT
I changed the code to
var spliceblock = {bl: 0, s: false};
for (var bl in blocks) {
if (mouse.x >= blocks[bl].x-camera.x && mouse.y >= camera.y+blocks[bl].y && mouse.x <= blocks[bl].x-camera.x+64 && mouse.y <= camera.y+blocks[bl].y+64) {
document.body.style.cursor = "pointer";
if (mouse.down) {
if (!blocks[bl].d && blocks[bl].d !== 0) {
blocks[bl].d = 32;
} else if (blocks[bl].d > 0) {
blocks[bl].d -= 0.5;
if (tools[player.tool].n === 'axe') {
blocks[bl].d -= 1;
}
} else {
var fb = false;
for (var i in inventory) {
if (inventory[i].n === blocks[bl].n) {
inventory[i].a ++;
fb = true;
}
}
if (!fb) {
inventory.push({n: blocks[bl].n, a: 1});
}
spliceblock.s = true;
spliceblock.bl = bl;
//blocks.splice(bl, 1);
}
}
}
}
if (spliceblock.s) {
blocks.splice(spliceblock.bl, 1);
}
but it still freezes randomly when trying to break blocks.

Modifying an array (using splice) while you're iterating through it is bound to cause problems. If you remove the block bl from the array and then continue to run through it, the counter will probably be off.
Instead, store the index of the block you're removing, then remove it after you're done looping through the blocks.

Related

Character will not jump after touching in JS

I am programming collision detection in JS for a platformer. For some reason, when my character touches the ground on the top, it won't jump again. Here's my code:
if (isCollideY(platforms[i].getBoundingClientRect(), document.getElementById('spriteNotReal').getBoundingClientRect()) == true) {
if (falling == true && (jumping == false)) {
moveY = platforms[i].getBoundingClientRect().y + 3;
momentumY = 0;
onSolidGround = true;
}
}
if (event.code == 'KeyW' && (moveY <= 300)) {
moveY += 1;
move (moveX, moveY);
momentumY = momentumY + 20;
onSolidGround = false;
falling = false;
jumping = true;
}
else if (onSolidGround == false) {
if (momentumY < 0) {
falling = true;
}
else if (momentumY > 0) {
jumping = true;
}
else {
jumping = false;
}
moveX += momentumX / 3 + 1;
document.getElementById("spriteNotReal").src = "jumpmain.gif";
}
My problem was somewhat stupid. After checking the input code, I realized that the jump wasn't happening because it would only jump while on the "platform" I set up to test, not while it was actually on a platform. Here's the improved code:
if (event.code == 'KeyW' && (onSolidGround == true)) {
moveY += 1;
move (moveX, moveY);
momentumY = momentumY + 20;
onSolidGround = false;
falling = false;
jumping = true;
}

How to detect collisions for a complex object in JavaScript

How should I detect collisions for a sprite that can't have a rectangular hitbox? I am trying to make a platformer, and I'm currently working on collision detections for the level's platforms. Here's my physics:
function onTimerTick() {
if (moveY > 300) {
momentumY = momentumY - 2;
move(moveX, moveY);
} else if (moveY < 300) {
moveY = 300;
momentumY = 0;
move(moveX, moveY);
}
moveY = moveY + momentumY;
move(moveX, moveY);
if (moveY <= 300) {
if (momentumX > 0) {
right = true;
momentumX -= 1;
} else if (momentumX < 0) {
if (document.getElementById("spriteNotReal").getAttribute("scr") != "walkLeft.gif") {
document.getElementById("spriteNotReal").src = "walkLeft.gif";
}
right = false;
momentumX += 1;
} else {
if (right == true) {
document.getElementById("spriteNotReal").src = "amaincharacter.png";
} else {
document.getElementById("spriteNotReal").src = "maincharacterleft.png";
}
}
moveX = moveX + momentumX;
} else {
moveX += momentumX / 3 + 1;
document.getElementById("spriteNotReal").src = "jumpmain.gif";
}
document.getElementById("gold").innerHTML = momentumX;
}
I'm thinking of trying to break up the level into different rectangles, all in the same class, and then test for collisions within that class. Is there any way I could do this? Also, I think I should use boundingClientRect, but I don't know how to use this for collisions.

Math.pow returning 0 in calc

I'm making a calculator currently and I'm running into an issue with one of the functions, specifically x^y, it keeps returning 0 and not even seeming to run the setInterval at all, though it runs without the if function around it. fn is for which function its using which is x^y, and vi is just a tool in the calculator to distinguish which number you are changing as in reactant, or reactant2, reactants are the 2 numbers that are squared against each other in this case. (this is only the portion of the code with the problem)
function click15(){
if (reactant > 0) {
reactant = parseFloat(reactant);
}
if (reactant2 > 0) {
reactant2 = parseFloat(reactant2);
}
if (fn === 0) {
product = reactant / reactant2;
} else if (fn === 1) {
product = reactant * reactant2;
} else if (fn === 2) {
product = reactant - reactant2;
} else if (fn === 3) {
product = reactant + reactant2;
} else if (fn === 4) {
if (vi === 0) {
vi = 1;
var timer = setInterval(function(){
if (vi === 0) {
product = (Math.pow(reactant, reactant2));
clearInterval(timer);
}
}, 4);
}
}
reactant = product;
product = 0;
reactant2 = "0";
vir = 0;
vir2 = 0;
vi = 0;
di1 = 0;
di2 = 0;
fn = -1;
}

JavaScript/HTML Canvas: mouse detection for looped row of buttons

I'm building a simple drum machine that uses canvas for the GUI. I have a row of buttons drawn with a for loop that toggle on/off when clicked.
Here's a sample on JSFiddle
While it works, I'm a bit embarrassed by my buttonToggleDetection function. It's the only solution I could think of to check which button the mouse is over. I'm wondering if anyone can suggest a better way to do this?
var buttonToggleDetection = function(posx, posy, x) {
if (posx < canvas.width/2 && posy > x && posy < x*2) {
if (posx > x*1 && posx < x*2) {
if (pattern[0] === 0) {
pattern[0] = 1;
} else {
pattern[0] = 0;
}
}
else if (posx > x*2 && posx < x*3) {
if (pattern[1] === 0) {
pattern[1] = 1;
} else {
pattern[1] = 0;
}
}
else if (posx > x*3 && posx < x*4) {
if (pattern[2] === 0) {
pattern[2] = 1;
} else {
pattern[2] = 0;
}
}
else if (posx > x*4 && posx < x*5) {
if (pattern[3] === 0) {
pattern[3] = 1;
} else {
pattern[3] = 0;
}
}
else if (posx > x*5 && posx < x*6) {
if (pattern[4] === 0) {
pattern[4] = 1;
} else {
pattern[4] = 0;
}
}
else if (posx > x*6 && posx < x*7) {
if (pattern[5] === 0) {
pattern[5] = 1;
} else {
pattern[5] = 0;
}
}
else if (posx > x*7 && posx < x*8) {
if (pattern[6] === 0) {
pattern[6] = 1;
} else {
pattern[6] = 0;
}
}
else if (posx > x*8 && posx < x*9) {
if (pattern[7] === 0) {
pattern[7] = 1;
} else {
pattern[7] = 0;
}
}
}
if (posx > canvas.width/2 && posy > x && posy < x*2) {
if (posx > x*9 && posx < x*10) {
if (pattern[8] === 0) {
pattern[8] = 1;
} else {
pattern[8] = 0;
}
}
else if (posx > x*10 && posx < x*11) {
if (pattern[9] === 0) {
pattern[9] = 1;
} else {
pattern[9] = 0;
}
}
else if (posx > x*11 && posx < x*12) {
if (pattern[10] === 0) {
pattern[10] = 1;
} else {
pattern[10] = 0;
}
}
else if (posx > x*12 && posx < x*13) {
if (pattern[11] === 0) {
pattern[11] = 1;
} else {
pattern[11] = 0;
}
}
else if (posx > x*13 && posx < x*14) {
if (pattern[12] === 0) {
pattern[12] = 1;
} else {
pattern[12] = 0;
}
}
else if (posx > x*14 && posx < x*15) {
if (pattern[13] === 0) {
pattern[13] = 1;
} else {
pattern[13] = 0;
}
}
else if (posx > x*15 && posx < x*16) {
if (pattern[14] === 0) {
pattern[14] = 1;
} else {
pattern[14] = 0;
}
}
else if (posx > x*16 && posx < x*17) {
if (pattern[15] === 0) {
pattern[15] = 1;
} else {
pattern[15] = 0;
}
}
}
return;
}
Your way of bounds checking the buttons seems fine...but your loop could be tightened up a bit by defining your buttons in an array and then looping through that array.
Here's one way to draw and toggle buttons in html canvas:
Define each of your button's x,y,width,height & pressed-state
var buttons=[];
buttons.push({x:20,y:20,width:50,height:35,text:'One',isPressed:false});
buttons.push({x:80,y:20,width:50,height:35,text:'Two',isPressed:true});
buttons.push({x:140,y:20,width:50,height:35,text:'Three',isPressed:false});
Test if the mouse is over any button:
for(var i=0;i<buttons.length;i++){
var b=buttons[i];
if(mx>b.x && mx<b.x+b.width && my>b.y && my<=b.y+b.height){
b.isPressed=(!b.isPressed);
}
}
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();
ctx.textAlign='center';
ctx.textBaseline='middle';
ctx.font='14px verdana';
var buttons=[];
buttons.push({x:20,y:20,width:50,height:35,text:'One',isPressed:false});
buttons.push({x:80,y:20,width:50,height:35,text:'Two',isPressed:true});
buttons.push({x:140,y:20,width:50,height:35,text:'Three',isPressed:false});
draw();
function draw(){
var label;
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<buttons.length;i++){
var b=buttons[i];
if(b.isPressed){
ctx.shadowBlur=0;
ctx.shadowOffsetX=0;
ctx.shadowOffsetY=0;
ctx.shadowColor=null;
ctx.fillStyle='powderblue';
label='ON';
}else{
ctx.shadowBlur=2;
ctx.shadowOffsetX=2;
ctx.shadowOffsetY=2;
ctx.shadowColor='black';
ctx.fillStyle='paleturquoise';
label='OFF';
}
ctx.strokeRect(b.x,b.y,b.width,b.height);
ctx.fillRect(b.x,b.y,b.width,b.height);
ctx.shadowBlur=0;
ctx.shadowOffsetX=0;
ctx.shadowOffsetY=0;
ctx.shadowColor=null;
ctx.fillStyle='black';
ctx.fillText(label,b.x+b.width/2,b.y+b.height/2);
ctx.fillStyle='gray';
ctx.fillText(label,b.x+b.width/2+1,b.y+b.height/2+1);
}
}
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mx=parseInt(e.clientX-offsetX);
my=parseInt(e.clientY-offsetY);
//
for(var i=0;i<buttons.length;i++){
var b=buttons[i];
if(mx>b.x && mx<b.x+b.width && my>b.y && my<=b.y+b.height){
b.isPressed=(!b.isPressed);
}
}
draw();
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Click the buttons</h4>
<canvas id="canvas" width=300 height=300></canvas>
I would recommend using svg instead of canvas. The content of an SVG node is very similar to that of a canvas node, but each shape is built out of XML markup or dynamically created elements, much like document.body's contents. This gives you a few big advantages:
You can apply classes to individual shapes, and use css to apply
colors/styles.
You can take advantage of css's :hover pseudo-style
to apply color to hovered elements.
Most importantly: You can bind events to each shape!
The code below is available to fiddle with at http://jsfiddle.net/3zevLyur/1/
Here's the html:
<svg id="drumMachine"/>
<div id="debugText"/>
Here's the javascript to build the pads and bind events:
var svg = document.getElementById("drumMachine");
var activePad = null;
var debugText = document.getElementById("debugText");
for (var x = 0; x < 16; x++) {
createNewPad(x);
}
function createNewPad(padNumber) {
var r = document.createElementNS("http://www.w3.org/2000/svg", "rect")
r.setAttribute("width", "40");
r.setAttribute("height", "40");
r.setAttribute("x", padNumber * 50);
r.setAttribute("data-pad-number", x);
r.onmouseenter = mouseOver;
r.onmouseleave = mouseOut;
svg.appendChild(r);
}
function mouseOver() {
activePad = this;
debugText.innerHTML = this.getAttribute("data-pad-number");
}
function mouseOut() {
activePad = null;
debugText.innerHTML = "";
}

How to move an element in javascript automatically with while loop?

I am making a Snake game so I'm trying to move my snake. It is moving with keys but it should move automatically on the screen. I tried doing that with while loops like in the code below but because of break; I have to press a key every time I want it to move. How can I make it move automatically? I tried removing break; an using an if statement but I didn't succeed.
Any other solutions or something else?
I'm new to programming so any advices would be helpful.
var main = function() {
var i = 0;
var j = 0;
$(document).keyup(function(event) {
var e = event.which;
while(i == 1) {
$('.snake').animate({left: '+=10px'}, 10);
break;
}
while(i == 2) {
$('.snake').animate({left: '-=10px'}, 10);
break;
}
while(i == 3) {
$('.snake').animate({top: '-=10px'}, 10);
break;
}
while(i == 4) {
$('.snake').animate({top: '+=10px'}, 10);
break;
}
//Which key is preesed
//D
if(e == 68) {
i = 1;
}
//A
else if(e == 65) {
i = 2;
}
//W
else if(e == 87) {
i = 3;
}
//S
else if(e == 83) {
i = 4;
}
//Any other key
else {
i = 0;
}
});
};
$(document).ready(main);
I think you just have to organize a little bit your code.
First. You must put your code inside a function. You really don't need a while. You can use a simple if.
function move(i) {
if(i == 1) {
$('.snake').animate({left: '+=10px'}, 10);
break;
}
if(i == 2) {
$('.snake').animate({left: '-=10px'}, 10);
break;
}
if(i == 3) {
$('.snake').animate({top: '-=10px'}, 10);
break;
}
if(i == 4) {
$('.snake').animate({top: '+=10px'}, 10);
break;
}
}
Now you have to change the event, using keydown instead of keyup
function main() {
var interval;
$(document).keydown(function(event) {
if(interval) clearInterval(interval); // Clear the previous interval
var e = event.which;
var i;
//Which key is pressed
//D
if(e == 68) {
i = 1;
}
//A
else if(e == 65) {
i = 2;
}
//W
else if(e == 87) {
i = 3;
}
//S
else if(e == 83) {
i = 4;
}
//Any other key
else {
i = 0;
}
interval = setInterval(function() {
move(i)
},1000); // repeat every 1 second
});
}
$(document).ready(main);

Categories

Resources