JS实现三角形绕中心旋转时尺寸异常放大问题排查
问题现象
实现键盘按「J」键时玩家三角形绕自身中心旋转的交互,代码运行后三角形能转动,但尺寸会随按键次数持续异常增大。
原实现代码如下:
document.onkeydown = function (event) { switch (event.keyCode) { case 74: //player presses "j" px = player.calculateCentreX(); py = player.calculateCentreY(); x1 = rotateX(player.x1,player.y1,35,px,py); x2 = rotateX(player.x2,player.y2,35,px,py); x3 = rotateX(player.x3,player.y3,35,px,py); y1 = rotateY(player.x1,player.y1,35,px,py); y2 = rotateY(player.x2,player.y2,35,px,py); y3 = rotateY(player.x3,player.y3,35,px,py); player.setPoints(x1,y1,x2,y2,x3,y3); break; default: break; } }; function rotateX(cx,cy,angle,px,py) { x = Math.cos(angle)*(px-cx) - Math.sin(angle)*(py-cy) + cx return x } function rotateY(cx,cy,angle,px,py) { y = Math.sin(angle)*(px-cx) + Math.cos(angle)*(py-cy) + cy return y }
其中setPoints方法的作用是更新三角形三个顶点的坐标为新计算值。
问题原因
代码存在两个核心错误:
- 旋转公式逻辑完全错误
标准2D绕点旋转的计算逻辑是:先把待旋转顶点平移到以旋转中心为原点的坐标系,完成旋转后再平移回原坐标系。你的代码里旋转向量方向写反(用了中心坐标减顶点坐标,正确应为顶点坐标减中心坐标),且最后偏移值加的是原始顶点坐标而非旋转中心坐标,实现的根本不是保持尺寸不变的旋转变换,每次计算都会把顶点到中心的距离放大约1.95倍,按键次数越多三角形越大。 - 角度单位不匹配
JavaScript中Math.cos、Math.sin方法仅接受弧度单位的参数,你直接传入35(角度值),实际传入的是35弧度(约合2005度),就算公式修正,旋转角度也完全不符合预期。
另外代码中所有临时变量都没有加let/const声明,会污染全局作用域,虽然不会直接导致尺寸异常,但属于不规范写法,建议一并修正。
修复方案
- 重写旋转计算函数,严格遵循2D旋转公式
- 提前把旋转角度从角度值转为弧度值
- 给临时变量添加声明,避免全局污染
修复后的核心代码参考:
// 提前把35度转成弧度,避免每次按键重复计算 const ROTATE_STEP = 35 * Math.PI / 180; document.onkeydown = function (event) { switch (event.keyCode) { case 74: // 先拿到旋转中心坐标 const centerX = player.calculateCentreX(); const centerY = player.calculateCentreY(); // 逐个计算三个顶点旋转后的坐标 const [x1, y1] = rotatePoint(player.x1, player.y1, centerX, centerY, ROTATE_STEP); const [x2, y2] = rotatePoint(player.x2, player.y2, centerX, centerY, ROTATE_STEP); const [x3, y3] = rotatePoint(player.x3, player.y3, centerX, centerY, ROTATE_STEP); player.setPoints(x1, y1, x2, y2, x3, y3); break; default: break; } }; /** * 计算点绕指定中心旋转后的坐标 * @param {number} pointX 待旋转点x坐标 * @param {number} pointY 待旋转点y坐标 * @param {number} centerX 旋转中心x坐标 * @param {number} centerY 旋转中心y坐标 * @param {number} radian 旋转弧度 * @returns {[number, number]} 旋转后的点坐标 */ function rotatePoint(pointX, pointY, centerX, centerY, radian) { // 平移到以旋转中心为原点的坐标系 const dx = pointX - centerX; const dy = pointY - centerY; // 旋转计算 const rotatedX = dx * Math.cos(radian) - dy * Math.sin(radian); const rotatedY = dx * Math.sin(radian) + dy * Math.cos(radian); // 平移回原坐标系返回 return [rotatedX + centerX, rotatedY + centerY]; }
内容的提问来源于stack exchange,提问作者Bayley Sapara
相关产品推荐
相关产品推荐

