如何运行单个对象JavaScript的多个实例

时间:2018-03-21 16:14:04

标签: javascript physics

目前正在尝试对圆形的弹性碰撞进行物理模拟。我遇到了一个问题,我不知道如何在两个圆同时进行交互的情况下运行模拟。我还没有想要创建圆圈之间的互动,只是让它们同时运行。任何帮助深表感谢。这是我的第一篇文章,所以如果我格式化错误,我会道歉。

var width = 400;
var height = 400;
var canvas = ctx = false;
var frameRate = 1 / 60; // Seconds
var frameDelay = frameRate * 1000; // ms
var loopTimer = false;
var ball = {
  position: {
    x: width / 2,
    y: height / 2
  },
  velocity: {
    x: 0,
    y: 0
  },
  radius: 15, // 1px = 1cm
  restitution: -1
};
var mouse = {
  x: 0,
  y: 0,
  isDown: false
};

function getMousePosition(event) {
  mouse.x = event.pageX - canvas.offsetLeft;
  mouse.y = event.pageY - canvas.offsetTop;
}
var mouseDown = function(event) {
  if (event.which == 1) {
    getMousePosition(event);
    mouse.isDown = true;
    ball.position.x = mouse.x;
    ball.position.y = mouse.y;
  }
}
var mouseUp = function(event) {
  if (event.which == 1) {
    mouse.isDown = false;
    ball.velocity.y = (ball.position.y - mouse.y) / 10;
    ball.velocity.x = (ball.position.x - mouse.x) / 10;
  }
}
var setup = function() {
  canvas = document.getElementById("canvas");
  ctx = canvas.getContext("2d");
  canvas.onmousemove = getMousePosition;
  canvas.onmousedown = mouseDown;
  canvas.onmouseup = mouseUp;
  ctx.fillStyle = 'blue';
  ctx.strokeStyle = '#000000';
  loopTimer = setInterval(loop, frameDelay);
}
var loop = function() {
  if (!mouse.isDown) {
    ball.position.x += ball.velocity.x * frameRate * 100;
    ball.position.y += ball.velocity.y * frameRate * 100;
  }
  if (ball.position.y > height - ball.radius) {
    ball.velocity.y *= ball.restitution;
    ball.position.y = height - ball.radius;
  }
  if (ball.position.x > width - ball.radius) {
    ball.velocity.x *= ball.restitution;
    ball.position.x = width - ball.radius;
  }
  if (ball.position.x < ball.radius) {
    ball.velocity.x *= ball.restitution;
    ball.position.x = ball.radius;
  }
  if (ball.position.y < ball.radius) {
    ball.velocity.y *= ball.restitution;
    ball.position.y = ball.radius;
  }
  ctx.clearRect(0, 0, width, height);
  ctx.save();
  ctx.translate(ball.position.x, ball.position.y);
  ctx.beginPath();
  ctx.arc(0, 0, ball.radius, 0, Math.PI * 2, true);
  ctx.fill();
  ctx.closePath();
  ctx.restore();
  if (mouse.isDown) {
    ctx.beginPath();
    ctx.moveTo(ball.position.x, ball.position.y);
    ctx.lineTo(mouse.x, mouse.y);
    ctx.stroke();
    ctx.closePath();
  }
}
setup();
#canvas {
  border: solid 1px #ccc;
}
<canvas id="canvas"></canvas>

2 个答案:

答案 0 :(得分:0)

我将如何做到这一点:

我没有将球作为一种静态物体,而是制作了一个构造函数(More about that here)。

然后我制作了一个球阵列来存放所有的球。

为了使拖动成为可能,我存储了一个单独的球,这个球没有被&#34;物理&#34;在newBall变量中。这个球要么是看不见的,要么就是当前被拖拽的球。

mouseDown() newBall位于光标下方。 在mouseUp()中,它获得了它的速度并被添加到动画balls的数组中。此外,还会创建一个新的newBall

loop()中,我在动画balls数组中循环两次。曾经为物理学,一次为绘画。 (通常你会使用两种不同的tickRates方法来使动画更加流畅,因为物理计算不需要每秒发生60次。

&#13;
&#13;
var width = 400;
var height = 400;
var canvas = ctx = false;
var frameRate = 1 / 60; // Seconds
var frameDelay = frameRate * 1000; // ms
var loopTimer = false;

function ball() {
  this.position = {
    x: width / 2,
    y: height / 2
  };
  this.velocity = {
    x: 0,
    y: 0
  };
  this.radius = 15; // 1px = 1cm
  this.restitution = -1
};
var balls = [];
var newBall = new ball();


var mouse = {
  x: 0,
  y: 0,
  isDown: false
};

function getMousePosition(event) {
  mouse.x = event.pageX - canvas.offsetLeft;
  mouse.y = event.pageY - canvas.offsetTop;
}

var mouseDown = function(event) {
  if (event.which == 1) {
    getMousePosition(event);
    mouse.isDown = true;
    newBall.position.x = mouse.x;
    newBall.position.y = mouse.y;
  }
}
var mouseUp = function(event) {
  if (event.which == 1) {
    mouse.isDown = false;
    newBall.velocity.y = (newBall.position.y - mouse.y) / 10;
    newBall.velocity.x = (newBall.position.x - mouse.x) / 10;
    balls.push(newBall);
    newBall = new ball();
  }
}
var setup = function() {
  canvas = document.getElementById("canvas");
  ctx = canvas.getContext("2d");
  canvas.onmousemove = getMousePosition;
  canvas.onmousedown = mouseDown;
  canvas.onmouseup = mouseUp;
  ctx.fillStyle = 'blue';
  ctx.strokeStyle = '#000000';
  loopTimer = setInterval(loop, frameDelay);
}
var loop = function() {
  for (var ball of balls) {
    ball.position.x += ball.velocity.x * frameRate * 100;
    ball.position.y += ball.velocity.y * frameRate * 100;

    if (ball.position.y > height - ball.radius) {
      ball.velocity.y *= ball.restitution;
      ball.position.y = height - ball.radius;
    }
    if (ball.position.x > width - ball.radius) {
      ball.velocity.x *= ball.restitution;
      ball.position.x = width - ball.radius;
    }
    if (ball.position.x < ball.radius) {
      ball.velocity.x *= ball.restitution;
      ball.position.x = ball.radius;
    }
    if (ball.position.y < ball.radius) {
      ball.velocity.y *= ball.restitution;
      ball.position.y = ball.radius;
    }
  }
  ctx.clearRect(0, 0, width, height);
  for (var ball of balls) {
    ctx.save();
    ctx.translate(ball.position.x, ball.position.y);
    ctx.beginPath();
    ctx.arc(0, 0, ball.radius, 0, Math.PI * 2, true);
    ctx.fill();
    ctx.closePath();
    ctx.restore();
  }

  ctx.save();
  ctx.translate(newBall.position.x, newBall.position.y);
  ctx.beginPath();
  ctx.arc(0, 0, newBall.radius, 0, Math.PI * 2, true);
  ctx.fill();
  ctx.closePath();
  ctx.restore();

  if (mouse.isDown) {
    ctx.beginPath();
    ctx.moveTo(newBall.position.x, newBall.position.y);
    ctx.lineTo(mouse.x, mouse.y);
    ctx.stroke();
    ctx.closePath();
  }
}
setup();
&#13;
#canvas {
  border: solid 1px #ccc;
}
&#13;
<canvas id="canvas"></canvas>
&#13;
&#13;
&#13;

现在要复杂一点:

我添加了tickDelaytickTimer以在tickLoop中使用它们

ball构造函数现在有两种方法:

show()在画布上画球

tick()执行pysics的东西(dt = deltaTime:自上次打勾以来的时间)

如果鼠标未被按下,

newBall现在为null

setup()根据实际尺寸width元素初始化height<canvas>

tick()遍历球并调用.tick() tickDelay以毫秒为单位,因此它被除以1000

drawFrame()是你以前的loop()并且做绘图的东西

&#13;
&#13;
var width = 400;
var height = 400;
var canvas = ctx = false;
var frameRate = 1 / 60; // Seconds
var frameDelay = frameRate * 1000; // ms
var tickDelay = frameDelay * 2; //ticks 2 times slower than frames
var frameTimer;
var tickTimer;

function ball() {
  this.position = {
    x: width / 2,
    y: height / 2
  };
  this.velocity = {
    x: 0,
    y: 0
  };
  this.radius = 15; // 1px = 1cm
  this.restitution = -.99;
  this.show = function() {
    ctx.save();
    ctx.translate(this.position.x, this.position.y);
    ctx.beginPath();
    ctx.arc(0, 0, this.radius, 0, Math.PI * 2, true);
    ctx.fill();
    ctx.closePath();
    ctx.restore();
  };
  this.tick = function(dt) {
    this.position.x += this.velocity.x * dt;
    this.position.y += this.velocity.y * dt;

    if (this.position.y > height - this.radius) {
      this.velocity.y *= this.restitution;
      this.position.y = height - this.radius;
    }
    if (this.position.x > width - this.radius) {
      this.velocity.x *= this.restitution;
      this.position.x = width - this.radius;
    }
    if (this.position.x < this.radius) {
      this.velocity.x *= this.restitution;
      this.position.x = this.radius;
    }
    if (this.position.y < this.radius) {
      this.velocity.y *= this.restitution;
      this.position.y = this.radius;
    }
  }
};
var balls = [];
var newBall;


var mouse = {
  x: 0,
  y: 0,
  isDown: false
};

function getMousePosition(event) {
  mouse.x = event.pageX - canvas.offsetLeft;
  mouse.y = event.pageY - canvas.offsetTop;
}

function mouseDown(event) {
  if (event.which == 1) {
    getMousePosition(event);
    mouse.isDown = true;
    if (!newBall) newBall = new ball();
    newBall.position.x = mouse.x;
    newBall.position.y = mouse.y;
  }
}

function mouseUp(event) {
  if (event.which == 1) {
    mouse.isDown = false;
    newBall.velocity.y = (newBall.position.y - mouse.y);
    newBall.velocity.x = (newBall.position.x - mouse.x);
    balls.push(newBall);
    newBall = null;
  }
}

function setup() {
  canvas = document.getElementById("canvas");
  width = canvas.getBoundingClientRect().width;
  height = canvas.getBoundingClientRect().height;
  ctx = canvas.getContext("2d");
  canvas.onmousemove = getMousePosition;
  canvas.onmousedown = mouseDown;
  canvas.onmouseup = mouseUp;
  ctx.fillStyle = 'blue';
  ctx.strokeStyle = '#000000';
  requestAnimationFrame(drawFrame);
  frameTimer = setInterval(drawFrame, frameDelay);
  tickTimer = setInterval(tick, tickDelay);
}

function tick() {
  for (var ball of balls) ball.tick(tickDelay * .001);
}

function drawFrame() {
  ctx.clearRect(0, 0, width, height);
  for (var ball of balls) ball.show();
  if (newBall) newBall.show(ctx);

  if (mouse.isDown && newBall) {
    ctx.beginPath();
    ctx.moveTo(newBall.position.x, newBall.position.y);
    ctx.lineTo(mouse.x, mouse.y);
    ctx.stroke();
    ctx.closePath();
  }
}
setup();
&#13;
#canvas {
  border: solid 1px #ccc;
}
&#13;
<canvas id="canvas"></canvas>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

一种非常简单的方法可以与您现在完全相同,但不会将所有函数作为变量启动。将所有函数的变量更改为函数,以及调用它们的位置。至少变量叫做ball。然后你就可以制作两个这样的变量

ball1 = new ball();
ball2 = new ball();

你的剧本有点混乱,我很难说如果没有任何错误会这样做,但如果确实如此,我很乐意提供帮助。如果您只是按照我现在提供的方式进行操作,这不是最好的解决方案,所以请不要将其作为解决方案使用,而应将其作为一种入门方式。如果我们只是给你答案,你也不会真正学到任何东西

编辑:

另一件需要注意的事情是,对于游戏和图形项目使用setInterval可能是一个坏主意,因为JavaScript是单线程的。更好的解决方案是使用requestAnimationFrame()

它看起来像这样

function mainLoop() {
update();
draw();
requestAnimationFrame(mainLoop);
}

// Start things off
requestAnimationFrame(mainLoop);