简体   繁体   English

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

[英]How to run multiple instances of a single object JavaScript

Currently attempting to make a physics simulation for elastic collisions of circles. 当前正在尝试对圆的弹性碰撞进行物理模拟。 I am having an issue where I do not know how to run the simulation with two circles interacting at the same time. 我遇到了一个问题,即我不知道如何在两个圈子同时交互的情况下运行模拟。 I am not yet looking to create the interaction between the circles just to have them both running simultaneously. 我还没有希望在圈子之间建立互动,只是让它们同时运行。 Any help is much appreciated. 任何帮助深表感谢。 This is my first post so I apologize if I formatted something incorrectly. 这是我的第一篇文章,因此如果格式化不正确,我深表歉意。

 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> 

Here is how I would do it: 这是我的方法:

Instead of making the ball a kind of static object I made a constructor function ( More about that here ). 我没有使球成为一种静态对象,而是构造了一个构造函数( 更多有关此内容 )。

Then I made a ball array to store all the balls. 然后,我制作了一个球阵列来存储所有球。

To make the dragging possible I store a seperate ball, which is not being moved by "physics" in the newBall variable. 为了使拖动成为可能,我将一个单独的球存储在newBall变量中,该球不会被“物理”移动。 This ball is either invisible or is the ball currently being dragged. 该球不可见,或者是当前正在拖动的球。

In mouseDown() the newBall gets positioned under the cursor. mouseDown()newBall位于光标下方。 In mouseUp() it gets it's velocity and gets added to the array of animated balls . mouseUp()它获取速度并添加到动画balls数组中。 Also a new newBall gets created. 还创建了一个新的newBall

In loop() I loop two times through the array of animated balls . loop()我两次遍历动画balls数组。 Once for the physics, once for the painting. 一次是物理学,一次是绘画。 (Normally you would use two different methods with different tickRates to make animation more smooth, because physics calculation doesn't need to happen 60 times per second. (通常,您会使用带有不同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> 

Now to get a bit more complex: 现在变得更加复杂:

I added tickDelay and tickTimer to use them in a tickLoop 我添加了tickDelaytickTimer以在tickTimer中使用它们

The ball constructor now has two methods: ball构造器现在有两种方法:

show() draws the ball on the canvas show()在画布上绘制球

tick() does the pysics stuff ( dt = deltaTime: time since last tick) tick()进行物理处理( dt = deltaTime:自上次滴答以来的时间)

newBall is now null if the mouse isn't pressed 如果未按下鼠标,则newBall现在为null

setup() initializes the width and height according to the <canvas> elements real size setup()根据<canvas>元素的实际大小初始化widthheight

tick() loops through the balls and calls .tick() tickDelay is in milliseconds so it gets divided by 1000 tick()在球中循环并调用.tick() tickDelay以毫秒为单位,因此除以1000

drawFrame() is your former loop() and does the drawing stuff 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> 

A really simple way would to do exactly the same as you do now, but not initiate all functions as a variable. 一种非常简单的方法可以做与现在完全相同的操作,但是不能将所有函数都初始化为变量。 Change all the variables that are functions to just functions, and where you call them. 将所有作为函数的变量更改为仅函数,以及在何处调用它们。 At least the variable called ball. 至少变量称为ball。 Then after that you could make two variables like this 然后,您可以像这样创建两个变量

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

Your script is kind of messy so hard for me to say if this will go through without any errors, but if it does, I am more than happy to help. 您的脚本有点混乱,因此我很难说这是否可以顺利进行,但是如果可以,我非常乐意提供帮助。 This is not the very best solution if you only go for the way i presented now so please do not use this as you solution, but more as a way to get started. 如果仅按照我现在介绍的方式进行操作,这不是最好的解决方案,因此请不要将其用作解决方案,而应将其作为入门的一种方法。 Also you will not really learn anything of it if we just gave you the answer 如果我们给您答案,您也不会真正学到任何东西

Edit: 编辑:

Another thing to mark is that using setInterval for games and graphical projects may be a bad idea since JavaScript is single threaded. 值得一提的是,由于JavaScript是单线程的,因此将setInterval用于游戏和图形项目可能不是一个好主意。 A better solution is using requestAnimationFrame() 更好的解决方案是使用requestAnimationFrame()

It would look something like this 看起来像这样

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

// Start things off
requestAnimationFrame(mainLoop);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM