You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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方法的作用是更新三角形三个顶点的坐标为新计算值。

问题原因

代码存在两个核心错误:

  1. 旋转公式逻辑完全错误
    标准2D绕点旋转的计算逻辑是:先把待旋转顶点平移到以旋转中心为原点的坐标系,完成旋转后再平移回原坐标系。你的代码里旋转向量方向写反(用了中心坐标减顶点坐标,正确应为顶点坐标减中心坐标),且最后偏移值加的是原始顶点坐标而非旋转中心坐标,实现的根本不是保持尺寸不变的旋转变换,每次计算都会把顶点到中心的距离放大约1.95倍,按键次数越多三角形越大。
  2. 角度单位不匹配
    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 18:42:33