在html5画布上旋转单个图像(但不是其他图像)?

时间:2010-07-10 19:50:12

标签: image html5 canvas rotation

我有一个精灵,我正在使用普通的精灵表格blitting在html画布上制作动画。在某些关键事件中,我想改变精灵的方向(即,翻转或旋转180度)而不改变画布上的任何东西(其他精灵)。

有谁知道怎么做?

4 个答案:

答案 0 :(得分:2)

所以我的游戏出现了这个问题;我有上升,下降和左动画的细胞,但没有正确的细胞。所以我需要翻转左边的细胞来绘制正确的细胞。

对于每个精灵,我会跟踪它在画布中的当前顶部和左侧,以及精灵表中每个单元格的顶部和左侧。

我见过以前的答案显示一个简单的水平翻转,只是翻译原点和翻转(反比例)轴,但是这没有考虑到精灵,翻转原点会弄乱精灵的注册点(它在画布的顶部和左侧)。

这个问题表现在正确镜像的精灵中,但它的位置偏离了精灵的宽度。我通过考虑精灵的宽度来解决它。注意我是如何使用带有9个参数的CanvasRenderingContext2D.prototype.drawImage,因为我正在从精灵表中切出一个sprite:

// check if we need to flip image (special case for right movement)
if(sprite.translated){
  context.save();
  context.translate(context.canvas.width, 0);
  context.scale(-1, 1);
  context.drawImage(sprite.sheet,
    cell.left,
    cell.top,
    sprite.width,
    sprite.height,
    // secret sauce: change the destination's X registration point
    context.canvas.width - sprite.left - sprite.width,
    sprite.top,
    sprite.width, sprite.height);
  context.restore();
} else {
  // Assumes cells are all the same width and height, set in sprite
  context.drawImage(sprite.sheet, cell.left, cell.top, sprite.width,
  sprite.height, sprite.left, sprite.top, sprite.width, sprite.height);
}

注意:我也可以在翻译中完成数学运算,因为它的目的是简化其他地方的计算。

答案 1 :(得分:1)

使用rotate转换简单地重绘精灵。 Transformations in HTML Canvas 2D Context

画布只是一个屏幕外缓冲区。除非你告诉它,否则它不会被清除,除非你告诉它,否则不会改变任何其他内容。

有许多不同的情况,你可能需要重绘精灵区域或周围区域。否则,您将获得重影效果,其中部分旧精灵在新图形下方仍然可见,或者其他图形变得模糊。一些原因是:

  • 您的精灵部分透明,
  • 你的精灵部分半透明,
  • 其他图纸是在您的精灵上面制作的,
  • 你的精灵是非矩形的,
  • 你正在翻转不是90度的倍数。

因此可能需要更多工作,并且有几种不同的方法可以做到这一点。您可以使用clip方法简单地重绘整个场景,或仅重绘该位置的特定对象。

完全不同的方向可能是使用其他HTML元素imgdiv,使用绝对定位和CSS3转换。将场景渲染委托给浏览器基本上是一种诡计。

答案 2 :(得分:1)

虽然我很欣赏Shtééf的答案,经过一些研究后,我发现旋转你实际用来显示的画布似乎并不理想。在尝试创建复杂的动画时进行保存,旋转和恢复(也就是认为街头霸王2不是星形)会导致画布在Chrome中闪烁。

然而,我发现了一个有用的策略。这里的想法是你实际上创建了两个画布,一个将用于你的游戏,另一个将是各种各样的后备缓冲器,它将用于旋转或缩放你的精灵。您实质上转换后备缓冲区画布,绘制有问题的图像,然后将其传输到主画布并恢复(或不恢复)后备缓冲区。通过这种方式,您只能旋转隐藏的画布,并且只影响所讨论的精灵而不是整个游戏板。

代码看起来像这样(正在进行中):

mainContext.clearRect(lastXpos, lastYpos, lastWidth, lastHeight);
backContext.clearRect(0, 0, lastWidth, lastHeight);
lastXpos = xpos;
lastYpos = ypos;
lastWidth = width;
lastHeight = height;


backContext.save();

//check the direction of the sprite
//turn the backContext to this direction   
//SPRITE_INVERTED==-1
if (spriteXDirection == SPRITE_INVERTED || spriteYDirection == SPRITE_INVERTED) 
{
    var horScale = 0;
    var verScale = 0;

    if (spriteXDirection == SPRITE_INVERTED)
    {
    horScale = width;
    }

    if (spriteYDirection == SPRITE_INVERTED)
    {
    verScale = height;
    }


    backContext.translate(horScale, verScale);
    backContext.scale(spriteXDirection, spriteYDirection);


}


//draw the sprite not we always use 0,0 for top/left
backContext.drawImage(animations[currentPlay].sheet,
                animationX,
                animationY,
                width,
                height, 0, 0, width, height);

//Get the image data from the back context
var image = backContext.getImageData(0, 0, width, height);


//flip the back context back to center - or not, I haven't decided how to optimize this yet.
backContext.restore();


//transfer the image to your main context
mainContext.putImageData(image, xpos, ypos);

这让我在理解如何翻译我的精灵而不让我的游戏板上的所有东西都移动到位时给我带来了很多麻烦。它似乎比修改主要上下文更好。

答案 3 :(得分:0)

为什么不使用save()和restore

ctx.save(); // save current state
ctx.rotate(Math.PI); // rotate
ctx.drawImage(link,x,y,20,20); // draws a chain link or dagger
ctx.restore(); // restore original states (no rotation etc)

How to rotate one image in a canvas?