为什么圆圈没有正确分开

时间:2018-03-23 14:37:02

标签: javascript canvas

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

获得了我的代码的矢量posrtion
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>

0 个答案:

没有答案