如何 运行 单个对象的多个实例 JavaScript
How to run multiple instances of a single object JavaScript
目前正在尝试对圆的弹性碰撞进行物理模拟。我遇到一个问题,我不知道如何 运行 两个圆圈同时交互的模拟。我还没有打算创建圈子之间的交互,只是为了让它们同时 运行ning。任何帮助深表感谢。这是我的第一个 post 如果我的格式不正确,我深表歉意。
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>
以下是我的做法:
我没有让球成为一种静态对象,而是创建了一个构造函数 (More about that here)。
然后我做了一个球数组来存放所有的球
为了使拖动成为可能,我在 newBall
变量中存储了一个单独的球,它不会被 "physics" 移动。这个球要么是不可见的,要么是当前正在拖动的球。
在 mouseDown()
中,newBall
位于光标下方。
在 mouseUp()
中,它获得速度并添加到动画数组 balls
中。还创建了一个新的 newBall
。
在 loop()
中,我在动画数组 balls
中循环两次。一次是物理,一次是绘画。
(通常你会使用两种不同的方法和不同的 tickRates 来使动画更流畅,因为物理计算不需要每秒发生 60 次。
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();
#canvas {
border: solid 1px #ccc;
}
<canvas id="canvas"></canvas>
现在要复杂一点:
我添加了 tickDelay
和 tickTimer
以在 tickLoop
中使用它们
ball
构造函数现在有两个方法:
show()
画球 canvas
tick()
做物理方面的事情(dt
= deltaTime:自上次滴答以来的时间)
如果未按下鼠标,newBall
现在是 null
setup()
根据<canvas>
元素实际大小
初始化width
和height
tick()
遍历球并调用 .tick()
tickDelay 以毫秒为单位,因此它被除以 1000
drawFrame()
是你以前的 loop()
并且会画画
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();
#canvas {
border: solid 1px #ccc;
}
<canvas id="canvas"></canvas>
一个非常简单的方法就是和你现在做的完全一样,但不是把所有的函数都作为一个变量来初始化。将所有作为函数的变量更改为函数,以及您调用它们的位置。至少变量叫球。然后你可以像这样制作两个变量
ball1 = new ball();
ball2 = new ball();
你的脚本有点乱,我很难说这是否会没有任何错误,但如果是这样,我非常乐意提供帮助。如果您只采用我现在介绍的方式,这不是最好的解决方案,所以请不要将其用作您的解决方案,而是将其作为一种入门方式。如果我们只是给你答案,你也不会真正学到任何东西
编辑:
另一件需要注意的事情是,对游戏和图形项目使用 setInterval 可能不是一个好主意,因为 JavaScript 是单线程的。更好的解决方案是使用 requestAnimationFrame()
看起来像这样
function mainLoop() {
update();
draw();
requestAnimationFrame(mainLoop);
}
// Start things off
requestAnimationFrame(mainLoop);
目前正在尝试对圆的弹性碰撞进行物理模拟。我遇到一个问题,我不知道如何 运行 两个圆圈同时交互的模拟。我还没有打算创建圈子之间的交互,只是为了让它们同时 运行ning。任何帮助深表感谢。这是我的第一个 post 如果我的格式不正确,我深表歉意。
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>
以下是我的做法:
我没有让球成为一种静态对象,而是创建了一个构造函数 (More about that here)。
然后我做了一个球数组来存放所有的球
为了使拖动成为可能,我在 newBall
变量中存储了一个单独的球,它不会被 "physics" 移动。这个球要么是不可见的,要么是当前正在拖动的球。
在 mouseDown()
中,newBall
位于光标下方。
在 mouseUp()
中,它获得速度并添加到动画数组 balls
中。还创建了一个新的 newBall
。
在 loop()
中,我在动画数组 balls
中循环两次。一次是物理,一次是绘画。
(通常你会使用两种不同的方法和不同的 tickRates 来使动画更流畅,因为物理计算不需要每秒发生 60 次。
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();
#canvas {
border: solid 1px #ccc;
}
<canvas id="canvas"></canvas>
现在要复杂一点:
我添加了 tickDelay
和 tickTimer
以在 tickLoop
ball
构造函数现在有两个方法:
show()
画球 canvas
tick()
做物理方面的事情(dt
= deltaTime:自上次滴答以来的时间)
newBall
现在是 null
setup()
根据<canvas>
元素实际大小
width
和height
tick()
遍历球并调用 .tick()
tickDelay 以毫秒为单位,因此它被除以 1000
drawFrame()
是你以前的 loop()
并且会画画
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();
#canvas {
border: solid 1px #ccc;
}
<canvas id="canvas"></canvas>
一个非常简单的方法就是和你现在做的完全一样,但不是把所有的函数都作为一个变量来初始化。将所有作为函数的变量更改为函数,以及您调用它们的位置。至少变量叫球。然后你可以像这样制作两个变量
ball1 = new ball();
ball2 = new ball();
你的脚本有点乱,我很难说这是否会没有任何错误,但如果是这样,我非常乐意提供帮助。如果您只采用我现在介绍的方式,这不是最好的解决方案,所以请不要将其用作您的解决方案,而是将其作为一种入门方式。如果我们只是给你答案,你也不会真正学到任何东西
编辑:
另一件需要注意的事情是,对游戏和图形项目使用 setInterval 可能不是一个好主意,因为 JavaScript 是单线程的。更好的解决方案是使用 requestAnimationFrame()
看起来像这样
function mainLoop() {
update();
draw();
requestAnimationFrame(mainLoop);
}
// Start things off
requestAnimationFrame(mainLoop);