How to detect collisions for a complex object in JavaScript - 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.

Related

How to solve this multiple nested for loop

EDIT: Big edit from ealier
I have achieved: the ultimate for-loop HELL.
What it does: scans an image and finds a 40 by 40 pixel square that has every pixel within it approximately the same color.
The problem: The code doesn't work as intended. Unsure why, but all my attempts to debug are in vain.
jimp.read('jeffrey.png')
.then(image => {
console.log(jimp.intToRGBA(image.getPixelColor(0,0)))
console.log(image.bitmap.width)
console.log(image.bitmap.height)
var breakAll = false;
var FINALX;
var FINALY;
var doneCounter = 0;
//40 by 40 pixels needed for qr code. Thisis barcode, so make it 40 by 80 or smthn, figure out that x thing.
for(var x = 0; x < image.bitmap.width; x++) {
var breakThis = false;
console.log(x + " is x")
if(breakAll == true) {
break;
}
var verticalStart = 0;
for(var y1 = verticalStart; y1 < image.bitmap.height; y1++) {
if(breakAll == true) {
break;
}
var tempStandardR = jimp.intToRGBA(image.getPixelColor(x,y1)).r;
var tempStandardG = jimp.intToRGBA(image.getPixelColor(x,y1)).g;
var tempStandardB = jimp.intToRGBA(image.getPixelColor(x,y1)).b;
var verticalCounter = 0;
for(var y2 = y1; y2 < image.bitmap.height; y2++) {
if(breakAll == true) {
break;
}
if(verticalCounter >= 40) {
//Then do X stuff
//horizcountertim
for(var y3 = y1; y3 < y1 + 40; y3++) {
if(breakAll == true) {
break;
}
breakThis = false;
var horizontalCounter = 0;
var tempStandardR3 = jimp.intToRGBA(image.getPixelColor(x,y3)).r;
var tempStandardG3 = jimp.intToRGBA(image.getPixelColor(x,y3)).g;
var tempStandardB3 = jimp.intToRGBA(image.getPixelColor(x,y3)).b;
for(var x2 = x; x2 < x + 41; x2++) {
if(breakAll == true) {
break;
}
console.log(doneCounter)
if(doneCounter >= 40) {
//SUCESS!!!!!!
//THE SPOT HAS BEEN FOUND AT (x minus 40, y minus 40).
//insert other image in this image at above coordinates. Wow I highly doubt this works.
console.log('SUCESS!!!!!!!!!')
FINALX = x2-40;
FINALY = y3-40;
breakAll = true;
break;
}
if(breakAll == true) {
break;
}
var tempStandardR4 = jimp.intToRGBA(image.getPixelColor(x2,y3)).r;
var tempStandardG4 = jimp.intToRGBA(image.getPixelColor(x2,y3)).g;
var tempStandardB4 = jimp.intToRGBA(image.getPixelColor(x2,y3)).b;
if((((tempStandardR3 - tempStandardR4) <= 20) && ((tempStandardR3 - tempStandardR4) >= -20)) && (((tempStandardG3 - tempStandardG4) <= 20) && ((tempStandardG3 - tempStandardG4) >= -20)) && (((tempStandardB3 - tempStandardB4) <= 20) && ((tempStandardB3 - tempStandardB4) >= -20))) {
horizontalCounter++;
if(horizontalCounter == 40) {
horizontalCounter = 0;
doneCounter++;
break;
}
// if((x2 - x >= 39) && (y3 - y1) >= 39) {
if(breakAll == true) {
break;
}
}
else {
horizontalCounter = 0;
verticalCounter = 0;
doneCounter = 0;
console.log('donecounter reset')
verticalStart = y3;
//y2 = y3;
breakThis = true;
break;
}
}
if(breakAll == true) {
break;
}
if(breakThis = true) {
break;
}
}
if(breakThis = true) {
breakThis = false;
break;
}
}
if(breakAll == true) {
break;
}
var tempStandardR2 = jimp.intToRGBA(image.getPixelColor(x,y2)).r;
var tempStandardG2 = jimp.intToRGBA(image.getPixelColor(x,y2)).g;
var tempStandardB2 = jimp.intToRGBA(image.getPixelColor(x,y2)).b;
if((((tempStandardR - tempStandardR2) <= 20) && ((tempStandardR - tempStandardR2) >= -20)) && (((tempStandardG - tempStandardG2) <= 20) && ((tempStandardG - tempStandardG2) >= -20)) && (((tempStandardB - tempStandardB2) <= 20) && ((tempStandardB - tempStandardB2) >= -20))) {
verticalCounter++;
}
else {
verticalCounter = 0;
verticalStart = y2;
console.log('lvl1 reset')
doneCounter = 0;
break;
}
}
}
}
console.log(' done');
console.log(FINALX + " = x")
console.log(FINALY + " = y")
})
.catch(err => {
console.log(err);
})
Each of the tempStandards are the RGB value for that individual pixel.
All of the for loops are to get a 40 by 40 open grid.
The issue I do see is a problem, but am baffled as to why, is doneCounter, that is supposed to ++ every time a horizontal counter has reached 40 and thus finished its horizontal check of one row of the 40 by 40 grid.
The issue when console logging doneCounter is, it console logs the same value twice, which makes no sense since its within the same for loop that has an if else statement that either adds to donecounter or resets it to 0.
EDIT: I scrapped the above code to try and remake it entirely to see if that would let it work, still failed though and not a clue as to why: Below is the updated attempt:
jimp.read('jeffrey.png')
.then(image => {
console.log(jimp.intToRGBA(image.getPixelColor(0,0)))
console.log(image.bitmap.width)
console.log(image.bitmap.height)
var breakAll = false;
var FINALX;
var FINALY;
var doneCounter = 0;
var veritcalCounter = 0;
var verticalStart = 0;
var horizontalCounter = 0;
var breakAll = false;
var breakThis = false;
//40 by 40 pixels needed for qr code. Thisis barcode, so make it 40 by 80 or smthn, figure out that x thing.
for(var x = 0; x < image.bitmap.width; x++) {
console.log(x)
verticalCounter = 0;
for(var y = 0; y < image.bitmap.height; y++) {
var tempStandardR = jimp.intToRGBA(image.getPixelColor(x,verticalStart)).r;
var tempStandardG = jimp.intToRGBA(image.getPixelColor(x,verticalStart)).g;
var tempStandardB = jimp.intToRGBA(image.getPixelColor(x,verticalStart)).b;
var tempStandardR2 = jimp.intToRGBA(image.getPixelColor(x,y)).r;
var tempStandardG2 = jimp.intToRGBA(image.getPixelColor(x,y)).g;
var tempStandardB2 = jimp.intToRGBA(image.getPixelColor(x,y)).b;
if((((tempStandardR - tempStandardR2) <= 20) && ((tempStandardR - tempStandardR2) >= -20)) && (((tempStandardG - tempStandardG2) <= 20) && ((tempStandardG - tempStandardG2) >= -20)) && (((tempStandardB - tempStandardB2) <= 20) && ((tempStandardB - tempStandardB2) >= -20))) {
verticalCounter++;
if(verticalCounter == 40) {
verticalCounter = 0;
for(var y1 = y-40; y1 < y; y1++) {
horizontalCounter = 0;
for(var x1 = x; x1 < x+41; x1++) {
var tempStandardR3 = jimp.intToRGBA(image.getPixelColor(x,y1)).r;
var tempStandardG3 = jimp.intToRGBA(image.getPixelColor(x,y1)).g;
var tempStandardB3 = jimp.intToRGBA(image.getPixelColor(x1,y1)).b;
var tempStandardR4 = jimp.intToRGBA(image.getPixelColor(x1,y1)).r;
var tempStandardG4 = jimp.intToRGBA(image.getPixelColor(x1,y1)).g;
var tempStandardB4 = jimp.intToRGBA(image.getPixelColor(x1,y1)).b;
if((((tempStandardR3 - tempStandardR4) <= 20) && ((tempStandardR3 - tempStandardR4) >= -20)) && (((tempStandardG3 - tempStandardG4) <= 20) && ((tempStandardG3 - tempStandardG4) >= -20)) && (((tempStandardB3 - tempStandardB4) <= 20) && ((tempStandardB3 - tempStandardB4) >= -20))) {
if(x1 == x+40) {
doneCounter++;
if(doneCounter == 39) {
//SUCESS!!!!!!
//THE SPOT HAS BEEN FOUND AT (x minus 40, y minus 40).
//insert other image in this image at above coordinates. Wow I highly doubt this works.
console.log('SUCESS!!!!!!!!!')
FINALX = x;
FINALY = y1-40;
breakAll = true;
break;
}
break;
}
}
else {
verticalCounter = 0;
horizontalCounter = 0;
doneCounter = 0;
y = y1;
breakThis = true;
break;
}
if(breakAll == true) {
break;
}
}
if(breakThis == true) {
breakThis = false;
break;
}
if(breakAll == true) {
break;
}
}
if(breakAll == true) {
break;
}
}
if(breakAll == true) {
break;
}
}
else {
verticalCounter = 0;
verticalStart = 0;
}
if(breakAll == true) {
break;
}
}
if(breakAll == true) {
break;
}
}
console.log(' done');
console.log(FINALX + " = x")
console.log(FINALY + " = y")
})
.catch(err => {
console.log(err);
})

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;
}

More JS AI causes slower AI movement in HTML Canvas

I have a simple little game with one character as the player and four enemy characters. I created a very basic AI, that moves towards the player when the player is nearby. That all worked fine, but when I added AI-AI collision (using a bounding box model), it slowed it down tremendously, and exponentially the more AI there are. With four AI, they move quite slowly. 3 AI is a bit better. 2 is just perfect, and 1 is too fast.
I have the following function to calculate the AI movement when near a player.
function updateAI() {
for (i = 0; i < aiCount; i++) {
if (aiCounterAI >= aiCount) {
aiCounterAI = 0;
}
checkArmyAIcol = armyAI[aiCounterAI][1];
checkArmyAIrow = armyAI[aiCounterAI][2];
enemySpeed = enemies[armyAI[aiCounterAI][0][0]][3];
enemyPlayerCollision = false;
if (playerBattle.xCoord - 6 <= checkArmyAIcol && playerBattle.xCoord + 6 >= checkArmyAIcol) {
if (playerBattle.yCoord - 6 <= checkArmyAIrow && playerBattle.yCoord + 6 >= checkArmyAIrow) {
if (playerBattle.x < armyAI[aiCounterAI][3] - 48) {
armyAI[aiCounterAI][3] = armyAI[aiCounterAI][3] - enemySpeed;
aiDirection = 'left';
}
if (playerBattle.x > armyAI[aiCounterAI][3] + 48) {
armyAI[aiCounterAI][3] = armyAI[aiCounterAI][3] + enemySpeed;
aiDirection = 'right';
}
if (playerBattle.y < armyAI[aiCounterAI][4] - 48) {
armyAI[aiCounterAI][4] = armyAI[aiCounterAI][4] - enemySpeed;
aiDirection = 'up';
}
if (playerBattle.y > armyAI[aiCounterAI][4] + 48) {
armyAI[aiCounterAI][4] = armyAI[aiCounterAI][4] + enemySpeed;
aiDirection = 'down';
}
checkBattleCollision('ai',aiCounterAI);
armyAI[aiCounterAI][1] = Math.ceil(armyAI[aiCounterAI][3] / 48);
armyAI[aiCounterAI][2] = Math.ceil(armyAI[aiCounterAI][4] / 48);
}
}
aiCounterAI++;
}
}
And finally I have this function to calculate the AI collision.
if (type == 'ai') {
enemyEnemyCollision = false;
if (aiCount > 1) {
checkArmyAIcol1 = armyAI[ai][1];
checkArmyAIrow1 = armyAI[ai][2];
checkArmyAIx1 = armyAI[ai][3];
checkArmyAIy1 = armyAI[ai][4];
var aiCounter2 = 0;
for (i = 0; i < aiCount; i++) {
if (aiCounter2 != ai) {
checkArmyAIcol2 = armyAI[aiCounter2][1];
checkArmyAIrow2 = armyAI[aiCounter2][2];
checkArmyAIx2 = armyAI[aiCounter2][3];
checkArmyAIy2 = armyAI[aiCounter2][4];
// Check if the AI is near the other AI before checking if collision is true
if (checkArmyAIcol1 - 1 <= checkArmyAIcol2 && checkArmyAIcol1 + 1 >= checkArmyAIcol2) {
if (checkArmyAIrow1 - 1 <= checkArmyAIrow2 && checkArmyAIrow1 + 1 >= checkArmyAIrow2) {
if (checkArmyAIx1 < checkArmyAIx2 + 48 &&
checkArmyAIx1 + 48 > checkArmyAIx2 &&
checkArmyAIy1 < checkArmyAIy2 + 48 &&
checkArmyAIy1 + 48 > checkArmyAIy2) {
enemyEnemyCollision = true;
checkEnemyEnemyCollision(ai,aiCounter2);
}
}
}
}
aiCounter2++;
}
}
}
function checkEnemyEnemyCollision(enemy1,enemy2) {
enemySpeed = enemies[armyAI[enemy1][0][0]][3];
if (enemyEnemyCollision == true) {
if (aiDirection == 'left') {
armyAI[enemy1][3] = armyAI[enemy1][3] + enemySpeed;}
if (aiDirection == 'right') {
armyAI[enemy1][3] = armyAI[enemy1][3] - enemySpeed;}
if (aiDirection == 'up') {
armyAI[enemy1][4] = armyAI[enemy1][4] + enemySpeed;}
if (aiDirection == 'down') {
armyAI[enemy1][4]= armyAI[enemy1][4] - enemySpeed;}
console.log("ya'll collided ya clumsy potatoes");
}
}
The updateAI function is fast and runs great. Adding the collision (using a bounding box model) as said before slows it down a lot. These functions are called sixty times a second, through requestAnimationFrame in my gameloop. My guess is that it can't keep up fast enough in the collision with the frame rate so they just can't move much as they could otherwise. Yet, I don't know how to fix this. Does anyone have any suggestions? Bounding box collision and multiple moving items is new territory for me so I wouldn't mind suggestions on improving my code.

js game freezes with no error

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.

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 = "";
}

Categories

Resources