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

如何解决Canvas中汽车移动与旋转分离导致的双车显示问题

问题解决:单辆汽车同时实现移动与旋转功能

你遇到的双车问题,是因为在HTML中新增的<img id="CarRotate">会直接渲染在页面上,和Canvas里绘制的汽车形成重复。正确的做法是完全依靠Canvas的绘图API实现旋转,不需要额外的DOM图片元素。以下是具体修改方案:

修改步骤

  • 撤销在HTML中添加的<img id="CarRotate">元素,保持原HTML结构不变
  • 保留JS中原始的cCarImage Image对象(不要改成获取DOM元素),继续通过src加载汽车图片
  • 添加一个变量记录汽车的旋转角度,用于控制Canvas绘图时的旋转状态
  • 在键盘事件中添加'l'键的处理逻辑,每次触发时增加90度旋转角度
  • 修改render函数,利用Canvas的变换API(translate、rotate)实现围绕汽车中心的旋转

修改后的完整代码

index.html(无需改动,保持原结构)

<!DOCTYPE html>
<html>
    <head>
       <meta charset="UTF-8">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <link rel="stylesheet" href="image.css">
    </head>
    <body>
        <div id="canvasContainer">
            <canvas id="canvas" width="900" height="520"></canvas>
        </div>
        <script src="image.js"></script>
    </body>
</html>

image.js(修改后的代码)

const cCanvas = document.getElementById('canvas');
cCanvas.width = 600;
cCanvas.height = 300;
const cContext = cCanvas.getContext('2d');
const cBackgroundImage = new Image();
const cBackgroundWidth = cCanvas.width;
let lBackgroundHeight; 
const cCarImage = new Image();
const cCarImageWidth = 40; 
const cCarImageHeight = 100; 
let lCarImageX; 
let lCarImageY; 
// 新增:记录汽车旋转角度,初始为0
let carRotation = 0;

document.addEventListener('DOMContentLoaded', (ev) => 
    {
        cBackgroundImage.onload = function () {
            cCarImage.onload = function () 
            {
              const cAspectRatio = cBackgroundImage.naturalWidth / cBackgroundImage.naturalHeight;
              lBackgroundHeight = cCanvas.height = cBackgroundWidth / cAspectRatio; 
              lCarImageX = cBackgroundWidth / 2 - cCarImageWidth / 2; 
              lCarImageY = lBackgroundHeight - cCarImageHeight; 
              render(); // 直接调用render初始化
            }
            cCarImage.src = "Car.jpg"; 
        }
        cBackgroundImage.src = "Streets.jpg";
    }
)

document.body.addEventListener("keydown", e =>{
  e.preventDefault();
  switch(e.key){
    case 'ArrowUp':
      lCarImageY -= 10;
      break;
    case 'ArrowDown':
      lCarImageY += 10;
      break;
    case 'ArrowLeft':
      lCarImageX -= 10;
      break;
    case 'ArrowRight':
      lCarImageX += 10;
      break;
    // 新增:处理'l'键旋转,每次加90度,取模360保持角度在0-359之间
    case 'l':
      carRotation = (carRotation + 90) % 360;
      break;
  }
    render();
})

function render(){
  cContext.clearRect(0, 0, cCanvas.width, cCanvas.height);
  cContext.drawImage(cBackgroundImage, 0, 0, cBackgroundWidth, lBackgroundHeight); 

  // 保存当前画布状态,避免变换影响后续绘图
  cContext.save();
  
  // 1. 将画布原点平移到汽车的中心位置
  cContext.translate(
    lCarImageX + cCarImageWidth / 2, 
    lCarImageY + cCarImageHeight / 2
  );
  
  // 2. 将画布旋转指定角度(注意要转成弧度)
  cContext.rotate((carRotation * Math.PI) / 180);
  
  // 3. 绘制汽车,此时要以汽车的左上角相对于中心的位置绘制
  cContext.drawImage(
    cCarImage, 
    -cCarImageWidth / 2, 
    -cCarImageHeight / 2, 
    cCarImageWidth, 
    cCarImageHeight
  );
  
  // 恢复画布到之前的状态
  cContext.restore();
}

关键说明

  • 使用cContext.save()和cContext.restore()来隔离旋转变换,防止影响背景图的绘制
  • 旋转前先将画布原点平移到汽车中心,这样旋转是围绕汽车自身中心进行的,而不是画布原点
  • 角度转弧度:Canvas的rotate方法接受弧度值,所以需要将角度乘以Math.PI/180进行转换

内容的提问来源于stack exchange,提问作者ttom

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 01:04:57