如何让部分图形不受ctx.rotate()的旋转影响?
解决Canvas仅旋转特定图形的问题
Canvas的上下文变换是累积生效的,你之前的rotate会修改整个坐标系,导致后续循环里的所有绘制都受影响。要实现仅旋转指定图形,核心是用ctx.save()和ctx.restore()隔离上下文状态,步骤如下:
- 调用
ctx.save()保存当前上下文状态(此时坐标系未被旋转) - 平移到目标旋转中心(比如玩家的中心位置
width/2, height/2) - 执行
ctx.rotate(angle)完成旋转 - 平移回原位置的反向,保证绘制时可以沿用之前的坐标逻辑
- 绘制所有需要旋转的图形
- 调用
ctx.restore()恢复到初始状态,后续绘制不受旋转影响
另外要注意:默认rotate是绕坐标系原点(0,0)旋转,直接使用会导致图形位置偏移,所以必须通过平移调整旋转中心。
修改后的代码示例:
var mainInterval = setInterval(() => { ctx.clearRect(-width,-height,width,height); ctx.fillStyle = "green"; ctx.fillRect(0,0,width,height); // 绘制不需要旋转的3张图,上下文保持初始状态 ctx.drawImage(pistolInv,width / 4,height - 60 * graphics,width / 8,60 * graphics); ctx.drawImage(submachinegunInv,width / 2,height - 60 * graphics,width / 8,60 * graphics); ctx.drawImage(ak47Inv,width / 4 * 3,height - 60 * graphics,width / 8,60 * graphics); // 处理需要旋转的图形 ctx.save(); // 保存未旋转的上下文状态 // 平移到旋转中心 ctx.translate(width / 2, height / 2); // 执行旋转 ctx.rotate(angle); // 平移回原位置的反向,保证绘制坐标逻辑不变 ctx.translate(-width / 2, -height / 2); // 绘制需要旋转的4张图 if(equippedGun != -1){ // 注意:每次定时器创建新Image会重复加载资源,建议提前加载所有枪图并缓存 var gun = new Image(); gun.src = "assets/guns/" + guns[equippedGun] + ".png"; ctx.drawImage(gun,width / 2,height / 2,120 * graphics,20 * graphics); } ctx.drawImage(player,width / 2 - (30 * graphics),height / 2 - (30 * graphics),60 * graphics,60 * graphics); ctx.drawImage(hand,width / 2 + (15 * graphics),height / 2 - (33 * graphics)); ctx.drawImage(hand,width / 2 - (40 * graphics),height / 2 - (33 * graphics)); ctx.restore(); // 恢复上下文状态,不影响下一次循环绘制 },10);
额外提醒:你代码里每次定时器都new Image()加载枪图的做法会重复请求资源,严重影响性能。建议在定时器初始化前,提前把所有需要的枪图片加载完成并缓存,定时器里直接使用已加载的Image实例即可。
内容的提问来源于stack exchange,提问作者AlirezaBest
相关产品推荐
相关产品推荐

