2014-07-12 36 views
1

这是我依赖这个网站多年后的第一个问题!帆布水/ blob物理与纹理的圆形路径?

无论如何,我想完成类似这种效果:

http://www.flashmonkey.co.uk/html5/wave-physics/

不过的圆形轨道上,而不是地平线。本质上,屏幕中心会出现一个浮动的圆圈/斑点,它会对鼠标交互作出反应。我不在寻找的是重力,或者圆圈在屏幕周围反射 - 只有表面涟漪。

如果可能,我想将静态纹理应用于形状,这是否有可能?我对帆布完全陌生!

我已经尝试从以下链接循环的代码从上面的例子替换一些代码,非常有限的成功:

http://www.html5canvastutorials.com/tutorials/html5-canvas-circles/

如果只有它是那么容易:)

有任何想法吗?

提前致谢!

回答

2

我试图弄清楚波模拟如何使用View Source和JavaScript控制台工作。它工作正常,但抛出了一些JS错误。另外,看起来物理更新与render()方法中的渲染纠缠在一起。

这里是我发现有关代码:

mouseMove()方法基于鼠标位置的波产生的干扰,创造鼠标周围的峰值。变量target是需要更新的粒子的索引,它是从鼠标pos计算出来的。

if (particle && mouseY > particle.y) { 
    var speed = mouseY - storeY; 

    particles[target - 2].vy = speed/6; 
    particles[target - 1].vy = speed/5; 
    particles[target].vy = speed/3; 
    particles[target + 1].vy = speed/5; 
    particles[target + 2].vy = speed/6; 

    storeY = mouseY; 
} 

然后,颗粒周围target被更新。我发现的问题是,它没有边界检查,即当target == 0时它可能有particles[-1]。如果发生这种情况,会抛出异常,方法调用结束,但代码不会停止。

render()方法首先更新粒子位置,然后呈现波。

下面是其物理代码:

for (var u = particles.length - 1; u >= 0; --u) { 
    var fExtensionY = 0; 
    var fForceY = 0; 

    if (u > 0) { 
     fExtensionY = particles[u - 1].y - particles[u].y - springs[u - 1].iLengthY; 
     fForceY += -fK * fExtensionY; 
    } 

    if (u < particles.length - 1) { 
     fExtensionY = particles[u].y - particles[u + 1].y - springs[u].iLengthY; 
     fForceY += fK * fExtensionY; 
    } 

    fExtensionY = particles[u].y - particles[u].origY; 
    fForceY += fK/15 * fExtensionY; 

    particles[u].ay = -fForceY/particles[u].mass; 
    particles[u].vy += particles[u].ay; 
    particles[u].ypos += particles[u].vy; 
    particles[u].vy /= 1.04; 
} 

基本上,它是为Hooke's Law通过它们之间的弹簧联粒子链。对于每个粒子u,它将前一个和下一个粒子的吸引力(if语句检查它们是否可用)添加到变量fForceY。我不完全了解springs阵列的用途。在最后四行中,它计算加速度(力/质量),更新速度(加速度),然后定位(加速度),最后将速度降低1.04(摩擦)。

物理学更新后,代码呈现波:

context.clearRect(0, 0, stageWidth, stageHeight); 
context.fillStyle = color; 
context.beginPath(); 

for (u = 0; u < particles.length; u++) { 
    ... 
} 

... 
context.closePath(); 
context.fill(); 

我不解释,你需要阅读画布的教程,了解它。


这里有一些想法上手,请注意,我没有测试这些代码。

要修改绘制圆形波的代码,我们需要引入一个polar coordinate system,其中粒子的x -position是圆圈中的角度,而y-定位距离中心的距离。这里我们应该使用thetar,但它需要大量的重构。我们稍后会谈谈转型。

mouseMove():从鼠标的位置计算粒子指数在屏幕上极坐标,并确保干扰回绕:

定义函数(外mouseMove(),我们再次需要这个版本)

function wrapAround(i, a) { return (i + a.length) % a.length; } 

然后改变

particles[target - 2] --> particles[wrapAround(target - 2, particles)] 
particles[target - 1] --> particles[wrapAround(target - 1, particles)] 
... 

模运算符不这项工作,但我加了particles.length所以我不modulo一个负数。

render():确保强制计算环绕,因此我们需要再次使用wrapAround函数。我们可以剥去的两个if语句:

fExtensionY = particles[wrapAround(u - 1, particles)].y - particles[u].y - springs[wrapAround(u - 1, springs)].iLengthY; 
    fForceY += -fK * fExtensionY; 

    fExtensionY = particles[u].y - particles[wrapAround(u + 1, particles)].y - springs[warpAround(u, springs)].iLengthY; 
    fForceY += fK * fExtensionY; 

这里是到目前为止的结果中的jsfiddle:注意波从另一个侧面传播。 http://jsfiddle.net/DM68M/

完成之后,最难的部分就是将它们渲染成一个圆。为此,我们需要坐标变换函数,将粒子的(x, y)视为(angle in the circle, distance from center),并且我们还需要在mouseMove()中对鼠标交互进行逆变换。

function particleCoordsToScreenCoords(particleX, particleY) { 
    return [ radiusFactor * particleY * Math.cos(particleX/angleFactor), 
      radiusFactor * particleY * Math.sin(particleX/angleFactor) ]; 
} 

function screenCoordsToParticleCoords(screenX, screenY) { 
    // something involving Math.atan2 and Math.sqrt 
} 

其中...Factor变量需要单独确定。 angleFactor是在粒子阵列中发现的最高x位置上的两个pi

然后,在提供给context.lineTo, context.arc的坐标中,使用particleCoordsToScreenCoords来转换坐标。