JS: putting 2 liquid buttons in my page instead of 1 - javascript

Heello everyone!
I hope you feel well and i wish you a happy new year !
I just love this liquid button :
https://codepen.io/waaark/pen/VbgwEM
$(function() {
// Vars
var pointsA = [],
pointsB = [],
$canvas = null,
canvas = null,
context = null,
vars = null,
points = 8,
viscosity = 20,
mouseDist = 70,
damping = 0.05,
showIndicators = false;
mouseX = 0,
mouseY = 0,
relMouseX = 0,
relMouseY = 0,
mouseLastX = 0,
mouseLastY = 0,
mouseDirectionX = 0,
mouseDirectionY = 0,
mouseSpeedX = 0,
mouseSpeedY = 0;
/**
* Get mouse direction
*/
function mouseDirection(e) {
if (mouseX < e.pageX)
mouseDirectionX = 1;
else if (mouseX > e.pageX)
mouseDirectionX = -1;
else
mouseDirectionX = 0;
if (mouseY < e.pageY)
mouseDirectionY = 1;
else if (mouseY > e.pageY)
mouseDirectionY = -1;
else
mouseDirectionY = 0;
mouseX = e.pageX;
mouseY = e.pageY;
relMouseX = (mouseX - $canvas.offset().left);
relMouseY = (mouseY - $canvas.offset().top);
}
$(document).on('mousemove', mouseDirection);
/**
* Get mouse speed
*/
function mouseSpeed() {
mouseSpeedX = mouseX - mouseLastX;
mouseSpeedY = mouseY - mouseLastY;
mouseLastX = mouseX;
mouseLastY = mouseY;
setTimeout(mouseSpeed, 50);
}
mouseSpeed();
/**
* Init button
*/
function initButton() {
// Get button
var button = $('.btn-liquid');
var buttonWidth = button.width();
var buttonHeight = button.height();
// Create canvas
$canvas = $('<canvas></canvas>');
button.append($canvas);
canvas = $canvas.get(0);
canvas.width = buttonWidth+100;
canvas.height = buttonHeight+100;
context = canvas.getContext('2d');
// Add points
var x = buttonHeight/2;
for(var j = 1; j < points; j++) {
addPoints((x+((buttonWidth-buttonHeight)/points)*j), 0);
}
addPoints(buttonWidth-buttonHeight/5, 0);
addPoints(buttonWidth+buttonHeight/10, buttonHeight/2);
addPoints(buttonWidth-buttonHeight/5, buttonHeight);
for(var j = points-1; j > 0; j--) {
addPoints((x+((buttonWidth-buttonHeight)/points)*j), buttonHeight);
}
addPoints(buttonHeight/5, buttonHeight);
addPoints(-buttonHeight/10, buttonHeight/2);
addPoints(buttonHeight/5, 0);
// addPoints(x, 0);
// addPoints(0, buttonHeight/2);
// addPoints(0, buttonHeight/2);
// addPoints(buttonHeight/4, 0);
// Start render
renderCanvas();
}
/**
* Add points
*/
function addPoints(x, y) {
pointsA.push(new Point(x, y, 1));
pointsB.push(new Point(x, y, 2));
}
/**
* Point
*/
function Point(x, y, level) {
this.x = this.ix = 50+x;
this.y = this.iy = 50+y;
this.vx = 0;
this.vy = 0;
this.cx1 = 0;
this.cy1 = 0;
this.cx2 = 0;
this.cy2 = 0;
this.level = level;
}
Point.prototype.move = function() {
this.vx += (this.ix - this.x) / (viscosity*this.level);
this.vy += (this.iy - this.y) / (viscosity*this.level);
var dx = this.ix - relMouseX,
dy = this.iy - relMouseY;
var relDist = (1-Math.sqrt((dx * dx) + (dy * dy))/mouseDist);
// Move x
if ((mouseDirectionX > 0 && relMouseX > this.x) || (mouseDirectionX < 0 && relMouseX < this.x)) {
if (relDist > 0 && relDist < 1) {
this.vx = (mouseSpeedX / 4) * relDist;
}
}
this.vx *= (1 - damping);
this.x += this.vx;
// Move y
if ((mouseDirectionY > 0 && relMouseY > this.y) || (mouseDirectionY < 0 && relMouseY < this.y)) {
if (relDist > 0 && relDist < 1) {
this.vy = (mouseSpeedY / 4) * relDist;
}
}
this.vy *= (1 - damping);
this.y += this.vy;
};
/**
* Render canvas
*/
function renderCanvas() {
// rAF
rafID = requestAnimationFrame(renderCanvas);
// Clear scene
context.clearRect(0, 0, $canvas.width(), $canvas.height());
context.fillStyle = '#fff';
context.fillRect(0, 0, $canvas.width(), $canvas.height());
// Move points
for (var i = 0; i <= pointsA.length - 1; i++) {
pointsA[i].move();
pointsB[i].move();
}
// Create dynamic gradient
var gradientX = Math.min(Math.max(mouseX - $canvas.offset().left, 0), $canvas.width());
var gradientY = Math.min(Math.max(mouseY - $canvas.offset().top, 0), $canvas.height());
var distance = Math.sqrt(Math.pow(gradientX - $canvas.width()/2, 2) + Math.pow(gradientY - $canvas.height()/2, 2)) / Math.sqrt(Math.pow($canvas.width()/2, 2) + Math.pow($canvas.height()/2, 2));
var gradient = context.createRadialGradient(gradientX, gradientY, 300+(300*distance), gradientX, gradientY, 0);
gradient.addColorStop(0, '#102ce5');
gradient.addColorStop(1, '#E406D6');
// Draw shapes
var groups = [pointsA, pointsB]
for (var j = 0; j <= 1; j++) {
var points = groups[j];
if (j == 0) {
// Background style
context.fillStyle = '#1CE2D8';
} else {
// Foreground style
context.fillStyle = gradient;
}
context.beginPath();
context.moveTo(points[0].x, points[0].y);
for (var i = 0; i < points.length; i++) {
var p = points[i];
var nextP = points[i + 1];
var val = 30*0.552284749831;
if (nextP != undefined) {
// if (nextP.ix > p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y-val;
// p.cx2 = nextP.x-val;
// p.cy2 = nextP.y;
// } else if (nextP.ix > p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x+val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y-val;
// } else if (nextP.ix < p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y+val;
// p.cx2 = nextP.x+val;
// p.cy2 = nextP.y;
// } else if (nextP.ix < p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x-val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y+val;
// } else {
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
p.cx2 = (p.x+nextP.x)/2;
p.cy2 = (p.y+nextP.y)/2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
// continue;
// }
// context.bezierCurveTo(p.cx1, p.cy1, p.cx2, p.cy2, nextP.x, nextP.y);
} else {
nextP = points[0];
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
}
}
// context.closePath();
context.fill();
}
if (showIndicators) {
// Draw points
context.fillStyle = '#000';
context.beginPath();
for (var i = 0; i < pointsA.length; i++) {
var p = pointsA[i];
context.rect(p.x - 1, p.y - 1, 2, 2);
}
context.fill();
// Draw controls
context.fillStyle = '#f00';
context.beginPath();
for (var i = 0; i < pointsA.length; i++) {
var p = pointsA[i];
context.rect(p.cx1 - 1, p.cy1 - 1, 2, 2);
context.rect(p.cx2 - 1, p.cy2 - 1, 2, 2);
}
context.fill();
}
}
// Init
initButton();
});
body {
display: flex;
height: 100vh;
align-items: center;
justify-content: center;
}
.btn-liquid {
display: inline-block;
position: relative;
width: 240px;
height: 60px;
border-radius: 27px;
color: #fff;
font: 700 14px/60px "Droid Sans", sans-serif;
letter-spacing: 0.05em;
text-align: center;
text-decoration: none;
text-transform: uppercase;
}
.btn-liquid .inner {
position: relative;
z-index: 2;
}
.btn-liquid canvas {
position: absolute;
top: -50px;
right: -50px;
bottom: -50px;
left: -50px;
z-index: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<a href="http://waaark.com" class="btn-liquid">
<span class="inner">Liquid button ?</span>
</a>
I wanted to put 2 of this lovely button on a same single webpage, but i succeeded only tu put 1 on the same page.
I think it's because of JS because of the name of the variables must be different. So i tried to rename all the variables for the second button but i didn't succeed. I'm a newbie in JS and i think i can't distinguish really what is a real variable than what is not in this script (which seems to have extremly lot of variables).
Could you help me to put 2 of this lovely button on the same webpage ?
PS: To go further :
To try to succeed i tried this pen : https://codepen.io/architechnium/pen/wpYgGY (we would call it the "2nd pen")
but it worked even more bad, for this pen i had only a white page with no button at all on my local webpage (althought i did it exactly as with the first pen).
But i think there is maybe a trick or something special with this 2nd pen because there is only 1 414 views for this one instead of 60 000+ for the first pen (which has only 1 button).
Thank you very much for your attention and thank you very much for your help ! :)

You need to add code twice for the second button. You can optimize the code. I am showing this way you can add two buttons.
$(function() {
// Vars
var pointsA = [],
pointsB = [],
$canvas = null,
canvas = null,
context = null,
vars = null,
points = 8,
viscosity = 20,
mouseDist = 70,
damping = 0.05,
showIndicators = false;
mouseX = 0,
mouseY = 0,
relMouseX = 0,
relMouseY = 0,
mouseLastX = 0,
mouseLastY = 0,
mouseDirectionX = 0,
mouseDirectionY = 0,
mouseSpeedX = 0,
mouseSpeedY = 0;
pointsA2 = [],
pointsB2 = [],
$canvas2 = null,
canvas2 = null,
context2 = null,
vars2 = null,
points2 = 8,
viscosity2 = 20,
mouseDist2 = 70,
damping2 = 0.05,
showIndicators2 = false;
mouseX2 = 0,
mouseY2 = 0,
relMouseX2 = 0,
relMouseY2 = 0,
mouseLastX2 = 0,
mouseLastY2 = 0,
mouseDirectionX2 = 0,
mouseDirectionY2 = 0,
mouseSpeedX2 = 0,
mouseSpeedY2 = 0;
/**
* Get mouse direction
*/
function mouseDirection(e) {
if (mouseX < e.pageX)
mouseDirectionX = 1;
else if (mouseX > e.pageX)
mouseDirectionX = -1;
else
mouseDirectionX = 0;
if (mouseY < e.pageY)
mouseDirectionY = 1;
else if (mouseY > e.pageY)
mouseDirectionY = -1;
else
mouseDirectionY = 0;
mouseX = e.pageX;
mouseY = e.pageY;
relMouseX = (mouseX - $canvas.offset().left);
relMouseY = (mouseY - $canvas.offset().top);
}
function mouseDirection2(e) {
if (mouseX2 < e.pageX)
mouseDirectionX2 = 1;
else if (mouseX2 > e.pageX)
mouseDirectionX2 = -1;
else
mouseDirectionX2 = 0;
if (mouseY2 < e.pageY)
mouseDirectionY2 = 1;
else if (mouseY2 > e.pageY)
mouseDirectionY2 = -1;
else
mouseDirectionY2 = 0;
mouseX2 = e.pageX;
mouseY2 = e.pageY;
relMouseX2 = (mouseX2 - $canvas2.offset().left);
relMouseY2 = (mouseY2 - $canvas2.offset().top);
}
$('.btn-grid-1').on('mousemove', mouseDirection);
$('.btn-grid-2').on('mousemove', mouseDirection2);
/**
* Get mouse speed
*/
function mouseSpeed() {
mouseSpeedX = mouseX - mouseLastX;
mouseSpeedY = mouseY - mouseLastY;
mouseLastX = mouseX;
mouseLastY = mouseY;
setTimeout(mouseSpeed, 50);
}
mouseSpeed();
function mouseSpeed2() {
mouseSpeedX2 = mouseX2 - mouseLastX2;
mouseSpeedY2 = mouseY2 - mouseLastY2;
mouseLastX2 = mouseX2;
mouseLastY2 = mouseY2;
setTimeout(mouseSpeed2, 50);
}
mouseSpeed2();
/**
* Init button
*/
function initButton() {
// Get button
var button = $('.btn-liquid');
var buttonWidth = button.width();
var buttonHeight = button.height();
// Create canvas
$canvas = $('<canvas></canvas>');
button.append($canvas);
canvas = $canvas.get(0);
canvas.width = buttonWidth+100;
canvas.height = buttonHeight+100;
context = canvas.getContext('2d');
// Add points
var x = buttonHeight/2;
for(var j = 1; j < points; j++) {
addPoints((x+((buttonWidth-buttonHeight)/points)*j), 0);
}
addPoints(buttonWidth-buttonHeight/5, 0);
addPoints(buttonWidth+buttonHeight/10, buttonHeight/2);
addPoints(buttonWidth-buttonHeight/5, buttonHeight);
for(var j = points-1; j > 0; j--) {
addPoints((x+((buttonWidth-buttonHeight)/points)*j), buttonHeight);
}
addPoints(buttonHeight/5, buttonHeight);
addPoints(-buttonHeight/10, buttonHeight/2);
addPoints(buttonHeight/5, 0);
// addPoints(x, 0);
// addPoints(0, buttonHeight/2);
// addPoints(0, buttonHeight/2);
// addPoints(buttonHeight/4, 0);
// Start render
renderCanvas();
}
function initButton2() {
// Get button
var button = $('.btn-liquid-2');
var buttonWidth = button.width();
var buttonHeight = button.height();
// Create canvas
$canvas2 = $('<canvas></canvas>');
button.append($canvas2);
canvas2 = $canvas2.get(0);
canvas2.width = buttonWidth+100;
canvas2.height = buttonHeight+100;
context2 = canvas2.getContext('2d');
// Add points
var x = buttonHeight/2;
for(var j = 1; j < points2; j++) {
addPoints2((x+((buttonWidth-buttonHeight)/points2)*j), 0);
}
addPoints2(buttonWidth-buttonHeight/5, 0);
addPoints2(buttonWidth+buttonHeight/10, buttonHeight/2);
addPoints2(buttonWidth-buttonHeight/5, buttonHeight);
for(var j = points2-1; j > 0; j--) {
addPoints2((x+((buttonWidth-buttonHeight)/points2)*j), buttonHeight);
}
addPoints2(buttonHeight/5, buttonHeight);
addPoints2(-buttonHeight/10, buttonHeight/2);
addPoints2(buttonHeight/5, 0);
// addPoints(x, 0);
// addPoints(0, buttonHeight/2);
// addPoints(0, buttonHeight/2);
// addPoints(buttonHeight/4, 0);
// Start render
renderCanvas2();
}
/**
* Add points
*/
function addPoints(x, y) {
pointsA.push(new Point(x, y, 1));
pointsB.push(new Point(x, y, 2));
}
function addPoints2(x, y) {
pointsA2.push(new Point2(x, y, 1));
pointsB2.push(new Point2(x, y, 2));
}
/**
* Point
*/
function Point(x, y, level) {
this.x = this.ix = 50+x;
this.y = this.iy = 50+y;
this.vx = 0;
this.vy = 0;
this.cx1 = 0;
this.cy1 = 0;
this.cx2 = 0;
this.cy2 = 0;
this.level = level;
}
function Point2(x, y, level) {
this.x = this.ix = 50+x;
this.y = this.iy = 50+y;
this.vx = 0;
this.vy = 0;
this.cx1 = 0;
this.cy1 = 0;
this.cx2 = 0;
this.cy2 = 0;
this.level = level;
}
Point.prototype.move = function() {
this.vx += (this.ix - this.x) / (viscosity*this.level);
this.vy += (this.iy - this.y) / (viscosity*this.level);
var dx = this.ix - relMouseX,
dy = this.iy - relMouseY;
var relDist = (1-Math.sqrt((dx * dx) + (dy * dy))/mouseDist);
// Move x
if ((mouseDirectionX > 0 && relMouseX > this.x) || (mouseDirectionX < 0 && relMouseX < this.x)) {
if (relDist > 0 && relDist < 1) {
this.vx = (mouseSpeedX / 4) * relDist;
}
}
this.vx *= (1 - damping);
this.x += this.vx;
// Move y
if ((mouseDirectionY > 0 && relMouseY > this.y) || (mouseDirectionY < 0 && relMouseY < this.y)) {
if (relDist > 0 && relDist < 1) {
this.vy = (mouseSpeedY / 4) * relDist;
}
}
this.vy *= (1 - damping);
this.y += this.vy;
};
Point2.prototype.move = function() {
this.vx += (this.ix - this.x) / (viscosity2*this.level);
this.vy += (this.iy - this.y) / (viscosity2*this.level);
var dx = this.ix - relMouseX2,
dy = this.iy - relMouseY2;
var relDist2 = (1-Math.sqrt((dx * dx) + (dy * dy))/mouseDist);
// Move x
if ((mouseDirectionX2 > 0 && relMouseX2 > this.x) || (mouseDirectionX2 < 0 && relMouseX2 < this.x)) {
if (relDist2 > 0 && relDist2 < 1) {
this.vx = (mouseSpeedX2 / 4) * relDist2;
}
}
this.vx *= (1 - damping2);
this.x += this.vx;
// Move y
if ((mouseDirectionY2 > 0 && relMouseY2 > this.y) || (mouseDirectionY2 < 0 && relMouseY2 < this.y)) {
if (relDist2 > 0 && relDist2 < 1) {
this.vy = (mouseSpeedY2 / 4) * relDist2;
}
}
this.vy *= (1 - damping2);
this.y += this.vy;
};
/**
* Render canvas
*/
function renderCanvas() {
// rAF
rafID = requestAnimationFrame(renderCanvas);
// Clear scene
context.clearRect(0, 0, $canvas.width(), $canvas.height());
context.fillStyle = '#fff';
context.fillRect(0, 0, $canvas.width(), $canvas.height());
// Move points
for (var i = 0; i <= pointsA.length - 1; i++) {
pointsA[i].move();
pointsB[i].move();
}
// Create dynamic gradient
var gradientX = Math.min(Math.max(mouseX - $canvas.offset().left, 0), $canvas.width());
var gradientY = Math.min(Math.max(mouseY - $canvas.offset().top, 0), $canvas.height());
var distance = Math.sqrt(Math.pow(gradientX - $canvas.width()/2, 2) + Math.pow(gradientY - $canvas.height()/2, 2)) / Math.sqrt(Math.pow($canvas.width()/2, 2) + Math.pow($canvas.height()/2, 2));
var gradient = context.createRadialGradient(gradientX, gradientY, 300+(300*distance), gradientX, gradientY, 0);
gradient.addColorStop(0, '#102ce5');
gradient.addColorStop(1, '#E406D6');
// Draw shapes
var groups = [pointsA, pointsB]
for (var j = 0; j <= 1; j++) {
var points = groups[j];
if (j == 0) {
// Background style
context.fillStyle = '#1CE2D8';
} else {
// Foreground style
context.fillStyle = gradient;
}
context.beginPath();
context.moveTo(points[0].x, points[0].y);
for (var i = 0; i < points.length; i++) {
var p = points[i];
var nextP = points[i + 1];
var val = 30*0.552284749831;
if (nextP != undefined) {
// if (nextP.ix > p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y-val;
// p.cx2 = nextP.x-val;
// p.cy2 = nextP.y;
// } else if (nextP.ix > p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x+val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y-val;
// } else if (nextP.ix < p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y+val;
// p.cx2 = nextP.x+val;
// p.cy2 = nextP.y;
// } else if (nextP.ix < p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x-val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y+val;
// } else {
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
p.cx2 = (p.x+nextP.x)/2;
p.cy2 = (p.y+nextP.y)/2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
// continue;
// }
// context.bezierCurveTo(p.cx1, p.cy1, p.cx2, p.cy2, nextP.x, nextP.y);
} else {
nextP = points[0];
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
}
}
// context.closePath();
context.fill();
}
if (showIndicators) {
// Draw points
context.fillStyle = '#000';
context.beginPath();
for (var i = 0; i < pointsA.length; i++) {
var p = pointsA[i];
context.rect(p.x - 1, p.y - 1, 2, 2);
}
context.fill();
// Draw controls
context.fillStyle = '#f00';
context.beginPath();
for (var i = 0; i < pointsA.length; i++) {
var p = pointsA[i];
context.rect(p.cx1 - 1, p.cy1 - 1, 2, 2);
context.rect(p.cx2 - 1, p.cy2 - 1, 2, 2);
}
context.fill();
}
}
function renderCanvas2() {
// rAF
rafID = requestAnimationFrame(renderCanvas2);
// Clear scene
context2.clearRect(0, 0, $canvas2.width(), $canvas2.height());
context2.fillStyle = '#fff';
context2.fillRect(0, 0, $canvas2.width(), $canvas2.height());
// Move points
for (var i = 0; i <= pointsA2.length - 1; i++) {
pointsA2[i].move();
pointsB2[i].move();
}
// Create dynamic gradient
var gradientX = Math.min(Math.max(mouseX2 - $canvas2.offset().left, 0), $canvas2.width());
var gradientY = Math.min(Math.max(mouseY2 - $canvas2.offset().top, 0), $canvas2.height());
var distance = Math.sqrt(Math.pow(gradientX - $canvas2.width()/2, 2) + Math.pow(gradientY - $canvas2.height()/2, 2)) / Math.sqrt(Math.pow($canvas2.width()/2, 2) + Math.pow($canvas2.height()/2, 2));
var gradient = context2.createRadialGradient(gradientX, gradientY, 300+(300*distance), gradientX, gradientY, 0);
gradient.addColorStop(0, '#102ce5');
gradient.addColorStop(1, '#E406D6');
// Draw shapes
var groups = [pointsA2, pointsB2]
for (var j = 0; j <= 1; j++) {
var points = groups[j];
if (j == 0) {
// Background style
context2.fillStyle = '#1CE2D8';
} else {
// Foreground style
context2.fillStyle = gradient;
}
context2.beginPath();
context2.moveTo(points[0].x, points[0].y);
for (var i = 0; i < points.length; i++) {
var p = points[i];
var nextP = points[i + 1];
var val = 30*0.552284749831;
if (nextP != undefined) {
// if (nextP.ix > p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y-val;
// p.cx2 = nextP.x-val;
// p.cy2 = nextP.y;
// } else if (nextP.ix > p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x+val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y-val;
// } else if (nextP.ix < p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y+val;
// p.cx2 = nextP.x+val;
// p.cy2 = nextP.y;
// } else if (nextP.ix < p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x-val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y+val;
// } else {
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
p.cx2 = (p.x+nextP.x)/2;
p.cy2 = (p.y+nextP.y)/2;
context2.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
// continue;
// }
// context.bezierCurveTo(p.cx1, p.cy1, p.cx2, p.cy2, nextP.x, nextP.y);
} else {
nextP = points[0];
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
context2.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
}
}
// context.closePath();
context2.fill();
}
if (showIndicators2) {
// Draw points
context2.fillStyle = '#000';
context2.beginPath();
for (var i = 0; i < pointsA2.length; i++) {
var p = pointsA2[i];
context2.rect(p.x - 1, p.y - 1, 2, 2);
}
context2.fill();
// Draw controls
context2.fillStyle = '#f00';
context2.beginPath();
for (var i = 0; i < pointsA2.length; i++) {
var p = pointsA2[i];
context2.rect(p.cx1 - 1, p.cy1 - 1, 2, 2);
context2.rect(p.cx2 - 1, p.cy2 - 1, 2, 2);
}
context2.fill();
}
}
// Init
initButton();
initButton2();
});
body {
display: flex;
height: 100vh;
align-items: center;
justify-content: center;
}
.btn-liquid, .btn-liquid-2 {
display: inline-block;
position: relative;
width: 240px;
height: 60px;
border-radius: 27px;
color: #fff;
font: 700 14px/60px "Droid Sans", sans-serif;
letter-spacing: 0.05em;
text-align: center;
text-decoration: none;
text-transform: uppercase;
}
.btn-liquid .inner, .btn-liquid-2 .inner {
position: relative;
z-index: 2;
}
.btn-liquid canvas, .btn-liquid-2 canvas {
position: absolute;
top: -50px;
right: -50px;
bottom: -50px;
left: -50px;
z-index: 1;
}
.btn-grid{width: 50%;padding: 0 50px}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</head>
<body>
<div class="btn-grid btn-grid-1">
<a href="http://waaark.com" class="btn-liquid">
<span class="inner">Liquid button ?</span>
</a>
</div>
<div class="btn-grid btn-grid-2">
<a href="http://waaark.com" class="btn-liquid-2">
<span class="inner">Liquid button ?</span>
</a>
</div>
</body>
</html>

Related

Removing lag on rendering thousands of entities in JS canvas

I am a beginner in JS canvas. I wanna make a game but when rendering too many (Bricks) the game becomes unplayable. Most of the lag comes from draw function the part where bricks are drawn, From ctx.fill() and ctx.rect() function. I observed it with the chrome's performance devtool.
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 10;
var x = canvas.width / 2;
var y = canvas.height - ballRadius;
var bulletX = x;
var bulletY = y;
var bullet2X = x;
var bullet2Y = y;
var dx = 2;
var dy = -2;
var paddleHeight = 0;
var paddleWidth = canvas.width;
var paddleX = (canvas.width - paddleWidth) / 2;
var rightPressed = false;
var leftPressed = false;
var brickRowCount = 50;
var brickColumnCount = 96;
var brickWidth = 5;
var brickHeight = 5;
var brickPadding = 0;
var brickOffsetTop = 0;
var brickOffsetLeft = 0;
var score = 0;
var damageDealth = 0;
var brickHealth = 1000;
var scoreEarned = 0;
window.bricks = [];
if (bricks.length == 0) {
bricks = [];
for (var c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (var r = 0; r < brickRowCount; r++) {
bricks[c][r] = {
x: 0,
y: 0,
status: brickHealth
};
}
}
}
var resetLevel =
setInterval(() => {
var brickStatus = 0;
for (var row = 0; row < bricks.length; row++) {
bricks[row].forEach((status) => {
if (status.status > 1) {
brickStatus += 1;
}
})
}
if (brickStatus < 1) {
for (var row = 0; row < bricks.length; row++) {
for (var brick = 0; brick < bricks[row].length; brick++) {
if (bricks[row][brick].status < 1) {
brickHealth += 1;
bricks[row][brick].status = 1000
allBullets = [];
childBullets = [];
AOEBullets = [];
}
}
}
}
console.log(brickStatus);
console.log("BrickHealth: " + brickHealth)
}, 1000);
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if (e.key == "Right" || e.key == "ArrowRight" || e.key == "d") {
rightPressed = true;
} else if (e.key == "Left" || e.key == "ArrowLeft" || e.key == "a") {
leftPressed = true;
}
}
function keyUpHandler(e) {
if (e.key == "Right" || e.key == "ArrowRight" || e.key == "d") {
rightPressed = false;
} else if (e.key == "Left" || e.key == "ArrowLeft" || e.key == "a") {
leftPressed = false;
}
}
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
class MakeBullet {
constructor(x, y, radius, color, speedX, speedY, pierce, lifespan, damage) {
this.x = x;
this.y = y;
this.speedX = speedX;
this.speedY = speedY;
this.radius = radius;
this.color = color;
this.pierce = pierce;
this.lifespan = lifespan;
this.damage = damage;
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
}
update() {
this.draw();
this.x = this.x + this.speedX;
this.y = this.y + this.speedY;
}
}
window.allBullets = [];
window.childBullets = [];
window.AOEBullets = [];
document.addEventListener("mousemove", (event) => {
const angle = Math.atan2(event.clientY - y, event.clientX - x);
window.shootAngle = {
x: Math.cos(angle),
y: Math.sin(angle)
}
})
setInterval(() => {
if (allBullets.length < 101) {
allBullets.push(new MakeBullet(x, y, 3, "rgba(0, 149, 221, 0.9)", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 8, 2, 25))
/* allBullets.push(new MakeBullet(x - 5, y, 3, "rgba(0, 149, 221, 0.9)", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 8, 8, 50))
allBullets.push(new MakeBullet(x + 5, y, 3, "rgba(0, 149, 221, 0.9)", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 8, 8, 25)) */
}
}, 75)
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawBricks() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
if (bricks[c][r].status > 0) {
var brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft;
var brickY = (r * (brickHeight + brickPadding)) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
}
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPaddle();
childBullets.forEach((childBullet) => {
if (childBullet.lifespan > 0) {
childBullet.update();
childBullet.draw();
if (childBullet.x + childBullet.speedX > canvas.width - childBullet.radius || childBullet.x + childBullet.speedX < childBullet.radius) {
childBullet.speedX = -childBullet.speedX;
}
if (childBullet.y + childBullet.speedY > canvas.width - childBullet.radius || childBullet.y + childBullet.speedY < childBullet.radius) {
childBullet.speedY = -childBullet.speedY;
} else if (childBullet.y + childBullet.speedY > canvas.height - childBullet.radius) {
if (childBullet.x > paddleX && childBullet.x < paddleX + paddleWidth) {
if (childBullet.y = childBullet.y - paddleHeight) {
childBullet.speedY = -childBullet.speedY;
}
}
}
}
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status > 0) {
if (childBullet.x > b.x && childBullet.x < b.x + brickWidth && childBullet.y > b.y && childBullet.y < b.y + brickHeight) {
b.status -= childBullet.damage;
childBullet.pierce -= 1
var randomScore = Math.floor(Math.random() * 5);
score += randomScore;
scoreEarned += randomScore;
damageDealth += childBullet.damage;
}
}
}
}
})
AOEBullets.forEach((AOEBullet) => {
if (AOEBullet.lifespan > 0) {
AOEBullet.update();
AOEBullet.draw();
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status > 0) {
if (AOEBullet.x + AOEBullet.radius > b.x + brickWidth && AOEBullet.x - AOEBullet.radius < b.x + brickWidth && AOEBullet.y + AOEBullet.radius > b.y + brickHeight && AOEBullet.y - AOEBullet.radius < b.y + brickHeight) {
b.status -= AOEBullet.damage;
AOEBullet.pierce -= 1
var randomScore = Math.floor(Math.random() * 10);
score += randomScore;
scoreEarned += randomScore;
damageDealth += AOEBullet.damage;
}
}
}
}
}
})
if (shootAngle !== undefined) {
allBullets.forEach((bullet) => {
if (bullet.lifespan > 0) {
if (bullet.pierce > 0) {
bullet.update();
bullet.draw();
window.BulletX = bullet.x;
window.BulletY = bullet.y;
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status > 0) {
if (bullet.x > b.x && bullet.x < b.x + brickWidth && bullet.y > b.y && bullet.y < b.y + brickHeight) {
b.status -= bullet.damage;
bullet.pierce -= 1;
var randomScore = Math.floor(Math.random() * 100);
score += randomScore;
scoreEarned += randomScore;
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 25, "rgba(0,149,221, 0.024)", 0, 0, 5, 0.4, 1.4))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 50, "rgba(0,149,221, 0.018)", 0, 0, 5, 0.3, 0.7))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 75, "rgba(0,149,221, 0.016)", 0, 0, 5, 0.2, 0.5))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 100, "rgba(0,149,221, 0.012)", 0, 0, 5, 0.1, 0.2))
damageDealth += bullet.damage;
}
if (bullet.x > b.x && bullet.x < b.x + brickWidth && bullet.y > b.y && bullet.y < b.y + brickHeight) {
b.status -= bullet.damage;
}
if (bullet.x > b.x && bullet.x < b.x + brickWidth && bullet.y > b.y && bullet.y < b.y + brickHeight) {
b.status -= bullet.damage;
}
if (bullet.x > b.x && bullet.x < b.x + brickWidth && bullet.y > b.y && bullet.y < b.y + brickHeight) {
b.status -= bullet.damage;
}
}
}
}
if (bullet.x + bullet.speedX > canvas.width - bullet.radius || bullet.x + bullet.speedX < bullet.radius) {
bullet.speedX = -bullet.speedX;
}
if (bullet.y + bullet.speedY > canvas.width - bullet.radius || bullet.y + bullet.speedY < bullet.radius) {
bullet.speedY = -bullet.speedY;
} else if (bullet.y + bullet.speedY > canvas.height - bullet.radius) {
if (bullet.x > paddleX && bullet.x < paddleX + paddleWidth) {
if (bullet.y = bullet.y - paddleHeight) {
bullet.speedY = -bullet.speedY;
}
}
}
}
}
})
}
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if (y + dy < ballRadius) {
dy = -dy;
} else if (y + dy > canvas.height - ballRadius) {
if (x > paddleX && x < paddleX + paddleWidth) {
if (y = y - paddleHeight) {
dy = -dy;
}
} else {
document.location.reload();
clearInterval(interval); // Needed for Chrome to end game
}
}
if (rightPressed && x < canvas.width - ballRadius) {
x += 7;
} else if (leftPressed && x > 0 + ballRadius) {
x -= 7;
}
// x += dx;
//y += dy;
}
var interval = setInterval(draw, 10);
setInterval(() => {
allBullets.forEach((bullet) => {
for (var i = 0; i < 1; i++) {
var angle = 2 * Math.PI * Math.random();
var randomx = bullet.speedX * Math.cos(angle);
var randomy = bullet.speedY * Math.sin(angle);
if (bullet.lifespan < 1) {
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 25, "rgba(0,149,221, 0.024)", 0, 0, 5, 0.4, 0.24))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 50, "rgba(0,149,221, 0.018)", 0, 0, 5, 0.3, 0.16))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 75, "rgba(0,149,221, 0.016)", 0, 0, 5, 0.2, 0.08))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 100, "rgba(0,149,221, 0.012)", 0, 0, 5, 0.1, 0.04))
if (childBullets.length < 51) {
childBullets.push(new MakeBullet(bullet.x, bullet.y, 2, "#0095DD", randomx + randomx * Math.floor(Math.random() * 2), randomy + randomy * Math.floor(Math.random() * 2), 5, 5, 1))
}
}
if (bullet.pierce < 1) {
if (childBullets.length < 51) {
childBullets.push(new MakeBullet(bullet.x, bullet.y, 2, "#0095DD", randomx + randomx * Math.floor(Math.random() * 5), randomy + randomy * Math.floor(Math.random() * 5), 5, 5, 1))
}
}
}
})
}, 1)
var lifeSpan = setInterval(() => {
allBullets.forEach((bullet) => {
bullet.lifespan -= 0.1;
})
childBullets.forEach((bullet) => {
bullet.lifespan -= 0.1;
})
AOEBullets.forEach((bullet) => {
bullet.lifespan -= 0.1;
})
}, 100)
setInterval(() => {
for (var i = 0; i < allBullets.length; i++) {
if (allBullets[i].pierce < 1 || allBullets[i].lifespan < 1) {
allBullets.splice(allBullets.indexOf[i], 1)
}
}
}, 50)
setInterval(() => {
for (var i = 0; i < childBullets.length; i++) {
if (childBullets[i].pierce < 1 || childBullets[i].lifespan < 0) {
childBullets.splice(childBullets.indexOf[i], 1)
}
}
}, 5000)
setInterval(() => {
for (var i = 0; i < AOEBullets.length; i++) {
if (AOEBullets[i].pierce < 1 || AOEBullets[i].lifespan < 0) {
AOEBullets.splice(AOEBullets.indexOf[i], 1)
}
}
}, 5000)
setInterval(() => {
for (var i = 0; i < 8; i++) {
allBullets.push(new MakeBullet(x, y, 10, "#0095DD", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 10, 3, 5))
allBullets.push(new MakeBullet(x + 10, y, 10, "#0095DD", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 10, 3, 5))
allBullets.push(new MakeBullet(x - 10, y, 10, "#0095DD", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 10, 3, 5))
}
}, 30000)
setInterval(() => {
document.getElementsByClassName("scrore")[0].innerText = "Score: " + score;
}, 100)
setInterval(() => {
document.getElementsByClassName("scoreEarned")[0].innerText = "Score Earned: " + scoreEarned;
scoreEarned = 0;
}, 1000)
var damage = setInterval(() => {
document.getElementsByClassName("damageDealth")[0].innerText = "Damage: " + damageDealth.toFixed(1);
damageDealth = 0;
}, 1000)
<canvas id="myCanvas" height="320" width="480" style="background-color: #eee"></canvas>
<p class="scrore" style="color: rgba(0, 149, 221, 0.9); font-family: 'Hammersmith One';">Score: 0</p>
<p class="scoreEarned" style="color: rgba(0, 149, 221, 0.9); font-family: 'Hammersmith One';">Score Earned: 0</p>
<p class="damageDealth" style="color: rgba(0, 149, 221, 0.9); font-family: 'Hammersmith One';">Damage: 0</p>
One idea to speed up the drawing is to prepare the next frame to be shown on an invisible canvas. Then blip the invisible canvas to the canvas shown to the player in one go.
// drawing surface
var visibleCanvas_; // (HTML5 canvas) serves as playfield, visible for user
var visibleCtx2d_; // (HTML5 canvas 2D context) context of visible canvas
// optimization: if drawing with fillRect(), draw on hidden canvas
var hiddenCanvas_; // (HTML5 canvas) invisible canvas on which shapes are drawn each step
var hiddenCtx2d_; // (HTML5 canvas 2D context) context of invisible canvas
function createHiddenCanvas_(mainCanvas) {
hiddenCanvas_= document.createElement("canvas");
hiddenCanvas_.width = mainCanvas.width;
hiddenCanvas_.height = mainCanvas.height;
hiddenCtx2d_= hiddenCanvas_.getContext("2d");
// other settings that do not change while drawing, e.g. brick color
// hiddenCtx2d_.strokeStyle = ...;
// hiddenCtx2d_.fillStyle = ...;
}
// must be called once at startup of the game
function init_() {
visibleCanvas_ = document.getElementById('myCanvas');
visibleCtx2d_= visibleCanvas_.getContext('2d');
createHiddenCanvas_(visibleCanvas_);
}
// to be called before we start building the next frame
function startDraw_() {
// clear hidden canvas
hiddenCtx2d_.clearRect(0, 0, hiddenCanvas_.width, hiddenCanvas_.height);
}
// draws single brick for next frame on hidden canvas
function drawBrick_(brickX, brickY, brickWidth, brickHeight) {
hiddenCtx2d_.fillRect(brickX, brickY, brickWidth, brickHeight);
}
// to be called after we finish building the next frame and want to display it
function finishDraw_() {
// clear visible canvas
visibleCtx2d_.clearRect(0, 0, visibleCanvas_.width, visibleCanvas_.height);
// blip hidden canvas on visible canvas
visibleCtx2d_.drawImage(hiddenCanvas_, 0, 0);
}
Draw all shapes for the next frame between startDraw_ and finishDraw_.
You should also look into window.requestAnimationFrame to manage when the next frame is drawn.

What's wrong with my rewrite from jquery to react

I try to rewrite this liquid button https://codepen.io/waaark/pen/VbgwEM , it use jquery.
I want to rewrite it for my react component, but don't know what is wrong:
here is the component code:
import React from "react";
import Link from "next/link";
import { useRef } from 'react';
import { useEffect } from 'react';
import { useState } from 'react';
const getPixelRatio = context => {
var backingStore =
context.backingStorePixelRatio ||
context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio ||
1;
return (window.devicePixelRatio || 1) / backingStore;
};
const useMove = () => {
let ref = useRef();
/* let msx = 0;
let msy = 0;
let mlx = 0;
let mly = 0; */
/* function mouseSpeed() {
msx = state.x - state.mouseLastXX;
msy = state.y - state.mouseLastYY;
mlx = state.x;
mly = state.y;
setTimeout(mouseSpeed, 50);
} */
const [state, setState] = useState({x: 0, y: 0, mouseDirectionXX:0, mouseDirectionYY:0, mouseSpeedXX:0, mouseSpeedYY:0, mouseLastXX:0, mouseLastYY:0})
const handleMouseMove = e => {
//e.persist()
let xx = state.mouseDirectionX;
let yy = state.mouseDirectionY;
//mouseSpeed();
if (state.x < e.clientX)
xx = 1;
else if (state.x > e.clientX)
xx = -1;
else
xx = 0;
if (state.y < e.clientY)
yy = 1;
else if (state.y > e.clientY)
yy = -1;
else
yy = 0;
//rx = (state.x - offset.left);
//ry = (state.y - offset.top);
setState(state => ({...state, x: e.clientX, y: e.clientY, mouseDirectionXX:xx, mouseDirectionYY:yy}))
//mouseX = e.clientX;
//mouseY = e.clientY;
//relMouseX = (mouseX - canvas.offsetLeft);
//relMouseY = (mouseY - canvas.offsetTop);
//console.log(xx + "///" + yy);
}
useEffect(() => {
window.addEventListener("mousemove", handleMouseMove);
return () => window.removeEventListener("mousemove", handleMouseMove);
}, []);
return {
mouseX: state.x,
mouseY: state.y,
mouseDirectionX: state.mouseDirectionXX,
mouseDirectionY: state.mouseDirectionYY,
mouseLastX: state.mouseLastXX,
mouseLastY: state.mouseLastYY,
mouseSpeedX: state.mouseSpeedXX,
mouseSpeedY: state.mouseSpeedYY,
//relMouseX: state.relMouseXX,
//relMouseY: state.relMouseYY,
handleMouseMove,
}
}
const LiquidButton = () => {
const {mouseX, mouseY, mouseDirectionX, mouseDirectionY, handleMouseMove} = useMove();
let ref = useRef();
let buttonWidth = 240;
let buttonHeight = 60;
let points = 8;
let pointsA = [], pointsB = [];
let viscosity = 10, mouseDist = 70, damping = 0.05, showIndicators = false;
let relMouseX = 0;
let relMouseY = 0;
//let canvas = ref.current;
/* function mouseSpeed() {
mouseSpeedX = mouseX - mouseLastX;
mouseSpeedY = mouseY - mouseLastY;
mouseLastX = mouseX;
mouseLastY = mouseY;
setTimeout(mouseSpeed, 50);
//console.log("AYE");
}
mouseSpeed(); */
useEffect(() => {
let canvas = ref.current;
let context = canvas.getContext('2d');
let canvaspos = canvas.getBoundingClientRect();
let offset = {
top: canvaspos.top,
left: canvaspos.left,
};
let mouseLastX = 0;
let mouseLastY = 0;
//mouseDirectionX = 0,
//mouseDirectionY = 0,
let mouseSpeedX = 0;
let mouseSpeedY = 0;
relMouseX = (mouseX - offset.left);
relMouseY = (mouseY - offset.top);
mouseSpeedX = mouseX - mouseLastX;
mouseSpeedY = mouseY - mouseLastY;
mouseLastX = mouseX;
mouseLastY = mouseY;
//NEW
console.log("mouseX:" + mouseX)
console.log("mouseLastX: "+ mouseLastX);
console.log("mouseSpeedX: "+ mouseSpeedX);
console.log("relMouseX:" + relMouseX)
console.log("mouseDirectionX: "+ mouseDirectionX);
console.log("mouseY:" + mouseY)
console.log("mouseLastY: "+ mouseLastY);
console.log("mouseSpeedY: "+ mouseSpeedY);
console.log("relMouseY:" + relMouseY)
console.log("mouseDirectionY: "+ mouseDirectionY);
function Point(x, y, level) {
this.x = this.ix = 75+x;
this.y = this.iy = 75+y;
this.vx = 0;
this.vy = 0;
this.cx1 = 0;
this.cy1 = 0;
this.cx2 = 0;
this.cy2 = 0;
this.level = level;
}
Point.prototype.move = function() {
this.vx += (this.ix - this.x) / (viscosity*this.level);
this.vy += (this.iy - this.y) / (viscosity*this.level);
var dx = this.ix - relMouseX,
dy = this.iy - relMouseY;
var relDist = (1-Math.sqrt((dx * dx) + (dy * dy))/mouseDist);
// Move x
if ((mouseDirectionX > 0 && relMouseX > this.x) || (mouseDirectionX < 0 && relMouseX < this.x)) {
if (relDist > 0 && relDist < 1) {
this.vx = (mouseSpeedX / 4) * relDist;
}
}
this.vx *= (1 - damping);
this.x += this.vx;
// Move y
if ((mouseDirectionY > 0 && relMouseY > this.y) || (mouseDirectionY < 0 && relMouseY < this.y)) {
if (relDist > 0 && relDist < 1) {
this.vy = (mouseSpeedY / 4) * relDist;
}
}
this.vy *= (1 - damping);
this.y += this.vy;
};
function addPoints(x, y) {
pointsA.push(new Point(x, y, 1));
pointsB.push(new Point(x, y, 2));
}
//NEW-END
let ratio = getPixelRatio(context);
let width = getComputedStyle(canvas)
.getPropertyValue('width')
.slice(0, -2);
let height = getComputedStyle(canvas)
.getPropertyValue('height')
.slice(0, -2);
canvas.width = buttonWidth+150;
canvas.height = buttonHeight+150;
//canvas.width = width * ratio;
//canvas.height = height * ratio;
canvas.style.width = width+`px`;
canvas.style.height = height+`px`;
let x = buttonHeight/2;
for(var j = 1; j < points; j++) {
addPoints((x+((buttonWidth-buttonHeight)/points)*j), 0);
}
addPoints(buttonWidth-buttonHeight/5, 0);
addPoints(buttonWidth+buttonHeight/10, buttonHeight/2);
addPoints(buttonWidth-buttonHeight/5, buttonHeight);
for(var j = points-1; j > 0; j--) {
addPoints((x+((buttonWidth-buttonHeight)/points)*j), buttonHeight);
}
addPoints(buttonHeight/5, buttonHeight);
addPoints(-buttonHeight/10, buttonHeight/2);
addPoints(buttonHeight/5, 0);
let requestId, i = 0;
const render = () => {
// Clear scene
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = "rgba(0, 0, 200, 0.0)";
context.fillRect(0, 0, canvas.width, canvas.height);
// Move points
for (var i = 0; i <= pointsA.length - 1; i++) {
pointsA[i].move();
pointsB[i].move();
}
// Create dynamic gradient
var gradientX = Math.min(Math.max(mouseX - offset.left, 0), canvas.width);
var gradientY = Math.min(Math.max(mouseY - offset.top, 0), canvas.height);
var distance = Math.sqrt(Math.pow(gradientX - canvas.width/2, 2) + Math.pow(gradientY - canvas.height/2, 2)) / Math.sqrt(Math.pow(canvas.width/2, 2) + Math.pow(canvas.height/2, 2));
var gradient = context.createRadialGradient(gradientX, gradientY, 300+(300*distance), gradientX, gradientY, 0);
gradient.addColorStop(0, '#102ce5');
gradient.addColorStop(1, '#E406D6');
// Draw shapes
var groups = [pointsA, pointsB]
for (var j = 0; j <= 1; j++) {
var points = groups[j];
if (j == 0) {
// Background style
context.fillStyle = '#1CE2D8';
} else {
// Foreground style
context.fillStyle = gradient;
}
context.beginPath();
context.moveTo(points[0].x, points[0].y);
for (var i = 0; i < points.length; i++) {
var p = points[i];
var nextP = points[i + 1];
var val = 30*0.552284749831;
if (nextP != undefined) {
// if (nextP.ix > p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y-val;
// p.cx2 = nextP.x-val;
// p.cy2 = nextP.y;
// } else if (nextP.ix > p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x+val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y-val;
// } else if (nextP.ix < p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y+val;
// p.cx2 = nextP.x+val;
// p.cy2 = nextP.y;
// } else if (nextP.ix < p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x-val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y+val;
// } else {
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
p.cx2 = (p.x+nextP.x)/2;
p.cy2 = (p.y+nextP.y)/2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
// continue;
// }
// context.bezierCurveTo(p.cx1, p.cy1, p.cx2, p.cy2, nextP.x, nextP.y);
} else {
nextP = points[0];
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
}
}
// context.closePath();
context.fill();
}
if (showIndicators) {
// Draw points
context.fillStyle = '#000';
context.beginPath();
for (var i = 0; i < pointsA.length; i++) {
var p = pointsA[i];
context.rect(p.x - 1, p.y - 1, 2, 2);
}
context.fill();
// Draw controls
context.fillStyle = '#f00';
context.beginPath();
for (var i = 0; i < pointsA.length; i++) {
var p = pointsA[i];
context.rect(p.cx1 - 1, p.cy1 - 1, 2, 2);
context.rect(p.cx2 - 1, p.cy2 - 1, 2, 2);
}
context.fill();
}
requestId = requestAnimationFrame(render);
};
render();
return () => {
cancelAnimationFrame(requestId);
};
});
return (
<div>
<canvas ref={ref} style={{ width: '390px', height: '210px' }} >
<a href="#" className="btn-liquid">
<span className="inner">Press Button</span>
</a>
</canvas>
<div className="mouseArea">
Hook
<div className="mouseInfo">
The current mouse position is ({mouseX}, {mouseY}) <br />
Mouse Direction is ({mouseDirectionX}, {mouseDirectionY}) <br />
{/* Mouse Last ({mouseLastX}, {mouseLastY}) <br /> */}
{/* Mouse Speed ({mouseSpeedX}, {mouseSpeedY}) <br /> */}
</div>
</div>
</div>
);
};
export default LiquidButton;
i tried to calculate the mouse speed and mouse direction, but still confuse where to put the code.When I console log the value, the mouse position, mouse speed and mouse last position are the same value
How about this?
let pointsA = [];
let pointsB = [];
let $canvas = null;
let canvas = null;
let context = null;
// let vars = null;
let points = 8;
let viscosity = 20;
let mouseDist = 70;
let damping = 0.05;
let showIndicators = false;
let mouseX = 0;
let mouseY = 0;
let relMouseX = 0;
let relMouseY = 0;
let mouseLastX = 0;
let mouseLastY = 0;
let mouseDirectionX = 0;
let mouseDirectionY = 0;
let mouseSpeedX = 0;
let mouseSpeedY = 0;
function mouseDirection(e) {
if (mouseX < e.pageX)
mouseDirectionX = 1;
else if (mouseX > e.pageX)
mouseDirectionX = -1;
else
mouseDirectionX = 0;
if (mouseY < e.pageY)
mouseDirectionY = 1;
else if (mouseY > e.pageY)
mouseDirectionY = -1;
else
mouseDirectionY = 0;
mouseX = e.pageX;
mouseY = e.pageY;
relMouseX = (mouseX - $canvas.offset().left);
relMouseY = (mouseY - $canvas.offset().top);
}
function mouseSpeed() {
mouseSpeedX = mouseX - mouseLastX;
mouseSpeedY = mouseY - mouseLastY;
mouseLastX = mouseX;
mouseLastY = mouseY;
setTimeout(mouseSpeed, 50);
}
mouseSpeed();
function initButton(button) {
// Get button
// var button = $('.btn-liquid');
var buttonWidth = button.width();
var buttonHeight = button.height();
// Create canvas
$canvas = $('<canvas></canvas>');
button.append($canvas);
canvas = $canvas.get(0);
canvas.width = buttonWidth + 100;
canvas.height = buttonHeight + 100;
context = canvas.getContext('2d');
// Add points
var x = buttonHeight / 2;
for (let j = 1; j < points; j++) {
addPoints((x + ((buttonWidth - buttonHeight) / points) * j), 0);
}
addPoints(buttonWidth - buttonHeight / 5, 0);
addPoints(buttonWidth + buttonHeight / 10, buttonHeight / 2);
addPoints(buttonWidth - buttonHeight / 5, buttonHeight);
for (let j = points - 1; j > 0; j--) {
addPoints((x + ((buttonWidth - buttonHeight) / points) * j), buttonHeight);
}
addPoints(buttonHeight / 5, buttonHeight);
addPoints(-buttonHeight / 10, buttonHeight / 2);
addPoints(buttonHeight / 5, 0);
// addPoints(x, 0);
// addPoints(0, buttonHeight/2);
// addPoints(0, buttonHeight/2);
// addPoints(buttonHeight/4, 0);
// Start render
renderCanvas();
}
function addPoints(x, y) {
pointsA.push(new Point(x, y, 1));
pointsB.push(new Point(x, y, 2));
}
function Point(x, y, level) {
this.x = this.ix = 50 + x;
this.y = this.iy = 50 + y;
this.vx = 0;
this.vy = 0;
this.cx1 = 0;
this.cy1 = 0;
this.cx2 = 0;
this.cy2 = 0;
this.level = level;
}
Point.prototype.move = function() {
this.vx += (this.ix - this.x) / (viscosity * this.level);
this.vy += (this.iy - this.y) / (viscosity * this.level);
var dx = this.ix - relMouseX,
dy = this.iy - relMouseY;
var relDist = (1 - Math.sqrt((dx * dx) + (dy * dy)) / mouseDist);
// Move x
if ((mouseDirectionX > 0 && relMouseX > this.x) || (mouseDirectionX < 0 && relMouseX < this.x)) {
if (relDist > 0 && relDist < 1) {
this.vx = (mouseSpeedX / 4) * relDist;
}
}
this.vx *= (1 - damping);
this.x += this.vx;
// Move y
if ((mouseDirectionY > 0 && relMouseY > this.y) || (mouseDirectionY < 0 && relMouseY < this.y)) {
if (relDist > 0 && relDist < 1) {
this.vy = (mouseSpeedY / 4) * relDist;
}
}
this.vy *= (1 - damping);
this.y += this.vy;
};
function renderCanvas() {
// rAF
// rafID =
requestAnimationFrame(renderCanvas);
// Clear scene
context.clearRect(0, 0, $canvas.width(), $canvas.height());
context.fillStyle = '#fff';
context.fillRect(0, 0, $canvas.width(), $canvas.height());
// Move points
for (var i = 0; i <= pointsA.length - 1; i++) {
pointsA[i].move();
pointsB[i].move();
}
// Create dynamic gradient
var gradientX = Math.min(Math.max(mouseX - $canvas.offset().left, 0), $canvas.width());
var gradientY = Math.min(Math.max(mouseY - $canvas.offset().top, 0), $canvas.height());
var distance = Math.sqrt(Math.pow(gradientX - $canvas.width() / 2, 2) + Math.pow(gradientY - $canvas.height() / 2, 2)) / Math.sqrt(Math.pow($canvas.width() / 2, 2) + Math.pow($canvas.height() / 2, 2));
var gradient = context.createRadialGradient(gradientX, gradientY, 300 + (300 * distance), gradientX, gradientY, 0);
gradient.addColorStop(0, '#102ce5');
gradient.addColorStop(1, '#E406D6');
// Draw shapes
var groups = [pointsA, pointsB]
for (var j = 0; j <= 1; j++) {
var points = groups[j];
if (j === 0) {
// Background style
context.fillStyle = '#1CE2D8';
} else {
// Foreground style
context.fillStyle = gradient;
}
context.beginPath();
context.moveTo(points[0].x, points[0].y);
for (let i = 0; i < points.length; i++) {
var p = points[i];
var nextP = points[i + 1];
// var val = 30*0.552284749831;
if (nextP !== undefined) {
// if (nextP.ix > p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y-val;
// p.cx2 = nextP.x-val;
// p.cy2 = nextP.y;
// } else if (nextP.ix > p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x+val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y-val;
// } else if (nextP.ix < p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y+val;
// p.cx2 = nextP.x+val;
// p.cy2 = nextP.y;
// } else if (nextP.ix < p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x-val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y+val;
// } else {
p.cx1 = (p.x + nextP.x) / 2;
p.cy1 = (p.y + nextP.y) / 2;
p.cx2 = (p.x + nextP.x) / 2;
p.cy2 = (p.y + nextP.y) / 2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
// continue;
// }
// context.bezierCurveTo(p.cx1, p.cy1, p.cx2, p.cy2, nextP.x, nextP.y);
} else {
nextP = points[0];
p.cx1 = (p.x + nextP.x) / 2;
p.cy1 = (p.y + nextP.y) / 2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
}
}
// context.closePath();
context.fill();
}
if (showIndicators) {
// Draw points
context.fillStyle = '#000';
context.beginPath();
for (let i = 0; i < pointsA.length; i++) {
// var p = pointsA[i];
context.rect(p.x - 1, p.y - 1, 2, 2);
}
context.fill();
// Draw controls
context.fillStyle = '#f00';
context.beginPath();
for (let i = 0; i < pointsA.length; i++) {
// var p = pointsA[i];
context.rect(p.cx1 - 1, p.cy1 - 1, 2, 2);
context.rect(p.cx2 - 1, p.cy2 - 1, 2, 2);
}
context.fill();
}
}
const StaticLiquidButton = ({
className,
liquidBtnRef,
href
}) => ( <
a href = {
href
}
className = "btn-liquid"
ref = {
liquidBtnRef
} >
<
span class = "inner" >
Liquid button ?
<
/span> <
/a>
);
StaticLiquidButton.propTypes = {
className: PropTypes.string.isRequired
};
const LiquidButton = () => {
const liquidBtnRef = React.useRef()
React.useEffect(() => {
const button = liquidBtnRef.current;
initButton($(button));
$(document).on('mousemove', mouseDirection);
return () => {
$(document).off('mousemove', mouseDirection)
}
},[])
return (
<StaticLiquidButton
className="TeslaAppUI-LiquidButton"
href="http://waaark.com"
liquidBtnRef={liquidBtnRef}
/>
)
}
function App() {
return ( <
div >
<
LiquidButton / >
<
/div>
);
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
body {
margin: 0;
display: flex;
height: 100vh;
align-items: center;
justify-content: center;
}
.btn-liquid {
display: inline-block;
position: relative;
width: 240px;
height: 60px;
border-radius: 27px;
color: #fff;
font: 700 14px/60px "Droid Sans", sans-serif;
letter-spacing: 0.05em;
text-align: center;
text-decoration: none;
text-transform: uppercase;
}
.btn-liquid .inner {
position: relative;
z-index: 2;
}
.btn-liquid canvas {
position: absolute;
top: -50px;
right: -50px;
bottom: -50px;
left: -50px;
z-index: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.7.2/prop-types.min.js" integrity="sha512-ssNhh7jlzc+K93ckIlSXFHHz6fSFv0l619WOv8xbFNRbFOujbasb42LVMOggDrQR1ScJncoWb+KAJx1uF3ipjw==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Good Luck...

Startscreen on Javascript Game / Clickable Play button

I'm in the middle of making a start-screen for my JavaScript Breakout game. I've (poorly) made the background and a play button.
The background is inside the canvas, which I want. But when I want to place the clickable play button ontop of the background in the canvas, it disappears. I've tried making another picture, and I can place that ontop, I just cant make it clickable.
I dont know what the best solution is, I'm very new to JavaScript.
//Script
var background = new Image();
background.src="breakoutbg.png";
var play = new Image();
play.src="breaoutplay.png";
var startBtn = document.getElementById('startBtn');
//game
function drawCanvas() {
ctx.beginPath();
ctx.drawImage(background,0,0);
ctx.fill();
ctx.closePath();
}
function drawPlay() {
ctx.beginPath();
ctx.drawImage(play,250,250);
ctx.fill();clickable;
ctx.closePath();
}
<div id="container">
<button type="button" id="startBtn" onclick="draw()" >
<img src="breaoutplay.png">
</button>
<canvas id="myCanvas" width="600" height="550"></canvas>
</div>
I dont know if I gave enough of the code, for someone to have an Idea about it. The entire code is on github: https://github.com/katrinemira/katrinemira.github.io/blob/master/breakout.html
Add this to ur CSS
#container {
display: inline-block;
position: relative;
}
#startBtn {
border: none;
background: none;
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
transform: translate(-50%,-50%);
-webkit-transform: translate(-50%,-50%);
-moz-transform: translate(-50%,-50%);
-ms-transform: translate(-50%,-50%);
}
The above code will place the button on the canvas in the center.
Also add z-index: 1; to the button to place it on top of canvas
<html>
<head>
<center>
<style>
body {
background-color: black;
}
* {
padding: 0;
margin: 0;
}
canvas {
background: #353d49;
display: block;
margin: 100px;
}
#startBtn {
border: none;
background: none;
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
transform: translate(-50%,-50%);
-webkit-transform: translate(-50%,-50%);
-moz-transform: translate(-50%,-50%);
-ms-transform: translate(-50%,-50%);
}
#container {
display: inline-block;
position: relative;
}
#myCanvas {
position: relative;
}
</style>
</head>
<body>
<div id="container">
<button type="button" id="startBtn" onclick="draw()"><img src="https://1.bp.blogspot.com/-fVAKH-3TLuo/W5onDDHje0I/AAAAAAAAB4I/q2ooE6GuzQkS80dtw1JILXjFWdfQ3IKkwCLcBGAs/s1600/breaoutplay.png">
</button>
<canvas id="myCanvas" width="600" height="550"></canvas>
</div>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 9;
var x = canvas.width - Math.floor(Math.random() * 600)
var y = canvas.height - 30;
var dx = 5;
var dy = -4;
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width - paddleWidth) / 2;
var rightPressed = false;
var leftPressed = false;
var brickRowCount = 7;
var brickColumnCount = 5;
var brickWidth = 75;
var brickHeight = 20;
var brickPadding = 4;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var score = 0;
var lives = 3;
var background = new Image();
background.src = "https://1.bp.blogspot.com/-hs2fckXJBkE/W5obuBm9kII/AAAAAAAAB38/C89KFBJCIlEwfl-g8d-T1Cu4cHFWjYI2QCLcBGAs/s1600/breakoutbg.png";
var play = new Image();
play.src = "https://1.bp.blogspot.com/-fVAKH-3TLuo/W5onDDHje0I/AAAAAAAAB4I/q2ooE6GuzQkS80dtw1JILXjFWdfQ3IKkwCLcBGAs/s1600/breaoutplay.png";
var startBtn = document.getElementById('startBtn');
//game
function drawCanvas() {
ctx.beginPath();
ctx.drawImage(background, 0, 0);
ctx.fill();
ctx.closePath();
}
function drawPlay() {
ctx.beginPath();
ctx.drawImage(play, 250, 250);
ctx.fill();
clickable;
ctx.closePath();
}
function newBrick() {
return {
x: 0,
y: 0,
status: 1
};
}
var bricks = [];
for (var c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (var r = 0; r < brickRowCount; r++) {
bricks[c].unshift(newBrick());
}
}
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
document.addEventListener("mousemove", mouseMoveHandler, false);
function keyDownHandler(e) {
if (e.keyCode == 39) {
rightPressed = true;
} else if (e.keyCode == 37) {
leftPressed = true;
}
}
function keyUpHandler(e) {
if (e.keyCode == 39) {
rightPressed = false;
} else if (e.keyCode == 37) {
leftPressed = false;
}
}
function mouseMoveHandler(e) {
var relativeX = e.clientX - canvas.offsetLeft;
if (relativeX > 0 && relativeX < canvas.width) {
paddleX = relativeX - paddleWidth / 2;
}
}
function collisionDetection() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status == 1) {
if (x > b.x && x < b.x + brickWidth + ballRadius && y > b.y && y < b.y + brickHeight + ballRadius) {
dy = -dy;
b.status = 0;
score++;
if (score == 9999) {
alert("YOU WIN, CONGRATS!");
document.location.reload();
}
}
}
}
}
}
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function moreBricks() {
bricks.unshift([]);
newBrick();
brickColumnCount++;
for (r = 0; r < brickRowCount; r++) {
bricks[0].unshift(newBrick());
}
}
function drawBricks() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
if (bricks[c][r].status == 1) {
var brickX = (r * (brickWidth + brickPadding)) + brickOffsetLeft;
var brickY = (c * (brickHeight + brickPadding)) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
}
}
}
function drawScore() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Score: " + score, 8, 20);
}
function drawLives() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Lives: " + lives, canvas.width - 65, 20);
}
var frameCount = 0;
const FRAME_COUNT_NEW_LINE = 500;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
startBtn.style.display = 'none';
frameCount += 1;
if (frameCount === FRAME_COUNT_NEW_LINE) {
frameCount = 0;
moreBricks();
}
drawBricks();
drawBall();
drawPaddle();
drawScore();
drawLives();
collisionDetection();
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if (y + dy < ballRadius) {
dy = -dy;
} else if (y + dy > canvas.height - ballRadius) {
if (x > paddleX && x < paddleX + paddleWidth) {
dy = -dy;
} else {
lives--;
if (!lives) {
document.location.reload();
} else {
x = canvas.width - Math.floor(Math.random() * 600);
y = canvas.height - 30;
dx = 5;
dy = -4;
paddleX = (canvas.width - paddleWidth) / 2;
}
}
}
if (rightPressed && paddleX < canvas.width - paddleWidth) {
paddleX += 7;
} else if (leftPressed && paddleX > 0) {
paddleX -= 7;
}
x += dx;
y += dy;
requestAnimationFrame(draw);
}
drawCanvas();
drawPlay();
</script>
</body>
</html>

how can I detect collision in a 2D tile game map

I made this basic game where I drew a map and a player, the player can move anywhere but how can I make so that it wont move when its on the tile[1] in the map?
also when I try to check if the player.x is greater than 50 it could go left it works but than if I click 2 keys at once it goes through
const context = document.querySelector("canvas").getContext("2d");
var rgb = 'rgb(' + Math.random()*256 + ',' + Math.random()*256 + ',' + Math.random()*256 + ','+Math.random() + ')';
document.onload = Loop();
var width = 1500;
var height = 800;
function Loop(){
var width = 1500;
var height = 800;
context.canvas.height = height;
context.canvas.width = width;
this.interval = setInterval(Update, 1000/100);
}
const Player = function(x, y, w, h, color) {
this.x = x; this.y = y; this.w = w; this.h = h;
this.speedY = 0; this.speedX = 0;
this.Draw = function(){
context.fillStyle = this.color;
context.fillRect(this.x, this.y, this.w, this.h);
};
this.Move = function(){
this.x += this.speedX;
this.y += this.speedY;
};
};<code>
var player = new Player(100,100,50, 50, rgb);
var Key = {};
function Update(){
context.clearRect(0, 0, width, height);
Map();
player.Draw();
player.Move();
onkeydown = onkeyup = function(e){
player.speedX = 0;
player.speedY = 0;
e = e || event;
Key[e.keyCode] = e.type == 'keydown';
if(Key[37] || Key[65]) {player.speedX -= 2}
if(Key[38] || Key[87]) {player.speedY -= 2}
if(Key[39] || Key[68]) {player.speedX += 2}
if(Key[40] || Key[83]) {player.speedY += 2}
if(Key[32]) {player.color = 'rgb(' + Math.random()*256 + ',' + Math.random()*256 + ',' + Math.random()*256 + ','+Math.random()*1 + ')';}
};
}
var map = [
1, 1, 1, 1, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 1, 1, 1, 1
];
var row = 5;
var column = 5;
function Map(){
for(let y = -1; y < column; y++){
for(let x = -1; x < row; x++){
switch(map[((y*row) + x)]) {
case 0: context.fillStyle = player.color;
break;
case 1: context.fillStyle = "#ffffff";
break;
default: context.fillStyle = "#000000";
}
context.fillRect(x*50, y*50, 50, 50);
}
}
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}
canvas {
display: block;
margin: auto;
border: solid 1px white;
border-radius: 10px;
}
script {
display: none;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="application/javascript">
void function() {
"use strict";
// Classes
function Camera(x,y) {
this.x = x || 0.0;
this.y = y || 0.0;
}
Camera.prototype = {
set: function(x,y) {
this.x = x || 0.0;
this.y = y || 0.0;
},
pan: function(x,y) {
this.x += x || 0.0;
this.y += y || 0.0;
}
};
var nextID = 0;
function Tile(colour) {
this.id = nextID++;
this.colour = colour || "black";
}
function Map(width,height) {
this.width = width || 1;
this.height = height || 1;
this.map = [];
this.map.length = this.height;
for (var y = 0; y < this.height; ++y) {
this.map[y] = [];
this.map[y].length = width;
for (var x = 0; x < this.width; ++x) {
this.map[y][x] = Math.random() < 0.2 ?
this.TILE_WALL:
this.TILE_GRASS;
}
this.map[y][0] = this.TILE_WALL;
this.map[y][this.width - 1] = this.TILE_WALL;
}
for (var x = 0; x < this.width; ++x) {
this.map[0][x] = this.TILE_WALL;
this.map[this.height - 1][x] = this.TILE_WALL;
}
}
Map.prototype = {
TILE_WIDTH: 32.0,
TILE_HEIGHT: 32.0,
INV_TILE_WIDTH: 0.0,
INV_TILE_HEIGHT: 0.0,
TILE_AIR: new Tile("#00000000"),
TILE_GRASS: new Tile("#00AA00FF"),
TILE_WALL: new Tile("#555555FF"),
set: function(x,y,tile) {
this.map[y][x] = tile;
},
scaleX: function(x) {
return (x * this.INV_TILE_WIDTH) | 0;
},
scaleY: function(y) {
return (y * this.INV_TILE_HEIGHT) | 0;
},
isColliding: function(x,y) {
return x > -1 && x < this.width
&& y > -1 && y < this.height
&& this.map[y][x].id > 1;
},
render: function(ctx,camera) {
for (var y = 0; y < this.height; ++y) {
for (var x = 0; x < this.width; ++x) {
var tile = this.map[y][x];
var _x = x * this.TILE_WIDTH - camera.x;
var _y = y * this.TILE_HEIGHT - camera.y;
ctx.fillStyle = tile.colour;
ctx.fillRect(_x,_y,this.TILE_WIDTH - 1,this.TILE_HEIGHT - 1);
}
}
}
};
Map.prototype.INV_TILE_WIDTH = 1.0 / Map.prototype.TILE_WIDTH;
Map.prototype.INV_TILE_HEIGHT = 1.0 / Map.prototype.TILE_HEIGHT;
function Player(x,y) {
this.x = x || 0.0;
this.y = y || 0.0;
this.dx = 0.0;
this.dy = 0.0;
this.isUp = false;
this.isDown = false;
this.isLeft = false;
this.isRight = false;
}
Player.prototype = {
WIDTH: 20.0,
HEIGHT: 20.0,
ACCELERATION: 1.0,
DEACCELERATION: 0.5,
MAX_SPEED: 3.0,
tick: function(map) {
// Movement
if (this.isUp) {
this.dy -= this.ACCELERATION;
if (this.dy < -this.MAX_SPEED) {
this.dy = -this.MAX_SPEED;
}
} else if (this.dy < 0.0) {
this.dy += this.DEACCELERATION;
if (this.dy > 0.0) {
this.dy = 0.0;
}
}
if (this.isDown) {
this.dy += this.ACCELERATION;
if (this.dy > this.MAX_SPEED) {
this.dy = this.MAX_SPEED;
}
} else if (this.dy > 0.0) {
this.dy -= this.DEACCELERATION;
if (this.dy < 0.0) {
this.dy = 0.0;
}
}
if (this.isLeft) {
this.dx -= this.ACCELERATION;
if (this.dx < -this.MAX_SPEED) {
this.dx = -this.MAX_SPEED;
}
} else if (this.dx < 0.0) {
this.dx += this.DEACCELERATION;
if (this.dx > 0.0) {
this.dx = 0.0;
}
}
if (this.isRight) {
this.dx += this.ACCELERATION;
if (this.dx > this.MAX_SPEED) {
this.dx = this.MAX_SPEED;
}
} else if (this.dx > 0.0) {
this.dx -= this.DEACCELERATION;
if (this.dx < 0.0) {
this.dx = 0.0;
}
}
// Collision
if (this.dx !== 0.0) {
var minY = map.scaleY(this.y);
var maxY = map.scaleY(this.y + this.HEIGHT);
var minX = 0;
var maxX = 0;
if (this.dx < 0.0) {
minX = map.scaleX(this.x + this.dx);
maxX = map.scaleX(this.x);
} else {
minX = map.scaleX(this.x + this.WIDTH);
maxX = map.scaleX(this.x + this.WIDTH + this.dx);
}
loop:
for (var y = minY; y <= maxY; ++y) {
for (var x = minX; x <= maxX; ++x) {
if (map.isColliding(x,y)) {
this.x = this.dx < 0.0 ?
(x + 1) * map.TILE_WIDTH:
x * map.TILE_WIDTH - this.WIDTH - 1;
this.dx = 0.0;
break loop;
}
}
}
}
if (this.dy !== 0.0) {
var minX = map.scaleX(this.x);
var maxX = map.scaleX(this.x + this.WIDTH);
var minY = 0;
var maxY = 0;
if (this.dy < 0.0) {
minY = map.scaleY(this.y + this.dy);
maxY = map.scaleY(this.y);
} else {
minY = map.scaleY(this.y + this.HEIGHT);
maxY = map.scaleY(this.y + this.HEIGHT + this.dy);
}
loop:
for (var y = minY; y <= maxY; ++y) {
for (var x = minX; x <= maxX; ++x) {
if (map.isColliding(x,y)) {
this.y = this.dy < 0.0 ?
(y + 1) * map.TILE_HEIGHT:
y * map.TILE_HEIGHT - this.HEIGHT - 1;
this.dy = 0.0;
break loop;
}
}
}
}
this.x += this.dx;
this.y += this.dy;
},
render: function(ctx,camera) {
camera.set(this.x,this.y);
ctx.lineWidth = 1;
ctx.strokeStyle = "black";
ctx.fillStyle = "darkred";
ctx.beginPath();
ctx.rect(this.x - camera.x,this.y - camera.y,this.WIDTH,this.HEIGHT);
ctx.fill();
ctx.stroke();
}
};
// Variables
var canvasWidth = 180;
var canvasHeight = 160;
var canvas = null;
var ctx = null;
var camera = null;
var map = null;
var player = null;
// Functions
function onKeyDown(e) {
switch(e.key.toUpperCase()) {
case "W": player.isUp = true; break;
case "S": player.isDown = true; break;
case "A": player.isLeft = true; break;
case "D": player.isRight = true; break;
}
}
function onKeyUp(e) {
switch(e.key.toUpperCase()) {
case "W": player.isUp = false; break;
case "S": player.isDown = false; break;
case "A": player.isLeft = false; break;
case "D": player.isRight = false; break;
}
}
function loop() {
// Tick
player.tick(map);
// Render
ctx.fillStyle = "gray";
ctx.fillRect(-canvasWidth >> 1,-canvasHeight >> 1,canvasWidth,canvasHeight);
map.render(ctx,camera);
player.render(ctx,camera);
//
requestAnimationFrame(loop);
}
// Entry point (first to execute)
onload = function() {
canvas = document.getElementById("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
ctx = canvas.getContext("2d");
ctx.translate(canvasWidth >> 1,canvasHeight >> 1);
camera = new Camera(0.0,0.0);
map = new Map(10,10);
player = new Player(40.0,40.0);
map.set(1,1,map.TILE_GRASS);
addEventListener("keydown",onKeyDown);
addEventListener("keyup",onKeyUp);
loop();
}
}();
</script>
</body>
</html>
Firstly, looking at your code, there are some things that are missing which is required to implement basic collision detection and those are:
The player's current direction that he/she is moving in. This is important because it allows the function determining the collision detection to distinguish which side it is checking for the collision (Up, down, left, or right) since a player can only collide with one side at a time.
The tile's position and size. This is also very important because like the first point, there is only one side of the tile that the player can collide with and knowing the size and position can determine if it is a collision or not based on the players size and position.
Also, since you mentioned it is a basic game, the implementation below is a basic collision detection. If you were to make a more complex and bigger game, you should try looking into quad trees for more efficient collision detection:
https://gamedevelopment.tutsplus.com/tutorials/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space--gamedev-374
Now this is the function for detecting collision, for the sake of readability and shortness, p will represent the player object and t would represent the tile object. This function returns whether or not the player is colliding with a tile based on their direction of movement.
function isColliding(p, t){
if (p.direction == 'up') {
return p.y +(p.height/2)-p.speedY< t.y + t.height && p.y > t.y
&& p.x + p.width > t.x && p.x < t.x + t.width;
}
if (p.direction == 'down') {
return p.y + (p.height/2)+p.speedY > t.y && p.y < t.y
&& p.x + p.width > t.x && p.x < t.x + t.width;
}
if (p.direction == 'right') {
return p.x + p.width+p.speedX > t.x && p.x < t.x
&& p.y +(p.height/2)> t.y && p.y + p.height < t.y +t.height+ (p.height / 2);
}
if (p.direction == 'left') {
return p.x -p.speedX< t.x + t.width && p.x > t.x
&& p.y +(p.height/2)> t.y && p.y + p.height < t.y +t.height+ (p.height / 2);
}
return false;
}
You would probably want to put this in the player move function to constantly detect for tiles as it is moving. To do that, you'd want to modify your keydown detection so that with each different keydown, it would update the player's direction, here's a simple example:
document.onkeydown = function(event){
if (event.keyCode == 87)
player.up = true;
else if (event.keyCode == 65)
player.left = true;
else if (event.keyCode == 83)
player.down = true;
else if (event.keyCode == 68)
player.right = true;
}
and another simple example for every time the player moves (user presses a keydown):
const Player= function(/*Param stuff*/){
/*Property stuff*/
//tileArray is the array (or object, your choice) of all the current tiles in the map
this.move=function(tileArray){
//Go through all tiles to see if player is colliding with any of them
for(var t in tileArray){
if(this.up){
if(isColliding(this, tileArray[t]){
//functionality for when player collides
}else{
//functionality for when player doesn't collide
}
}
//check if player is going down, left, etc
}
}
}
These are just examples of how to implement the detection. You should use it as a reference to implement it relatively to how your code function because I didn't write it based on what you posted.
PS.
Make sure to also convert the directions to false after the user stops pressing the key.

JavaScript Brick Breaker, Bricks in array aren't being spliced?

I'm having trouble with how I remove bricks. The bricks are part of an array, and the ball continuously runs a for loop checking to see if it's hit any bricks. If it does, it splices that brick from the array. But the bricks don't disappear!
//Helper Functions
function AABBIntersect(ax, ay, aw, ah, bx, by, bw, bh) {
return ax < bx+bw && ay < by+bh && bx < ax+aw && by < ay+ah;
}
var ball = {
//A few of the basic variables called by the upcoming function
update: function() {
this.x += this.vel.x;
this.y += this.vel.y;
if (0 > this.y) {
var offset = 0 - this.y;
this.y += 2*offset;
this.vel.y *= -1;
}
if (this.y+this.height > HEIGHT) {
this.serve();
}
if (0 > this.x || this.x+this.size > WIDTH) {
var offset = this.vel.x < 0 ? 0 - this.x : WIDTH - (this.x+this.size);
this.x += 2*offset;
this.vel.x *= -1;
}
if (AABBIntersect(this.x, this.y, this.size, this.size, player.x, player.y, player.width, player.height)) {
var offset = player.y - (this.y+this.size);
this.y += 2*offset;
var n = (this.x+this.size - player.x)/(player.width+this.size);
var phi = 0.25*pi*(2*n - 1);
var smash = Math.abs(phi) > 0.2*pi ? 1.5 : 1;
this.vel.x = smash*this.speed*Math.sin(phi);
this.vel.y = smash*-1*this.speed*Math.cos(phi);
}
for (var i = 0; i < bricks.length; i++) {
var b = bricks[i];
if (AABBIntersect(this.x, this.y, this.width, this.height, b.x, b.y, b.width, b.height)) {
bricks.splice(i, 1);
i--;
bricks.length--;
continue;
}
}
}
}
var bricks = [];
function main() {
canvas = document.createElement("canvas");
canvas.width = WIDTH;
canvas.height = HEIGHT;
ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
keystate = {};
document.addEventListener("keydown", function(evt) {
keystate[evt.keyCode] = true;
});
document.addEventListener("keyup", function(evt) {
delete keystate[evt.keyCode];
} );
init();
var loop = function() {
update();
draw();
window.requestAnimationFrame(loop, canvas);
};
window.requestAnimationFrame(loop, canvas);
}
function init() {
var cols = WIDTH / 40;
player.x = (WIDTH - player.width) / 2;
player.y = HEIGHT - (player.height * 2);
ball.x = (WIDTH - ball.size) / 2;
ball.y = player.y - ball.size;
ball.width = ball.size;
ball.height = ball.size;
ball.serve();
for (var i = 0; i < 7; i++) {
for (var j = 0; j < cols; j++) {
bricks.push({
color: "#f00",
x: 2 + j*40,
y: 2 + i*20,
w: 36,
h: 16
});
}
}
}
function update() {
frames++;
player.update();
ball.update();
}
function draw() {
ctx.fillRect(0, 0, WIDTH, HEIGHT);
ctx.save();
ctx.fillStyle = "#fff";
player.draw();
ball.draw();
for (var i = 0; i < bricks.length; i++) {
ctx.fillStyle = bricks[i].color;
ctx.fillRect(bricks[i].x, bricks[i].y, bricks[i].w, bricks[i].h);
}
ctx.restore();
}
main();
A few issues:
The brick objects do not have width or height properties, but w and h;
The splice should not happen on a brick element (b), but on the array of bricks (bricks);
The length of bricks should not be decremented after the splice, as that operation already reduces the length.
So use this loop:
for (var i = 0; i < bricks.length; i++) {
var b = bricks[i];
if (AABBIntersect(this.x, this.y, this.width, this.height, b.x, b.y, b.w, b.h)) {
bricks.splice(i, 1);
i--;
}
}

Categories

Resources