改进我的分裂机制,使其像agar.io一样

时间:2017-05-15 12:49:50

标签: javascript canvas

我几天来一直在克隆agar.io。我已经完成了分割功能。但是我的分裂机制既古老又无聊。我希望它像agar.io一样(以更快的速度加速并减速)。打开agar.io并播放一次,你会知道我期待改进的地方。

以下是我的代码。

var canvas,
  ctx,
  width = innerWidth,
  height = innerHeight,
  mouseX = 0,
  mouseY = 0;

var camera = {
    x: 0,
    y: 0,

    // camera
    update: function(obj) {
      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;
    }
  },

  player = {
    defaultMass: 54,
    x: 0,
    y: 0,
    blobs: [],

    blobsExtent: {
      minx: 0,
      miny: 0,
      maxx: 0,
      maxy: 0,
    },

    update: function() {
      var be = this.blobsExtent;
      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(y / 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);
            }
          }
        }

        if (i === 0) {
          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);
        }
      }

      this.x += (mouseX - width / 2) / (width / 2) * 1;
      this.y += (mouseY - height / 2) / (height / 2) * 1
    },

    split: function(cell) {
      if (cell.mass >= this.defaultMass) {
        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 handleKeydown(e) {
  if (e.keyCode == 32) {
    var currentLength = player.blobs.length;
    for (var i = 0; i < currentLength; i++) {
      player.split(player.blobs[i]);
    }
  }
}

function setup() {
  canvas = document.getElementById("game");
  ctx = canvas.getContext("2d");
  canvas.width = width;
  canvas.height = height;

  addEventListener("mousemove", handleMouseMove);
  addEventListener("keydown", handleKeydown);

  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
  });
  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);

  ctx.fillStyle = "green";
  ctx.fillRect(-camera.x + 0, -camera.y + 0, 20, 20);

  player.draw();
}

setup();
body {
  margin: 0;
  padding: 0;
}
<title>Play Agario Clone</title>
<canvas id="game">Kindly update your browser.</canvas>

空格键分裂。

我希望分裂的blob首先以更高的速度运行然后减速。所有blob更新都是从player.update

完成的

1 个答案:

答案 0 :(得分:1)

有点乱,因为我没有那么多时间。添加了快速背景网格以显示移动。

将速度属性添加回blob并使用它来控制所有blob的速度,而不仅仅是分裂的blob。当一个blob分裂时,我给两个分裂的blob一个新的速度(8但是由你决定)

如果速度&gt;计算每个斑点的速度之后。 1(在分裂斑点的情况下)我通过乘以非常接近1(0.995)的数字来降低速度,这会在很多帧上缓慢降低速度。你将这个数字越接近1,加速时间越长。数字必须低于1或blob将继续变得越来越快。

&#13;
&#13;
// need something to see relative movement so this is to add a background grid
var gPattern;

function createGridPattern() {
  const grid = document.createElement("canvas");
  grid.width = 128;
  grid.height = 128;
  grid.ctx = grid.getContext("2d");
  grid.ctx.fillStyle = "white";
  grid.ctx.fillRect(0, 0, 128, 128);
  const alphas = [1, 0.2, 0.4, 0.2];
  grid.ctx.fillStyle = "black";

  for (var x = 0; x < 128; x += 16) {
    grid.ctx.globalAlpha = alphas[(x / 16) % 4];
    grid.ctx.fillRect(x, 0, 1, 128);
    grid.ctx.fillRect(0, x, 128, 1);
  }

  return ctx.createPattern(grid,"repeat");
}





var
  canvas,
  ctx,
  width = innerWidth,
  height = innerHeight,
  mouseX = 0,
  mouseY = 0;

var

  camera = {
    x: 0,
    y: 0,

    // camera
    update: function(obj) {
      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;
    }
  },

  player = {
    defaultMass: 54,
    x: 0,
    y: 0,
    blobs: [],

    blobsExtent: {
      minx: 0,
      miny: 0,
      maxx: 0,
      maxy: 0,
    },

    update: function() {
      var be = this.blobsExtent;
      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 * this.blobs[i].speed * Math.min(1, Math.pow(x / this.blobs[i].mass, 2));
        this.blobs[i].velY = y / length * this.blobs[i].speed * Math.min(1, Math.pow(y / this.blobs[i].mass, 2));
        if(this.blobs[i].speed > 1){
            this.blobs[i].speed *= 0.995; // make speed a little slow each frame
                       // make the 0.995 closer to 1 to make the speedup last longer
                       // eg 0.999 will keep speed longer
                       // this number must be less than 1
        }else{
            this.blobs[i].speed = 1;
        }
        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);
            }
          }
        }

        if (i === 0) {
          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);
        }
      }

      this.x += (mouseX - width / 2) / (width / 2) * 1;
      this.y += (mouseY - height / 2) / (height / 2) * 1
    },

    split: function(cell) {
      if (cell.mass >= this.defaultMass) {
        cell.mass /= 2;
        cell.speed = 8;  // this is the amount of extra speed when split

        this.blobs.push({
          x: cell.x,
          y: cell.y,
          mass: cell.mass,
          speed : 8,  // this is the amount of extra speed when split
        });
      }
    },

    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 handleKeydown(e) {
  if (e.keyCode == 32) {
    var currentLength = player.blobs.length;
    for (var i = 0; i < currentLength; i++) {
      player.split(player.blobs[i]);
    }
  }
}

function setup() {
  canvas = document.getElementById("game");
  ctx = canvas.getContext("2d");
  canvas.width = width;
  canvas.height = height;

  addEventListener("mousemove", handleMouseMove);
  addEventListener("keydown", handleKeydown);

  player.blobs.push({
    x: 0,
    y: 0,
    speed : 1,
    mass: player.defaultMass
  });
  player.blobs.push({
    x: 100,
    y: 100,
    speed : 1,
    
    mass: player.defaultMass / 2
  });
  player.blobs.push({
    x: 100,
    y: 100,
    speed : 1,
    mass: player.defaultMass / 2
  });
  player.blobs.push({
    x: 100,
    y: 100,
    speed : 1,
    mass: player.defaultMass / 2
  });
  player.blobs.push({
    x: 100,
    y: 100,
    speed : 1,
    mass: player.defaultMass * 2
  });

  var loop = function() {
    update();
    draw();
    requestAnimationFrame(loop);
  }
  
  gPattern = createGridPattern();
  loop();

}

function update() {
  camera.update(player);
  player.update();
}

function draw() {
  ctx.fillStyle = gPattern;

  ctx.setTransform(1,0,0,1,(-camera.x % 128) - 128, (-camera.y % 128) - 128);
  ctx.fillRect(0,0, width+256, height+256);
  ctx.setTransform(1,0,0,1,0,0);

  ctx.fillStyle = "green";
  ctx.fillRect(-camera.x + 0, -camera.y + 0, 20, 20);

  player.draw();
}

setup();
&#13;
canvas {
  border: 2px solid black;
  padding : 0px;
  margin : 0px;
}
&#13;
<canvas id="game">
	</canvas>
&#13;
&#13;
&#13;