Why circles aren't separated properly - javascript

I have this code for separating two circles. the problem is that whenever the radius of one of the circle changes (ie becomes bigger or smaller than the other) the circles start moving somewhere else. i am trying to move the circles apart together (). i dont know much about vectors. i got the vector posrtion of my code from Why circles are vibrating on collision (Canvas)
CollisionHandler.pushApart = function(cell, check) {
var x = check.x - cell.x;
var y = check.y - cell.y;
var distance = Math.hypot(x, y);
var cSz = Blob.getSize(cell.mass);
var chSz = Blob.getSize(check.mass);
var maxDist = cSz + chSz;
var boosting = Math.abs(cell.move.x) > 2 ||
Math.abs(cell.move.y) > 2 ||
Math.abs(check.move.x) > 2 ||
Math.abs(check.move.y) > 2;
if (distance < maxDist && !boosting) {
x /= distance;
y /= distance;
var pLen = cSz / (cSz + chSz);
var cx = cell.x + pLen * x * distance;
var cy = cell.y + pLen * y * distance;
cell.x += (cx - x * chSz - cell.x) * animationConstant;
cell.y += (cy - y * chSz - cell.y) * animationConstant;
check.x += (cx + x * cSz - check.x) * animationConstant;
check.y += (cy + y * cSz - check.y) * animationConstant;
/*var targetX = check.x - maxDistance * x;
var targetY = check.y - maxDistance * y;
cell.x += (targetX - cell.x) * animationConstant;
cell.y += (targetY - cell.y) * animationConstant;*/
}
};
<!DOCTYPE html>
<html>
<head>
<title>this is my clone of agar.io.</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<canvas></canvas>
<script>
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
var width = innerWidth;
var height = innerHeight;
canvas.width = width;
canvas.height = height;
var blobsFood = [];
var blobsVirus = [];
var blobsEject = [];
var blobsPlayer = [];
function getRandom(n) {
return Math.random() * n;
};
var gameWidth = 10000;
var gameHeight = 10000;
var massFood = 5;
var animationConstant = 0.2;
var maxSplit = 64;
function Blob(x, y, mass, hue) {
this.x = x;
this.y = y;
this.mass = mass;
this._mass = mass;
this.hue = hue;
this.time = Date.now();
this.move = {
x: 0,
y: 0,
angle: 0
};
};
Blob.getSize = function(mass) {
return Math.sqrt(mass * 100);
};
Blob.getSpeed = function(mass) {
return 15 * 1.6/Math.pow(mass, 0.32);
};
Blob.getBoostSpeed = function(mass) {
return 15 * 2.6 * Math.pow(mass, 0.0122);
};
Blob.prototype.boostMove = function() {
this.x += this.move.x;
this.y += this.move.y;
this.move.x *= 0.95;
this.move.y *= 0.95;
};
Blob.prototype.getAngle = function() {
return this.move.angle;
};
Blob.prototype.draw = function() {
ctx.save();
ctx.translate(this.x, this.y);
ctx.beginPath();
this._mass += (this.mass - this._mass) * animationConstant;
ctx.arc(0, 0, Blob.getSize(this._mass), 0, Math.PI * 2);
ctx.closePath();
ctx.fillStyle = "hsl(" + this.hue + ", 100%, 60%)";
ctx.strokeStyle = "hsl(" + this.hue + ", 100%, 50%)";
ctx.lineWidth = 5;
ctx.fill();
ctx.stroke();
ctx.restore();
};
Blob.prototype.onEaten = function(eater) {
// For virus and other cells
};
Blob.prototype.onEat = function(prey) {
this.mass += prey.mass;
};
function Virus() {
this.x = Math.random() * gameWidth;
this.y = Math.random() * gameWidth;
this.mass = 100;
this._mass = 100;
this.maxMass = 150;
this.hue = Math.random() * 360;
};
Virus.prototype = new Blob();
Virus.prototype.onEat = function(prey) {
this.mass += prey.mass;
if(this.mass >= this.maxMass) {
shootVirus(this, prey.getAngle());
}
};
Virus.prototype.onEaten = function(eater) {
var numSplits = maxSplit - blobsPlayer.length;
if(numSplits <= 0)
return;
var massLeft = eater.mass;
var splitAmount = 1;
var smallMass = 50;
while(massLeft > 0) {
splitAmount *= 2;
massLeft = eater.mass - splitAmount * 30;
};
var splitMass = eater.mass/splitAmount;
for(var i = 0; i < Math.min(splitAmount, numSplits); i++) {
if (eater.mass <= smallMass)
break;
var angle = Math.random() * 2 * Math.PI;
addPlayer(eater.x, eater.y, splitMass, angle, eater.hue);
eater.mass -= splitMass;
};
};
function CollisionHandler() {
console.log("CollisionHandler started.");
};
CollisionHandler.eatFactor = 0.02;
CollisionHandler.canEat = function(eater, check) {
var x = eater.x - check.x;
var y = eater.y - check.y;
var distance = Math.hypot(x, y);
var maxDistance = Blob.getSize(eater.mass + check.mass);
var minMass = CollisionHandler.eatFactor * check.mass + check.mass;
if(distance < maxDistance && eater.mass > minMass) {
return true;
} else {
return false;
}
};
CollisionHandler.pushApart = function(cell, check) {
var x = check.x - cell.x;
var y = check.y - cell.y;
var distance = Math.hypot(x, y);
var cSz = Blob.getSize(cell.mass);
var chSz = Blob.getSize(check.mass);
var maxDist = cSz + chSz;
var boosting = Math.abs(cell.move.x) > 2 ||
Math.abs(cell.move.y) > 2 ||
Math.abs(check.move.x) > 2 ||
Math.abs(check.move.y) > 2;
if(distance < maxDist && !boosting) {
x /= distance;
y /= distance;
var pLen = cSz / (cSz + chSz);
var cx = cell.x + pLen * x * distance;
var cy = cell.y + pLen * y * distance;
cell.x += (cx - x * chSz - cell.x) * animationConstant;
cell.y += (cy - y * chSz - cell.y) * animationConstant;
check.x += (cx + x * cSz - check.x) * animationConstant;
check.y += (cy + y * cSz - check.y) * animationConstant;
/*var targetX = check.x - maxDistance * x;
var targetY = check.y - maxDistance * y;
cell.x += (targetX - cell.x) * animationConstant;
cell.y += (targetY - cell.y) * animationConstant;*/
}
};
function addFood(n) {
for(var i = 0; i < n ; i++) {
var blob = new Blob(
getRandom(gameWidth),
getRandom(gameHeight),
massFood,
getRandom(360)
);
blobsFood.push(blob);
};
console.log(blobsFood.length);
};
var massVirus = 80;
var massVirusMax = 120;
function addVirus(n) {
for(var i = 0; i < n ; i++) {
var blob = new Virus();
blobsVirus.push(blob);
};
console.log(blobsVirus.length);
};
var massEject = 10;
function addEject(blob) {
if(blob.mass < 20)
return;
blob.mass -= massEject;
var angle = getMouseAngle(blob.x, blob.y);
var r = Blob.getSize(blob.mass);
var blob = new Blob(
blob.x + Math.cos(angle) * r,
blob.y + Math.sin(angle) * r,
massEject,
blob.hue
);
blob.move.x = Math.cos(angle) * 30;
blob.move.y = Math.sin(angle) * 30;
blob.move.angle = angle;
blobsEject.push(blob);
};
function addPlayer(x, y, mass, angle, hue) {
var moveX = Math.cos(angle) * Blob.getBoostSpeed(mass);
var moveY = Math.sin(angle) * Blob.getBoostSpeed(mass);
var blob = new Blob(x, y, mass, hue);
blob.move.x = moveX;
blob.move.y = moveY;
blob.move.angle = angle;
blobsPlayer.push(blob);
};
var mouseX = 0;
var mouseY = 0;
var cameraX = 0;
var cameraY = 0;
var _cameraX = 0;
var _cameraY = 0;
var zoom = 1;
var _zoom = 1;
function updateCamera() {
var x = 0;
var y = 0;
var m = 0;
var len = blobsPlayer.length;
blobsPlayer.forEach(function(blob) {
x += blob.x;
y += blob.y;
m += Blob.getSize(blob.mass);
});
cameraX = x/len;
cameraY = y/len;
zoom = 1/(Math.sqrt(m)/Math.log(m));
};
document.onmousemove = function(evt) {
mouseX = evt.clientX;
mouseY = evt.clientY;
};
document.onkeydown = function(evt) {
var key = evt.keyCode;
if(key == 32) {
var len = blobsPlayer.length;
for(var i = 0; i < len; i++) {
var blob = blobsPlayer[i];
splitPlayerBlob(blob);
};
}
if(key == 87) {
var len = blobsPlayer.length;
for(var i = 0; i < len; i++) {
var blob = blobsPlayer[i];
addEject(blob);
};
}
};
function getMouseAngle(x, y) {
var x = mouseX - width/2 + (cameraX - x) * zoom;
var y = mouseY - height/2 + (cameraY - y) * zoom;
return Math.atan2(y, x);
};
function splitPlayerBlob(blob) {
var numSplits = 16 - blobsPlayer.length;
if(numSplits <= 0) return;
if(blob.mass >= 20) {
blob.mass /= 2;
var angle = getMouseAngle(blob.x, blob.y);
addPlayer(blob.x, blob.y, blob.mass, angle, blob.hue);
}
};
function mouseMovePlayer() {
blobsPlayer.forEach(function(blob) {
var angle = getMouseAngle(blob.x, blob.y);
var speed = Blob.getSpeed(blob.mass);
var x = mouseX - width/2 + (cameraX - blob.x) * zoom;
var y = mouseY - height/2 + (cameraY - blob.y) * zoom;
// blob.x += Math.cos(angle) * speed * Math.min(1, Math.pow(x/toRadius(blob.mass), 2));
// blob.y += Math.sin(angle) * speed * Math.min(1, Math.pow(y/toRadius(blob.mass), 2));
blob.x += Math.cos(angle) * speed;
blob.y += Math.sin(angle) * speed;
});
};
function movePlayer() {
blobsPlayer.forEach(function(blob) {
blob.boostMove();
});
};
function moveEject() {
blobsEject.forEach(function(blob) {
blob.boostMove();
});
};
function separateEject() {
blobsEject.forEach(function(a, i) {
blobsEject.forEach(function(b, j) {
if(i == j)
return;
CollisionHandler.pushApart(a, b);
});
});
};
function separatePlayer() {
blobsPlayer.forEach(function(a, i) {
blobsPlayer.forEach(function(b, j) {
if(i == j)
return;
var ref1 = a;
var ref2 = b;
CollisionHandler.pushApart(ref1, ref2);
});
});
};
function eatFood() {
blobsPlayer.forEach(function(player) {
blobsFood.forEach(function(food, i) {
if(CollisionHandler.canEat(player, food)) {
player.onEat(food);
blobsFood.splice(i, 1);
}
});
});
};
function eatEject() {
blobsPlayer.forEach(function(player) {
blobsEject.forEach(function(eject, i) {
if(CollisionHandler.canEat(player, eject)) {
player.onEat(eject);
blobsEject.splice(i, 1);
}
});
});
blobsVirus.forEach(function(virus) {
blobsEject.forEach(function(eject, i) {
if(CollisionHandler.canEat(virus, eject)) {
virus.onEat(eject);
blobsEject.splice(i, 1);
}
});
});
};
function shootVirus(virus, angle) {
virus.mass = massVirus;
var speed = Blob.getSpeed(massVirus);
var blob = new Blob(virus.x, virus.y, massVirus, virus.hue);
var x = Math.cos(angle) * 30;
var y = Math.sin(angle) * 30;
blob.move.x = x;
blob.move.y = y;
blob.move.angle = angle;
blobsVirus.push(blob);
};
function moveVirus() {
blobsVirus.forEach(function(blob) {
blob.x += blob.move.x;
blob.y += blob.move.y;
blob.move.x *= 0.95;
blob.move.y *= 0.95;
});
};
function separateVirus() {
blobsVirus.forEach(function(a, i) {
blobsVirus.forEach(function(b, j) {
if(i == j)
return;
CollisionHandler.pushApart(a, b);
});
});
};
function eatVirus() {
blobsPlayer.forEach(function(player) {
blobsVirus.forEach(function(virus, i) {
if(CollisionHandler.canEat(player, virus)) {
player.onEat(virus);
virus.onEaten(player);
blobsVirus.splice(i, 1);
}
});
});
};
var baseTime = 10000;
function canCombine(player) {
var t = Math.floor(baseTime + (0.02 * player.mass));
var now = Date.now() - player.time;
return t < now;
};
function combinePlayer() {
blobsPlayer.forEach(function(a, i) {
blobsPlayer.forEach(function(b, j) {
if(i == j)
return;
var x = a.x - b.x;
var y = a.y - b.y;
var d = Math.hypot(x, y);
var r = Blob.getSize(a.mass + b.mass);
if(d < r && canCombine(a) && canCombine(b)) {
if(a.mass > b.mass) {
a.mass += b.mass;
blobsPlayer.splice(j, 1);
} else {
b.mass += a.mass;
blobsPlayer.splice(i, 1);
}
}
});
});
};
function updateGame() {
movePlayer();
mouseMovePlayer();
separatePlayer();
combinePlayer();
moveEject();
separateEject();
moveVirus();
separateVirus();
eatFood();
eatEject();
eatVirus();
updateCamera();
};
function drawGame() {
clearCanvas();
ctx.save();
_zoom += (zoom - _zoom) * 0.1;
_cameraX += (cameraX - _cameraX) * 0.1;
_cameraY += (cameraY - _cameraY) * 0.1;
ctx.translate(-_cameraX * _zoom + width/2, -_cameraY * _zoom + height/2);
ctx.scale(_zoom, _zoom);
drawAllBlobs();
ctx.restore();
};
function clearCanvas() {
ctx.fillStyle = "white";
ctx.fillRect(0, 0, width, height);
};
function drawAllBlobs() {
var blobs = blobsFood
.concat(blobsEject)
.concat(blobsVirus)
.concat(blobsPlayer);
var blobs = blobs.sort(function(a, b) {
return a.mass - b.mass;
});
blobs.forEach(function(blob) {
blob.draw();
});
};
function loop() {
updateGame();
drawGame();
requestAnimationFrame(loop);
};
addFood(300);
addVirus(15);
addPlayer(0, 0, 3000, 0, 45)
loop();
</script>
</body>
</html>

Related

Issue implementing codepen.io mouse trail

im trying to implement this
https://codepen.io/Mertl/pen/XWdyRwJ into a hugo template https://themes.gohugo.io/somrat/ ;
I dont know where to put the html file; put only the no cursor part into style.css; and copy the .js into script.js, nothing happens on the localhost website when I do this, any help is appreciated <3
code: (html, css and js)
<canvas id="canvas"></canvas>
body,
html {
margin: 0px;
padding: 0px;
position: fixed;
background: rgb(30, 30, 30);
cursor: none;
}
window.onload = function () {
//functions definition
//class definition
class segm {
constructor(x, y, l) {
this.b = Math.random()*1.9+0.1;
this.x0 = x;
this.y0 = y;
this.a = Math.random() * 2 * Math.PI;
this.x1 = this.x0 + l * Math.cos(this.a);
this.y1 = this.y0 + l * Math.sin(this.a);
this.l = l;
}
update(x, y) {
this.x0 = x;
this.y0 = y;
this.a = Math.atan2(this.y1 - this.y0, this.x1 - this.x0);
this.x1 = this.x0 + this.l * Math.cos(this.a);
this.y1 = this.y0 + this.l * Math.sin(this.a);
}
}
class rope {
constructor(tx, ty, l, b, slq, typ) {
if(typ == "l"){
this.res = l / 2;
}else{
this.res = l / slq;
}
this.type = typ;
this.l = l;
this.segm = [];
this.segm.push(new segm(tx, ty, this.l / this.res));
for (let i = 1; i < this.res; i++) {
this.segm.push(
new segm(this.segm[i - 1].x1, this.segm[i - 1].y1, this.l / this.res)
);
}
this.b = b;
}
update(t) {
this.segm[0].update(t.x, t.y);
for (let i = 1; i < this.res; i++) {
this.segm[i].update(this.segm[i - 1].x1, this.segm[i - 1].y1);
}
}
show() {
if(this.type == "l"){
c.beginPath();
for (let i = 0; i < this.segm.length; i++) {
c.lineTo(this.segm[i].x0, this.segm[i].y0);
}
c.lineTo(
this.segm[this.segm.length - 1].x1,
this.segm[this.segm.length - 1].y1
);
c.strokeStyle = "white";
c.lineWidth = this.b;
c.stroke();
c.beginPath();
c.arc(this.segm[0].x0, this.segm[0].y0, 1, 0, 2 * Math.PI);
c.fillStyle = "white";
c.fill();
c.beginPath();
c.arc(
this.segm[this.segm.length - 1].x1,
this.segm[this.segm.length - 1].y1,
2,
0,
2 * Math.PI
);
c.fillStyle = "white";
c.fill();
}else{
for (let i = 0; i < this.segm.length; i++) {
c.beginPath();
c.arc(this.segm[i].x0, this.segm[i].y0, this.segm[i].b, 0, 2*Math.PI);
c.fillStyle = "white";
c.fill();
}
c.beginPath();
c.arc(
this.segm[this.segm.length - 1].x1,
this.segm[this.segm.length - 1].y1,
2, 0, 2*Math.PI
);
c.fillStyle = "white";
c.fill();
}
}
}
//setting up canvas
let c = init("canvas").c,
canvas = init("canvas").canvas,
w = (canvas.width = window.innerWidth),
h = (canvas.height = window.innerHeight),
ropes = [];
//variables definition
let nameOfVariable = "value",
mouse = {},
last_mouse = {},
rl = 50,
randl = [],
target = { x: w/2, y: h/2 },
last_target = {},
t = 0,
q = 10,
da = [],
type = "l";
for (let i = 0; i < 100; i++) {
if(Math.random() > 0.25){
type = "l";
}else{
type = "o";
}
ropes.push(
new rope(
w / 2,
h / 2,
(Math.random() * 1 + 0.5) * 500,
Math.random() * 0.4 + 0.1,
Math.random()*15+5,
type
)
);
randl.push(Math.random() * 2 - 1);
da.push(0);
}
//place for objects in animation
function draw() {
if (mouse.x) {
target.errx = mouse.x - target.x;
target.erry = mouse.y - target.y;
} else {
target.errx =
w / 2 +
(h / 2 - q) *
Math.sqrt(2) *
Math.cos(t) /
(Math.pow(Math.sin(t), 2) + 1) -
target.x;
target.erry =
h / 2 +
(h / 2 - q) *
Math.sqrt(2) *
Math.cos(t) *
Math.sin(t) /
(Math.pow(Math.sin(t), 2) + 1) -
target.y;
}
target.x += target.errx / 10;
target.y += target.erry / 10;
t += 0.01;
for (let i = 0; i < ropes.length; i++) {
if (randl[i] > 0) {
da[i] += (1 - randl[i]) / 10;
} else {
da[i] += (-1 - randl[i]) / 10;
}
ropes[i].update({
x:
target.x +
randl[i] * rl * Math.cos((i * 2 * Math.PI) / ropes.length + da[i]),
y:
target.y +
randl[i] * rl * Math.sin((i * 2 * Math.PI) / ropes.length + da[i])
});
ropes[i].show();
}
last_target.x = target.x;
last_target.y = target.y;
}
//mouse position
canvas.addEventListener(
"mousemove",
function (e) {
last_mouse.x = mouse.x;
last_mouse.y = mouse.y;
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
},
false
);
canvas.addEventListener("mouseleave", function(e) {
mouse.x = false;
mouse.y = false;
});
//animation frame
function loop() {
window.requestAnimFrame(loop);
c.clearRect(0, 0, w, h);
draw();
}
//window resize
window.addEventListener("resize", function () {
(w = canvas.width = window.innerWidth),
(h = canvas.height = window.innerHeight);
loop();
});
//animation runner
loop();
setInterval(loop, 1000 / 60);
};
Try to implement like this
window.init = function(elemid) {
let canvas = document.getElementById(elemid),
c = canvas.getContext("2d"),
w = (canvas.width = window.innerWidth),
h = (canvas.height = window.innerHeight);
c.fillStyle = "rgba(30,30,30,1)";
c.fillRect(0, 0, w, h);
return {c:c,canvas:canvas};
}
window.requestAnimFrame = function() {
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback);
}
);
};
window.spaceworm = function () {
//functions definition
//class definition
class segm {
constructor(x, y, l) {
this.b = Math.random()*1.9+0.1;
this.x0 = x;
this.y0 = y;
this.a = Math.random() * 2 * Math.PI;
this.x1 = this.x0 + l * Math.cos(this.a);
this.y1 = this.y0 + l * Math.sin(this.a);
this.l = l;
}
update(x, y) {
this.x0 = x;
this.y0 = y;
this.a = Math.atan2(this.y1 - this.y0, this.x1 - this.x0);
this.x1 = this.x0 + this.l * Math.cos(this.a);
this.y1 = this.y0 + this.l * Math.sin(this.a);
}
}
class rope {
constructor(tx, ty, l, b, slq, typ) {
if(typ == "l"){
this.res = l / 2;
}else{
this.res = l / slq;
}
this.type = typ;
this.l = l;
this.segm = [];
this.segm.push(new segm(tx, ty, this.l / this.res));
for (let i = 1; i < this.res; i++) {
this.segm.push(
new segm(this.segm[i - 1].x1, this.segm[i - 1].y1, this.l / this.res)
);
}
this.b = b;
}
update(t) {
this.segm[0].update(t.x, t.y);
for (let i = 1; i < this.res; i++) {
this.segm[i].update(this.segm[i - 1].x1, this.segm[i - 1].y1);
}
}
show() {
if(this.type == "l"){
c.beginPath();
for (let i = 0; i < this.segm.length; i++) {
c.lineTo(this.segm[i].x0, this.segm[i].y0);
}
c.lineTo(
this.segm[this.segm.length - 1].x1,
this.segm[this.segm.length - 1].y1
);
c.strokeStyle = "white";
c.lineWidth = this.b;
c.stroke();
c.beginPath();
c.arc(this.segm[0].x0, this.segm[0].y0, 1, 0, 2 * Math.PI);
c.fillStyle = "white";
c.fill();
c.beginPath();
c.arc(
this.segm[this.segm.length - 1].x1,
this.segm[this.segm.length - 1].y1,
2,
0,
2 * Math.PI
);
c.fillStyle = "white";
c.fill();
}else{
for (let i = 0; i < this.segm.length; i++) {
c.beginPath();
c.arc(this.segm[i].x0, this.segm[i].y0, this.segm[i].b, 0, 2*Math.PI);
c.fillStyle = "white";
c.fill();
}
c.beginPath();
c.arc(
this.segm[this.segm.length - 1].x1,
this.segm[this.segm.length - 1].y1,
2, 0, 2*Math.PI
);
c.fillStyle = "white";
c.fill();
}
}
}
//setting up canvas
let c = init("canvas").c,
canvas = init("canvas").canvas,
w = (canvas.width = window.innerWidth),
h = (canvas.height = window.innerHeight),
ropes = [];
//variables definition
let nameOfVariable = "value",
mouse = {},
last_mouse = {},
rl = 50,
randl = [],
target = { x: w/2, y: h/2 },
last_target = {},
t = 0,
q = 10,
da = [],
type = "l";
for (let i = 0; i < 100; i++) {
if(Math.random() > 0.25){
type = "l";
}else{
type = "o";
}
ropes.push(
new rope(
w / 2,
h / 2,
(Math.random() * 1 + 0.5) * 500,
Math.random() * 0.4 + 0.1,
Math.random()*15+5,
type
)
);
randl.push(Math.random() * 2 - 1);
da.push(0);
}
//place for objects in animation
function draw() {
if (mouse.x) {
target.errx = mouse.x - target.x;
target.erry = mouse.y - target.y;
} else {
target.errx =
w / 2 +
(h / 2 - q) *
Math.sqrt(2) *
Math.cos(t) /
(Math.pow(Math.sin(t), 2) + 1) -
target.x;
target.erry =
h / 2 +
(h / 2 - q) *
Math.sqrt(2) *
Math.cos(t) *
Math.sin(t) /
(Math.pow(Math.sin(t), 2) + 1) -
target.y;
}
target.x += target.errx / 10;
target.y += target.erry / 10;
t += 0.01;
for (let i = 0; i < ropes.length; i++) {
if (randl[i] > 0) {
da[i] += (1 - randl[i]) / 10;
} else {
da[i] += (-1 - randl[i]) / 10;
}
ropes[i].update({
x:
target.x +
randl[i] * rl * Math.cos((i * 2 * Math.PI) / ropes.length + da[i]),
y:
target.y +
randl[i] * rl * Math.sin((i * 2 * Math.PI) / ropes.length + da[i])
});
ropes[i].show();
}
last_target.x = target.x;
last_target.y = target.y;
}
//mouse position
canvas.addEventListener(
"mousemove",
function (e) {
last_mouse.x = mouse.x;
last_mouse.y = mouse.y;
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
},
false
);
canvas.addEventListener("mouseleave", function(e) {
mouse.x = false;
mouse.y = false;
});
//animation frame
function loop() {
window.requestAnimFrame(loop);
c.clearRect(0, 0, w, h);
draw();
}
//window resize
window.addEventListener("resize", function () {
(w = canvas.width = window.innerWidth),
(h = canvas.height = window.innerHeight);
loop();
});
//animation runner
loop();
setInterval(loop, 1000 / 60);
};
window.onload = spaceworm;
body,
html {
margin: 0px;
padding: 0px;
position: fixed;
background: rgb(30, 30, 30);
cursor: none;
}
<canvas id="canvas"></canvas>

Why won't the image load

What is wrong with the code, I can't find the problem. I think it's because of the drawFrame and loadImage function, but I don't know. So is there a way to make the image load and you will still be able to move it around and shoot?
And when I try to remove the drawFrame function nothing would work. And if posiible is there a way to change the bullet from squares to circles?
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta charset="UTF-8">
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
}
canvas {
cursor: crosshair;
background-color: cornflowerblue;
}
</style>
</head>
<body>
<canvas id="Trump"></canvas>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
(async function main() {
var canvas = document.getElementById('Trump');
if (!canvas.getContext) return;
var ctx = canvas.getContext('2d');
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
//const fps = 60;
const ronaNum = 30; // number of particles at start
const ronaSize = 70; // corona size
const ronaSpeed = 100; // speed
let chinabmg;
function draw() {
$("canvas").one("click", function () {
chinabmg = new sound("stankytrumpchina.mp3");
chinabmg.play();
});
//mutes when clicked on m
document.body.onkeyup = function (e) {
if (e.keyCode == 77) { chinabmg.stop() }
};
//compatability
var requestAnimationFrame = window.requestAnimationFrame || //Chromium
window.webkitRequestAnimationFrame || //Webkit
window.mozRequestAnimationFrame || //Mozilla Geko
window.oRequestAnimationFrame || //Opera Presto
window.msRequestAnimationFrame || //IE Trident?
function (callback) { //Fallback function
window.setTimeout(callback, 1000 / 60);
};
var DrawX = 0;
var DrawY = 0;
var time = 0;
var width = canvas.width;
var height = canvas.height;
var offTop = canvas.offsetTop;
var offLeft = canvas.offsetLeft;
var rectWidth = 15;
var rectHeight = 15;
var speed = 1;
var x = width / 2;
var y = height / 2;
var size = 30;
var id = 0;
var bulletId = 0;
function sound(src) {
this.sound = document.createElement("audio");
this.sound.src = src;
this.sound.setAttribute("preload", "auto");
this.sound.setAttribute("controls", "none");
this.sound.setAttribute("loop", "auto");
this.sound.style.display = "none";
document.body.appendChild(this.sound);
this.play = function () {
this.sound.play();
}
this.stop = function () {
this.sound.pause();
}
}
function player(id, color, size, x, y) {
this.id = id;
this.color = color;
this.size = size;
this.x = x;
this.y = y;
this.speed = speed;
}
var playerList = [];
function addPlayer(color, size, x, y) {
playerList[id] = new player(id, color, size, x, y);
id += 1;
}
addPlayer("blue", size, width / 2 - 50, height / 2);
var pressedKeys = [];
function moveLeft(checkId, checkX, checkY, cSize, cSpeed, cKey) {
var x = checkX - cSpeed;
var y = checkY - cSpeed;
var x2 = checkX + cSize + cSpeed;
var y2 = checkY + cSize + cSpeed;
if (x > 0) {
playerList[checkId].x = checkX - cSpeed;
} else {
playerList[checkId].x = 0;
}
}
function moveUp(checkId, checkX, checkY, cSize, cSpeed, cKey) {
var x = checkX - cSpeed;
var y = checkY - cSpeed;
var x2 = checkX + cSize + cSpeed;
var y2 = checkY + cSize + cSpeed;
if (y > 0) {
playerList[checkId].y = checkY - cSpeed;
} else {
playerList[checkId].y = 0;
}
}
function moveRight(checkId, checkX, checkY, cSize, cSpeed, cKey) {
var x = checkX - cSpeed;
var y = checkY - cSpeed;
var x2 = checkX + cSize + cSpeed;
var y2 = checkY + cSize + cSpeed;
if (x2 < width) {
playerList[checkId].x = checkX + cSpeed;
} else {
playerList[checkId].x = width - cSize;
}
}
function moveDown(checkId, checkX, checkY, cSize, cSpeed, cKey) {
var x = checkX - cSpeed;
var y = checkY - cSpeed;
var x2 = checkX + cSize + cSpeed;
var y2 = checkY + cSize + cSpeed;
if (y2 < height) {
playerList[checkId].y = checkY + cSpeed;
} else {
playerList[checkId].y = height - cSize;
}
}
function Move(checkId, checkX, checkY, cSize, cSpeed, cKey) {
if (checkId === 0) {
switch (cKey) {
case 65:
// left
moveLeft(checkId, checkX, checkY, cSize, cSpeed, cKey);
break;
case 87:
// up
moveUp(checkId, checkX, checkY, cSize, cSpeed, cKey);
break;
case 68:
// right
moveRight(checkId, checkX, checkY, cSize, cSpeed, cKey);
break;
case 83:
// down
moveDown(checkId, checkX, checkY, cSize, cSpeed, cKey);
break;
default:
return; // exit this handler for other keys
}
}
}
var validKeys = [];
validKeys[0] = "65,87,68,83-107,109,80";
// == KEYDOWN ==
$(document.body).keydown(function (e) {
e.preventDefault();
//go through all players
$.each(playerList, function (i, currentPlayer) {
if (validKeys[currentPlayer.id].indexOf(e.which) == -1) return true;
if (!pressedKeys[e.which]) {
//set interval for the function
pressedKeys[e.which] = setInterval(function () {
Move(currentPlayer.id, currentPlayer.x, currentPlayer.y, currentPlayer.size, currentPlayer.speed, e.which);
}, 5);
}
});
});
// == KEYUP ==
$(document.body).keyup(function (e) {
if (pressedKeys[e.which]) {
clearInterval(pressedKeys[e.which]);
delete pressedKeys[e.which];
}
});
//=============================== SHOOTING ===============================
//Bullets
function bullet(id, color, size, speed, x, y, eX, eY) {
this.id = id;
this.color = color;
this.size = size;
this.x = x;
this.y = y;
this.eX = eX;
this.eY = eY;
this.velocityX = 1;
this.velocityY = 1;
this.speed = 9;
}
var bulletList = [];
function addBullet(color, bsize, bspeed, x, y, eX, eY) {
bulletList[bulletId] = new bullet(bulletId, color, bsize, 9, x, y, eX, eY);
bulletId += 1;
}
function updateBullet(bullet, player) {
var dx = (bullet.eX - player.x);
var dy = (bullet.eY - player.y);
var mag = Math.sqrt(dx * dx + dy * dy);
bullet.velocityX = (dx / mag) * 9;
bullet.velocityY = (dy / mag) * 9;
bullet.x += bullet.velocityX;
bullet.y += bullet.velocityY;
}
// Add event listener for `click` events.
canvas.onmousedown = function (e) {
addBullet("#696969", 10, 2, playerList[0].x, playerList[0].y, e.x, e.y);
};
//corona part
let corona = [];
createCoronaParticles();
// game loop
//setInterval(update, 1000 / fps);
function createCoronaParticles() {
corona = [];
let cx, cy;
for (var i = 0; i < ronaNum; i++) {
do {
cx = Math.floor(Math.random() * canvas.width);
cy = Math.floor(Math.random() * canvas.height);
} while (noSpawnOnFigure(canvas.height / 2, canvas.width / 2, cy, cx) < ronaSize * 5);
corona.push(newParticle(cx, cy));
}
}
function noSpawnOnFigure(cy1, cx1, cy2, cx2) {
return Math.sqrt(Math.pow(cy2 - cy1, 2) + Math.pow(cx2 - cx1, 2));
}
function newParticle(cx, cy) {
let rona = {
ca: Math.random() * Math.PI * 2, //radians
cr: ronaSize / 2,
cx: cx,
cy: cy,
cxv: Math.random() * ronaSpeed / 60 * (Math.random() < 0.5 ? 1 : -1),
cyv: Math.random() * ronaSpeed / 60 * (Math.random() < 0.5 ? 1 : -1)
};
return rona;
}
// function update() {
// }
// ======= DRAWING =======
function drawFrame() {
requestAnimationFrame(drawFrame);
ctx.font = "15pt Georgia"; // sets the font and font size of the text
ctx.clearRect(0, 0, width, height);
$.each(playerList, function (index, currentPlayer) {
//debug
//draw players
function loadImage(path) {
let image = new Image();
let promise = new Promise((resolve, reject) => {
image.onload = () => resolve(image);
image.onerror = reject
});
image.src = path;
return promise;
}
loadImage.src = 'trump.gif';
});
//draw bullets
$.each(bulletList, function (index, bullet) {
updateBullet(bullet, playerList[0]);
ctx.fillStyle = bullet.color;
ctx.fillRect(bullet.x, bullet.y, bullet.size, bullet.size);
});
// canvas
//ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw corona particles
ctx.strokeStyle = "rgb(150, 0, 0)";
ctx.lineWidth = 20;
let ca, cr, cx, cy;
for (let i = 0; i < corona.length; i++) {
// get properties
ca = corona[i].ca;
cr = corona[i].cr;
cx = corona[i].cx;
cy = corona[i].cy;
// draw path
ctx.beginPath();
ctx.fillStyle = "rgb(200, 0, 0)"
ctx.moveTo(
cx + cr * Math.cos(ca),
cy + cr * Math.sin(ca)
);
// draw circle
for (let j = 1; j < 180; j++) {
ctx.lineTo(
cx + cr * Math.cos(ca + j * Math.PI * 2 / 180),
cy + cr * Math.sin(ca + j * Math.PI * 2 / 180)
);
}
ctx.closePath();
ctx.stroke();
ctx.fill();
// move particles
corona[i].cx += corona[i].cxv;
corona[i].cy += corona[i].cyv;
// particle edge of screen
if (corona[i].cx < 0 - corona[i].cr) {
corona[i].cx = canvas.width + corona[i].cr;
} else if (corona[i].cx > canvas.width + corona[i].cr) {
corona[i].cx = 0 - corona[i].cr
}
if (corona[i].cy < 0 - corona[i].cr) {
corona[i].cy = canvas.height + corona[i].cr;
} else if (corona[i].cy > canvas.height + corona[i].cr) {
corona[i].cy = 0 - corona[i].cr
}
}
}
drawFrame();
}
$(draw);
}
)();
</script>
</body>
</html>
//draw players
function loadImage(path) {
let image = new Image();
let promise = new Promise((resolve, reject) => {
image.onload = () => resolve(image);
image.onerror = reject
});
image.src = path;
//Add the following line
ctx.drawImage(image,playerList[0].x,playerList[0].y);
return promise;
}
// change loadImage.src = 'trump.gif' into this
loadImage('trump.gif');

how to use html canvas in between 2 <div>s

I tried to use canvas in middle of my html page.but it does't work fine. I want to use ribbon effect in div. it works fine when the there is no div and when there is div or other element it doesn't work. I want use canvas in between two div. I used ribbon pen in codepen and will post the code below. I want to how to use it in my html page.
var TWO_PI = Math.PI * 2;
var HALF_PI = Math.PI * 0.5;
var THICKNESS = 12;
var LENGTH = 10;
var STEP = 0.1;
var FPS = 1000 / 60;
function Particle(x, y, mass) {
this.x = x || 0;
this.y = y || 0;
this.ox = this.x;
this.oy = this.y;
this.mass = mass || 1.0;
this.massInv = 1.0 / this.mass;
this.fixed = false;
this.update = function (dt) {
if (!this.fixed) {
var fx = 0.0000;
var fy = 0.0000;
var tx = this.x,
ty = this.y;
this.x += (this.x - this.ox) + fx * this.massInv * dt * dt;
this.y += (this.y - this.oy) + fy * this.massInv * dt * dt;
this.ox = tx;
this.oy = ty;
}
};
};
function Spring(p1, p2, restLength, strength) {
this.p1 = p1;
this.p2 = p2;
this.restLength = restLength || 10;
this.strength = strength || 1.0;
this.update = function (dt) {
// Compute desired force
var dx = p2.x - p1.x,
dy = p2.y - p1.y,
dd = Math.sqrt(dx * dx + dy * dy) + 0.0001,
tf = (dd - this.restLength) / (dd * (p1.massInv + p2.massInv)) * this.strength,
f;
// Apply forces
if (!p1.fixed) {
f = tf * p1.massInv;
p1.x += dx * f;
p1.y += dy * f;
}
if (!p2.fixed) {
f = -tf * p2.massInv;
p2.x += dx * f;
p2.y += dy * f;
}
}
};
function Sim() {
this.particles = [];
this.springs = [];
this.tick = function (dt) {
var i, n;
for (i = 0, n = this.springs.length; i < n; ++i) {
this.springs[i].update(dt);
}
for (i = 0, n = this.particles.length; i < n; ++i) {
this.particles[i].update(dt);
}
}
};
// Create a new system
var sim = new Sim(),
old = new Date().getTime(),
canvas = document.getElementById('world'),
context = canvas.getContext('2d');
function init() {
var np,
op,
mouse,
anchor,
step = STEP,
length = LENGTH,
count = length / step;
var sx = canvas.width * 0.5;
var sy = canvas.height * 0.5;
for (var i = 0; i < count; ++i) {
//np = new Particle(i*8,i*8,0.1+Math.random()*0.01);
np = new Particle(sx + (Math.random() - 0.5) * 200, sy + (Math.random() - 0.5) * 200, 0.1 + Math.random() * 0.01);
sim.particles.push(np);
if (i > 0) {
s = new Spring(np, op, step, 0.95);
sim.springs.push(s);
}
op = np;
}
// Fix the first particle
anchor = sim.particles[0];
//anchor.fixed = true;
anchor.x = 50;
anchor.y = 50;
// Move last particle with mouse
mouse = sim.particles[count - 1];
mouse.fixed = true;
canvas.addEventListener('mousemove', function (event) {
mouse.x = event.clientX;
mouse.y = event.clientY;
});
};
function step() {
var now = new Date().getTime(),
delta = now - old;
sim.tick(delta);
// Clear canvas
canvas.width = canvas.width;
var points = []; // Midpoints
var angles = []; // Delta angles
var i, n, p1, p2, dx, dy, mx, my, sin, cos, theta;
// Compute midpoints and angles
for (i = 0, n = sim.particles.length - 1; i < n; ++i) {
p1 = sim.particles[i];
p2 = sim.particles[i + 1];
dx = p2.x - p1.x;
dy = p2.y - p1.y;
mx = p1.x + dx * 0.5;
my = p1.y + dy * 0.5;
points[i] = {
x: mx,
y: my
};
angles[i] = Math.atan2(dy, dx);
}
// Render
context.beginPath();
for (i = 0, n = points.length; i < n; ++i) {
p1 = sim.particles[i];
p2 = points[i];
theta = angles[i];
r = Math.sin((i / n) * Math.PI) * THICKNESS;
sin = Math.sin(theta - HALF_PI) * r;
cos = Math.cos(theta - HALF_PI) * r;
context.quadraticCurveTo(
p1.x + cos,
p1.y + sin,
p2.x + cos,
p2.y + sin);
}
for (i = points.length - 1; i >= 0; --i) {
p1 = sim.particles[i + 1];
p2 = points[i];
theta = angles[i];
r = Math.sin((i / n) * Math.PI) * THICKNESS;
sin = Math.sin(theta + HALF_PI) * r;
cos = Math.cos(theta + HALF_PI) * r;
context.quadraticCurveTo(
p1.x + cos,
p1.y + sin,
p2.x + cos,
p2.y + sin);
}
context.strokeStyle = 'rgba(255,255,255,0.1)';
context.lineWidth = 8;
context.stroke();
context.strokeStyle = 'rgba(0,0,0,0.8)';
context.lineWidth = 0.5;
context.stroke();
context.fillStyle = 'rgba(255,255,255,0.9)';
context.fill();
old = now;
setTimeout(step, FPS);
};
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener("resize", resize);
resize();
init();
step();
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,600,700' rel='stylesheet' type='text/css'>
<canvas id='world' width='500' height='500'></canvas>
<header><h1>Wiggle your mouse...</h1></header>
Here is one way:
HTML:
<div class="top">
top
</div>
<div class="middle">
<canvas id='world' width='500' height='500'></canvas>
<header><h1>Wiggle your mouse...</h1></header>
</div>
<div class="bottom">
bottom
</div>
CSS:
div {
border: 1px solid black
}
.top, .bottom {
height: 200px
}
The js remains the same. The CSS gives the top and bottom divs some height. The canvas is in the middle div. Here is a jsfiddle: https://jsfiddle.net/av902pcs/

Why is camera's position not correctly calculated (canvas)

I am making a clone of agar.io and I am stuck in my code. I can't understand why my camera's position is not correctly calculated. I want my camera's position to half the vector between the farthest blob and the closest blob.
Below is a picture and my code:
<html>
<head>
<title>Play Agario Clone</title>
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<canvas id="game">
kindly update your browser.
</canvas>
<script>
var
canvas,
ctx,
width = innerWidth,
height = innerHeight,
mouseX = 0,
mouseY = 0;
var
camera = {
x: 0,
y: 0,
// camera
update: function(obj) {
var farthestBlobX = Math.max.apply(0, obj.blobs.map(function(cell) { return cell.x }));
var farthestBlobY = Math.max.apply(0, obj.blobs.map(function(cell) { return cell.y }));
var closestBlobX = Math.min.apply(0, obj.blobs.map(function(cell) { return cell.x }));
var closestBlobY = Math.min.apply(0, obj.blobs.map(function(cell) { return cell.y }));
var x = farthestBlobX - closestBlobX;
var y = farthestBlobY - closestBlobY;
var length = Math.sqrt(x * x + y * y);
this.x = length/2 - width/2;
this.y = length/2 - height/2;
}
},
player = {
defaultMass: 54,
x: 0,
y: 0,
blobs: [],
update: function () {
for (var i = 0; i < this.blobs.length; i ++) {
var x = mouseX + camera.x - this.blobs[i].x;
var y = mouseY + camera.y - this.blobs[i].y;
var length = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
var speed = 54/this.blobs[i].mass;
this.blobs[i].velX = x/length * speed * Math.min(1, Math.pow(x / this.blobs[i].mass, 2));
this.blobs[i].velY = y/length * speed * Math.min(1, Math.pow(x / this.blobs[i].mass, 2));
this.blobs[i].x += this.blobs[i].velX;
this.blobs[i].y += this.blobs[i].velY;
for (var j = 0; j < this.blobs.length; j ++) {
if (j != i && this.blobs[i] !== undefined) {
var blob1 = this.blobs[i];
var blob2 = this.blobs[j];
var x = blob2.x - blob1.x;
var y = blob2.y - blob1.y;
var dist = Math.sqrt(x * x + y * y);
if (dist < blob1.mass + blob2.mass) {
x /= dist;
y /= dist;
blob1.x = blob2.x - x * (blob1.mass + blob2.mass);
blob1.y = blob2.y - y * (blob1.mass + blob2.mass);
}
}
}
}
this.x += (mouseX - width/2)/(width/2) * 1;
this.y += (mouseY - height/2)/(height/2) * 1
},
split: function (cell) {
cell.mass /= 2;
this.blobs.push({
x: cell.x,
y: cell.y,
mass: cell.mass
});
},
draw: function () {
for (var i = 0; i < this.blobs.length; i ++) {
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc(-camera.x + this.blobs[i].x, -camera.y + this.blobs[i].y, this.blobs[i].mass, 0, Math.PI*2);
ctx.fill();
ctx.closePath();
}
}
};
function handleMouseMove (e) {
mouseX = e.clientX;
mouseY = e.clientY;
}
function setup () {
canvas = document.getElementById("game");
ctx = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
addEventListener("mousemove", handleMouseMove);
player.blobs.push({
x: 0,
y: 0,
mass: player.defaultMass
});
player.blobs.push({
x: 100,
y: 100,
mass: player.defaultMass/2
});
player.blobs.push({
x: 100,
y: 100,
mass: player.defaultMass*2
});
var loop = function () {
update();
draw();
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
}
function update () {
camera.update(player);
player.update();
}
function draw () {
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, width, height);
player.draw();
}
setup();
</script>
</body>
</html>
Instead of computing everything relative to your camera, use your camera to set the global transformation matrix of your canvas, and only for this.
This way, your blobs' updates will be cleaner, and your camera easier to manage.
Now to get the middle position between two points, do (pt1 + pt2) / 2.
You were not clear in your question, if fartherstX and fartherstY should represent the same blob. In your code it wasn't, so I didn't change it.
Also, I didn't gone into all your logics, but beware NaN values, I got some while doing the edit.
function draw() {
var cw = ctx.canvas.width / 2;
var ch = ctx.canvas.height / 2;
// reset transform to clear the canvas
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, width, height);
// here we really set the camera position
ctx.setTransform(1, 0, 0, 1, -camera.x + cw, -camera.y + ch);
ctx.strokeRect(0, 0, width, height); // just to show the original area
player.draw();
}
var
canvas,
ctx,
width = innerWidth,
height = innerHeight,
mouseX = 0,
mouseY = 0;
var camera = {
x: 0,
y: 0,
// camera
update: function(obj) {
var farthestBlobX = Math.max.apply(0, obj.blobs.map(function(cell) {
return cell.x
}));
var farthestBlobY = Math.max.apply(0, obj.blobs.map(function(cell) {
return cell.y
}));
var closestBlobX = Math.min.apply(0, obj.blobs.map(function(cell) {
return cell.x
}));
var closestBlobY = Math.min.apply(0, obj.blobs.map(function(cell) {
return cell.y
}));
this.x = (closestBlobX + farthestBlobX) / 2 || 0;
this.y = (closestBlobY + farthestBlobY) / 2 || 0;
}
},
player = {
defaultMass: 54,
x: 0,
y: 0,
blobs: [],
update: function() {
for (var i = 0; i < this.blobs.length; i++) {
var x = mouseX - this.blobs[i].x || 0;
var y = mouseY - this.blobs[i].y || 0;
var length = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
var speed = 54 / this.blobs[i].mass;
this.blobs[i].velX = x / length * speed * Math.min(1, Math.pow(x / this.blobs[i].mass, 2));
this.blobs[i].velY = y / length * speed * Math.min(1, Math.pow(x / this.blobs[i].mass, 2));
this.blobs[i].x += this.blobs[i].velX;
this.blobs[i].y += this.blobs[i].velY;
for (var j = 0; j < this.blobs.length; j++) {
if (j != i && this.blobs[i] !== undefined) {
var blob1 = this.blobs[i];
var blob2 = this.blobs[j];
var x = blob2.x - blob1.x;
var y = blob2.y - blob1.y;
var dist = Math.sqrt(x * x + y * y);
if (dist < blob1.mass + blob2.mass) {
x /= dist;
y /= dist;
blob1.x = blob2.x - x * (blob1.mass + blob2.mass);
blob1.y = blob2.y - y * (blob1.mass + blob2.mass);
}
}
}
}
this.x += (mouseX - width / 2) / (width / 2) * 1;
this.y += (mouseY - height / 2) / (height / 2) * 1;
},
split: function(cell) {
cell.mass /= 2;
this.blobs.push({
x: cell.x,
y: cell.y,
mass: cell.mass
});
},
draw: function() {
for (var i = 0; i < this.blobs.length; i++) {
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc(this.blobs[i].x, this.blobs[i].y, this.blobs[i].mass, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
}
}
};
function handleMouseMove(e) {
mouseX = e.clientX;
mouseY = e.clientY;
}
function setup() {
canvas = document.getElementById("game");
ctx = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
addEventListener("mousemove", handleMouseMove);
player.blobs.push({
x: 10,
y: 10,
mass: player.defaultMass
});
player.blobs.push({
x: 100,
y: 100,
mass: player.defaultMass / 2
});
player.blobs.push({
x: 100,
y: 100,
mass: player.defaultMass * 2
});
var loop = function() {
update();
draw();
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
}
function update() {
camera.update(player);
player.update();
}
setup();
body {
margin: 0;
padding: 0;
}
<canvas id="game">kindly update your browser.</canvas>
I see there is an answer already..
var canvas;
var ctx;
var width = innerWidth;
var height = innerHeight;
var mouseX = 0;
var mouseY = 0;
const camera = {
x : 0,
y : 0,
update(obj) { // camera
this.x = (obj.blobsExtent.minx + obj.blobsExtent.maxx) / 2;
this.y = (obj.blobsExtent.miny + obj.blobsExtent.maxy) / 2;
this.x -= width / 2;
this.y -= height / 2;
}
};
const player = {
defaultMass : 54,
blobs : [],
blobsExtent : { // get the extent while updating the blobs save you having to iterate all the objects a second time to get extent
minx :0,
miny : 0,
maxx : 0,
maxy : 0,
},
update () {
var be = this.blobsExtent; // be for Blob Extent alias to save typing and make code easier to read
for (var i = 0; i < this.blobs.length; i++) {
var blob1 = this.blobs[i];
var x = mouseX - blob1.x;
var y = mouseY - blob1.y;
// to stop the divide by zero propigating NaN set length to 1 if less than 1
var length = Math.max(1,Math.sqrt(x * x + y * y)); // x * x is quicker than Math.pow(x,2)
var speed = 54 / blob1.mass;
blob1.velX = x / length * speed * Math.min(1, Math.pow(x / blob1.mass, 2));
blob1.velY = y / length * speed * Math.min(1, Math.pow(x / blob1.mass, 2));
blob1.x += blob1.velX;
blob1.y += blob1.velY;
for (var j = 0; j < this.blobs.length; j++) {
if (j != i) {
var blob2 = this.blobs[j];
var x = blob2.x - blob1.x;
var y = blob2.y - blob1.y;
var dist = Math.sqrt(x * x + y * y);
var radTotal = blob1.mass + blob2.mass;
if (dist < radTotal) {
x /= dist;
y /= dist;
blob1.x = blob2.x - x * radTotal;
blob1.y = blob2.y - y * radTotal;
}
}
}
if(i === 0){ // use first blob to setup min max
be.maxx = be.minx = blob1.x;
be.maxy = be.miny = blob1.y;
}else{
be.maxx = Math.max(be.maxx, blob1.x);
be.maxy = Math.max(be.maxy, blob1.y);
be.minx = Math.min(be.minx, blob1.x);
be.miny = Math.min(be.miny, blob1.y);
}
}
},
split (cell) {
cell.mass /= 2;
this.blobs.push(createBlob(cell.x, cell.y, cell.mass));
},
draw () {
var b; // alias for blob
ctx.fillStyle = "red"; // all the same colour then can render as one path
ctx.setTransform(1,0,0,1,-camera.x,-camera.y);
ctx.beginPath();
for (var i = 0; i < this.blobs.length; i++) {
b = this.blobs[i];
ctx.arc( b.x, b.y, b.mass, 0, Math.PI * 2);
ctx.closePath();
}
ctx.fill();
ctx.setTransform(1,0,0,1,0,0); // restore default transform
}
};
function handleMouseMove(e) {
mouseX = e.clientX + camera.x;
mouseY = e.clientY + camera.y;
}
function createBlob(x,y,mass){ return {x,y,mass} }
function setup() {
canvas = document.getElementById("game");
ctx = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
addEventListener("mousemove", handleMouseMove);
player.blobs.push(createBlob(0,0,player.defaultMass));
player.blobs.push(createBlob(100,100,player.defaultMass / 2));
player.blobs.push(createBlob(100,100,player.defaultMass * 2));
}
function update() {
camera.update(player);
player.update();
}
function draw() {
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, width, height);
player.draw();
}
function loop() {
update();
draw();
requestAnimationFrame(loop);
}
setup();
requestAnimationFrame(loop);
body {
margin: 0;
padding: 0;
}
<canvas id="game"></canvas>

Is there a better way to accomplish this PIXI rope mouse follower?

I've created a simple mouse follower using PIXI.js. It creates evenly spaced points based on mouse movement and renders a textured PIXI.Rope object along those points. PIXI seems to be having a difficult time rendering the rope and I'm wondering if there would be a better way to accomplish this or whether I'm misusing the Rope object.
As you can see in the example below, this works effectively for the most part, but moving the mouse quickly or moving the rope over the top of itself results in glitches and artifacts that likely have something to do with the way that PIXI renders gradients (and my misunderstanding of it).
Please see:
http://plnkr.co/edit/6dB6QcKvSFlcT4k3OrMH?p=preview
(function()
{
document.addEventListener('DOMContentLoaded', function()
{
PIXI.Point = window.Vector;
var stage = new PIXI.Stage(0xFFFFFF);
var renderer = PIXI.autoDetectRenderer(500, 500);
document.body.appendChild(renderer.view);
var resizeWindow = function()
{
w = window.innerWidth;
h = window.innerHeight;
renderer.resize(w,h);
renderer.view.height = h;
renderer.view.width = w;
}
resizeWindow()
window.addEventListener('resize', resizeWindow)
var tRope, rope, skeleton;
var isDrawing = true, points = [], pointsSkeleton = [], threshold_lower = 10, threshold_upper = 15, lineLength = 1000;
var animate;
tRope = PIXI.Texture.fromImage("http://new.wethecollective.com/junk/rope2.png");
tRope.height = 22;
tRope.width = 1000;
tBone = PIXI.Texture.fromImage("http://new.wethecollective.com/junk/bone.png");
tBone.height = 10;
tBone.width = 10;
var addPoint = function(point, addToSkeleton)
{
if(addToSkeleton !== false)
{
addToSkeleton = true
}
points.push(point);
if(addToSkeleton)
{
var bone = new PIXI.Sprite(tBone);
bone.x = point.x - 5;
bone.y = point.y - 5;
pointsSkeleton[points.length -1] = skeleton.addChild(bone);
}
}
var removePoint = function(index)
{
points.splice(index, 1);
skeleton.removeChild(pointsSkeleton[index]);
pointsSkeleton.splice(index, 1);
}
animate = function()
{
requestAnimationFrame(animate);
// render the stage
renderer.render(stage);
}
var rlength = 0
while(rlength < lineLength)
{
rlength += threshold_upper;
addPoint(new PIXI.Point(rlength, 100), false);
}
rope = new PIXI.Rope(tRope, points);
skeleton = new PIXI.DisplayObjectContainer();
stage.addChild(rope);
stage.addChild(skeleton);
document.body.addEventListener('mousemove', function(e)
{
var pos = new PIXI.Point(e.clientX, e.clientY);
var v = pos.clone().sub(points[points.length - 1]);
l = v.length()
if(l > threshold_lower)
{
if(l <= threshold_upper)
{
addPoint(pos);
} else
{
var segment_l = 0;
var divisions = Math.floor(l / threshold_upper)
var divisionlength = l / divisions;
var lastPos = points[points.length - 1];
for(var i = 0; i < divisions; i++)
{
var v1 = v.clone();
v1.setLength(divisionlength);
v1.add(lastPos);
addPoint(v1);
segment_l += v1.length();
lastPos = v1;
}
}
}
totalLength = 0;
for(var i =0; i < points.length; i++)
{
if(i>0)
{
totalLength += points[i-1].clone().sub(points[i]).length()
}
}
if(totalLength > lineLength)
{
var pointsnum = points.length;
for(var i=0; i < pointsnum; i++)
{
var p = points[i].clone();
totalLength -= p.sub(points[i+1]).length()
removePoint(i);
i--;
pointsnum--;
if(totalLength <= lineLength)
{
break;
}
}
}
});
animate();
});
})();
(function(NS)
{
/*
* #class Vector
* #constructor
* #param x {Number} position of the point
* #param y {Number} position of the point
*/
NS.Vector = function(x, y)
{
/**
* #property x
* #type Number
* #default 0
*/
this.x = x || 0;
/**
* #property y
* #type Number
* #default 0
*/
this.y = y || 0;
};
/**
* Creates a clone of this point
*
* #method clone
* #return {Vector} a copy of the point
*/
NS.Vector.prototype.clone = function()
{
return new NS.Vector(this.x, this.y);
};
NS.Vector.prototype.add = function(v) {
this.x += v.x;
this.y += v.y;
return this;
};
NS.Vector.prototype.sub = function(v) {
this.x -= v.x;
this.y -= v.y;
return this;
};
NS.Vector.prototype.invert = function(v) {
this.x *= -1;
this.y *= -1;
return this;
};
NS.Vector.prototype.multiplyScalar = function(s) {
this.x *= s;
this.y *= s;
return this;
};
NS.Vector.prototype.divideScalar = function(s) {
if(s === 0) {
this.x = 0;
this.y = 0;
} else {
var invScalar = 1 / s;
this.x *= invScalar;
this.y *= invScalar;
}
return this;
};
NS.Vector.prototype.dot = function(v) {
return this.x * v.x + this.y * v.y;
};
NS.Vector.prototype.length = function(v) {
return Math.sqrt(this.x * this.x + this.y * this.y);
};
NS.Vector.prototype.lengthSq = function() {
return this.x * this.x + this.y * this.y;
};
NS.Vector.prototype.normalize = function() {
return this.divideScalar(this.length());
};
NS.Vector.prototype.distanceTo = function(v) {
return Math.sqrt(this.distanceToSq(v));
};
NS.Vector.prototype.distanceToSq = function(v) {
var dx = this.x - v.x, dy = this.y - v.y;
return dx * dx + dy * dy;
};
NS.Vector.prototype.set = function(x, y) {
this.x = x;
this.y = y;
return this;
};
NS.Vector.prototype.setX = function(x) {
this.x = x;
return this;
};
NS.Vector.prototype.setY = function(y) {
this.y = y;
return this;
};
NS.Vector.prototype.setLength = function(l) {
var oldLength = this.length();
if(oldLength !== 0 && l !== oldLength) {
this.multiplyScalar(l / oldLength);
}
return this;
};
NS.Vector.prototype.invert = function(v) {
this.x *= -1;
this.y *= -1;
return this;
};
NS.Vector.prototype.lerp = function(v, alpha) {
this.x += (v.x - this.x) * alpha;
this.y += (v.y - this.y) * alpha;
return this;
};
NS.Vector.prototype.rad = function() {
return Math.atan2(this.x, this.y);
};
NS.Vector.prototype.deg = function() {
return this.rad() * 180 / Math.PI;
};
NS.Vector.prototype.equals = function(v) {
return this.x === v.x && this.y === v.y;
};
NS.Vector.prototype.rotate = function(theta) {
var xtemp = this.x;
this.x = this.x * Math.cos(theta) - this.y * Math.sin(theta);
this.y = xtemp * Math.sin(theta) + this.y * Math.cos(theta);
return this;
};
// constructor
NS.Vector.prototype.constructor = NS.Vector;
})(window)
Please forgive my spaghetti code. I've just been building this out as a proof of concept at the moment.
I fixed this by physically removing the rope from stage and reinitialising it on each render pass. It feels a little hacky to me, but it does work.
animate = function()
{
requestAnimationFrame(animate);
stage.removeChild(rope);
rope = new PIXI.Rope(tRope, points);
stage.addChildAt(rope,0);
// render the stage
renderer.render(stage);
}

Categories

Resources