我有这个代码用于分隔两个圆圈。问题在于,只要其中一个圆的半径发生变化(即变得比另一个更大或更小),圆就开始在其他地方移动。我试图将圆圈分开()。我不太了解矢量。我从Why circles are vibrating on collision (Canvas)
获得了我的代码的矢量posrtionCollisionHandler.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>