为什么没有正确计算相机的位置(画布)

时间:2017-05-13 13:52:05

标签: javascript math canvas

我正在制作一个agar.io的克隆,我被困在我的代码中。我无法理解为什么我的相机位置没有正确计算。我希望我的相机位置在最远的斑点和最近的斑点之间的矢量的一半。

下面是一张图片和我的代码:

enter image description here

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

2 个答案:

答案 0 :(得分:2)

不是计算与相机相关的所有内容,而是使用相机设置画布的全局变换矩阵,仅用于此。
这样,您的blob更新将更加清晰,并且您的相机更易于管理。

现在要获得两点之间的中间位置,请(pt1 + pt2) / 2 如果fartherstXfartherstY代表相同的blob,那么您的问题就不清楚了。在你的代码中没有,所以我没有改变它。

另外,我没有进入你的所有逻辑,但要注意NaN值,我在编辑时得到了一些。

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>

答案 1 :(得分:1)

我看到已有答案..

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>