基于Canvas与物理引擎原理实现弹簧小球动画

作者:交互手记时间:2026-11-01 01:19:11浏览:659

本文详解如何利用HTML5 Canvas结合物理力学原理,实现弹簧小球的动态交互效果。通过受力分析分解重力、弹力及空气阻力,利用向量合成与投影算法计算合力与加速度,最终在每一帧渲染中更新小球坐标,展示完整的物理模拟过程与代码实现。

先展示最终实现的视觉效果。

场景中包含两个小球及连接它们的弹簧线条。左侧小球位置固定,点击启动后,右侧小球在重力作用下进行自由落体运动,并受弹簧力影响产生摆动。

先展示最终实现的视觉效果。

接下来梳理实现该效果的技术思路。

首先需要对系统进行受力分析。

先展示最终实现的视觉效果。

通过受力分析可知,系统中主要存在三个作用力。我们需要分别计算这三个力的大小与方向,将其合成为一个总力,进而求出该总力产生的加速度。

首先是重力分析。

右侧小球在整个运动过程中始终受到竖直向下的重力作用,其计算公式为:

G = m * g

其次是弹力分析。

右侧小球始终受到指向左侧小球球心的弹力,该力的计算公式遵循胡克定律:

胡克定律

F = -△x * k

最后是空气阻力分析。

空气阻力可简化为与速度方向相反,并乘以一个小于1的阻力系数。

// dragCoefficient值越大说明阻力越大
F = -v * dragCoefficient

首先定义重力的单位向量,由于重力方向始终垂直向下,其单位向量为(0, 1)。设定重力大小后,根据公式质量乘以重力加速度即可得出。此处设定质量为10,重力加速度为9.8,具体代码实现如下:

// 获取重力单位向量
function getGravityNorVector() {
  return {
    x: 0,
    y: 1,
  };
}

// 获取重力大小
function getGravitySize() {
  return m * g;
}

接着定义弹力的单位向量,其方向始终由右球球心指向左球球心。弹力大小依据胡克定律计算,即形变距离乘以弹簧弹性系数。

// 获取弹力单位向量
function getElasticityNorVector() {
  // 左球球心坐标减右球球心坐标,然后做向量归一化
  return normalized(createVector(originPosition, targetPosition));
}

// 获取弹力大小
function getElasticitySize() {
  // 计算Δx
  const offsetX =
    length(createVector(originPosition, targetPosition)) - originElasticitySize;

  // 胡克定律,只要大小,所以取绝对值
  return Math.abs(-offsetX * K);
}

随后计算空气阻力,其方向与当前速度方向相反。此处设定阻力系数为0.1。由于初始状态速度为0,阻力也为0,只有当小球运动产生速度后,阻力才会生效。

// 空气阻力,dragCoefficient为阻力系数,输出是一个向量
const other = {
  x: -vx * dragCoefficient,
  y: -vy * dragCoefficient,
};

现在已求出所有力的大小与方向,根据向量平行四边形法则,首先将弹力与重力进行合成。

// 单位向量 * 向量长度可以得到矢量力,输出是一个向量
const elasticityAndGravity = add(
  mul(getElasticitySize(), getElasticityNorVector()),
  mul(getGravitySize(), getGravityNorVector())
);

接着将上述合力与空气阻力合成,得到最终的总作用力。

// 所有力的合成,输出是一个向量
const total = add(elasticityAndGravity, other);

随后将合成后的总力分解为水平与垂直两个分力。利用向量投影算法,先通过向量点积求出总力与水平单位向量(1,0)及垂直单位向量(0,1)的夹角余弦值。将总力大小乘以对应的余弦值,得到投影到水平和垂直方向的分力大小,再分别乘以对应的单位向量,即可得到水平和垂直方向的分力向量。

// 获取力在x轴和y轴分量向量
function getXYAxisVector(fNorVector, fSize) {
  const yAxisNorVector = createVector(
    {
      x: targetPosition.x,
      y: targetPosition.y - 1,
    },
    targetPosition
  );
  const xAxisNorVector = createVector(
    {
      x: targetPosition.x - 1,
      y: targetPosition.y,
    },
    targetPosition
  );

  // 分别点击求向量在水平单位向量和垂直单位向量的余弦值
  const cosYAxis = dot(yAxisNorVector, fNorVector);
  const cosXAxis = dot(xAxisNorVector, fNorVector);

  return {
    yVector: mul(fSize * cosYAxis, yAxisNorVector),
    xVector: mul(fSize * cosXAxis, xAxisNorVector),
  };
}

// 获取水平和垂直分力向量
const result = getXYAxisVector(normalized(total), length(total));

根据牛顿第二定律公式:

F = m * a;

将得到的两个分力分别除以质量 m。此处 m 设定为10,从而计算出x轴和y轴方向的加速度。

// 获取水平和垂直方向加速度
const xAcceleration = result.xVector.x / m;
const yAcceleration = result.yVector.y / m;

在每一帧渲染时,将加速度累加到速度上,并将速度累加到右球的坐标中,即可渲染出动态效果。代码中除以100是为了降低速度数值,防止运动过快。

vx += xAcceleration;
vy += yAcceleration;
targetPosition.x += vx / 100;
targetPosition.y += vy / 100;

最终呈现出上述弹簧小球的交互效果。

先展示最终实现的视觉效果。

至此,关于使用Canvas实现弹簧效果的教程介绍完毕。如需了解更多Canvas相关技术内容,请搜索本站往期文章或继续浏览后续相关文章,感谢支持。

作者最新文章