在不移动所有其他对象的情况下以 canvas 旋转?

Rotating in canvas without moving all other objects?

我正在尝试制作一个 2 人坦克游戏,其中有两辆坦克互相射击,使用键盘控制它们。我已经为两者提供了向前和向后的运动,但是当我尝试旋转它们时,它也会旋转另一个。 (目前坦克只是矩形。)

如何旋转一个而不移动另一个?

var draw;
var context;
var DKey = false;
var AKey = false;
var WKey = false;
var SKey = false;
var tank1_x;
var tank1_y;
var tank1_w = 30;
var tank1_h = 30;
var UpKey = false;
var DownKey = false;
var RightKey = false;
var LeftKey = false;
var tank2_x;
var tank2_y;
var tank2_w = 30;
var tank2_h = 30;
var rad = Math.PI/180;

function init() {
    //canvas = document.getElementById('canvas');
    context = $('#myCanvas')[0].getContext('2d'); //sets the canvas as a jquery object to the variable 'context'
    WIDTH = $('#myCanvas').width();
    HEIGHT = $('#myCanvas').height();
    tank1_x = WIDTH * 1 / 4 - tank1_w / 2; //centre width TANK1
    tank1_y = HEIGHT * 1 / 4 - tank1_h / 2; //centre height TANK1
    tank2_x = WIDTH * 3 / 4 - tank2_w / 2; //centre width TANK2
    tank2_y = HEIGHT * 3 /4 - tank2_h / 2; //centre height TANK2
    setInterval('draw()', 25); //sets interval for draw method to repeat after
}
function clearCanvas() {
    context.clearRect(0,0,WIDTH,HEIGHT); // clears whole canvas
}

tank1 = function fillRect(x,y,w,h) {
    context.beginPath();
    context.fillRect(WIDTH*1/4, HEIGHT*1/4, tank1_w, tank1_h);
    context.endPath();
}

tank2 = function fillRect(x,y,w,h) {
    context.beginPath();
    context.fillRect(WIDTH*3/4, HEIGHT*3/4, tank2_w, tank2_h);
    context.endPath();
}

draw = function() { // redraws rectangle to canvas
    clearCanvas();
    //TANK1 ROTATION
    if (DKey) {
        var buffer = document.createElement('canvas');
        buffer.width = buffer.height = tank1_w*2;
        var bctx = buffer.getContext('2d');
        bctx.translate(tank1_x + tank1_w/2, tank1_y + tank1_h/2);
        bctx.rotate(5*rad);
        bctx.fillRect(tank1_x, tank1_y, tank1_w, tank1_h);
        ctx.drawImage(buffer, tank1_x, tank1_y);
    }
    else if (AKey) {
        context.save();
        context.clearRect(WIDTH, HEIGHT);
        context.translate(tank1_x + tank1_w/2, tank1_y + tank1_h/2); //http://www.williammalone.com/briefs/how-to-rotate-html5-canvas-around-center/ and Whosebug
        context.rotate(5*rad); //Translates origin of rotation to centre of block, then rotates 5 degrees
        context.fillRect(tank1_x, tank1_y, tank1_w, tank1_h); //Redraw TANK1
        context.rotate(-5*rad);
        context.translate(-tank1_x - tank1_w/2, -tank1_y - tank1_h/2); //Translates origin of rotation back to top left of canvas
        context.restore();
    }
    //TANK1 MOVEMENT
    if (WKey) tank1_y -= 5;
    else if (SKey) tank1_y += 5;
    if (tank1_x <= 0) tank1_x = 0;
    if ((tank1_x + tank1_w) >= WIDTH) tank1_x = WIDTH - tank1_w;
    if (tank1_y <= 0) tank1_y = 0;
    if ((tank1_y + tank1_h) >= HEIGHT) tank1_y = HEIGHT - tank1_h;
    context.fillRect(tank1_x,tank1_y,tank1_w,tank1_h);

    //TANK2 ROTATION
    if(RightKey) {
        context.translate(tank2_x + tank2_w/2, tank2_y + tank2_h/2);
        context.rotate(5*Math.PI/180);
        context.translate(-tank2_x - tank2_w/2, -tank2_y - tank2_h/2);
    }
    else if (LeftKey) {
        context.translate(tank2_x + tank2_w/2, tank2_y + tank2_h/2);
        context.rotate(-5*Math.PI/180);
        context.translate(-tank2_x - tank2_w/2, -tank2_y - tank2_h/2);
    }
    //TANK2 MOVEMENT
    if (UpKey) tank2_y -= 5;
    else if (DownKey) tank2_y += 5;
    if (tank2_x <= 0) tank2_x = 0;
    if ((tank2_x + tank2_w) >= WIDTH) tank2_x = WIDTH - tank2_w;
    if (tank2_y <= 0) tank2_y = 0;
    if ((tank2_y + tank2_h) >= HEIGHT) tank2_y = HEIGHT - tank2_h;
    context.fillRect(tank2_x,tank2_y,tank2_w,tank2_h);
}

function onKeyDown(event) {
    //TANK1 (WASD Keys)
    if (event.keyCode == 68) DKey = true;
    else if (event.keyCode == 65) AKey = true;
    if (event.keyCode == 87) WKey = true;
    else if (event.keyCode == 83) SKey = true;
    //TANK2 (Arrow Keys)
    if (event.keyCode == 39) RightKey = true;
    else if (event.keyCode == 37) LeftKey = true;
    if (event.keyCode == 38) UpKey = true;
    else if (event.keyCode == 40) DownKey = true;
}

function onKeyUp(event) {
    //TANK1
    if (event.keyCode == 68) DKey = false;
    else if (event.keyCode == 65) AKey = false;
    if (event.keyCode == 87) WKey = false;
    else if (event.keyCode == 83) SKey = false;
    //TANK2
    if (event.keyCode == 39) RightKey = false;
    else if (event.keyCode == 37) LeftKey = false;
    if (event.keyCode == 38) UpKey = false;
    else if (event.keyCode == 40) DownKey = false;
}

$(document).keydown(onKeyDown);
$(document).keyup(onKeyUp);

init();
});

我试过使用缓冲区,但这对我不起作用,清除然后旋转 canvas、重绘第一个坦克然后将 canvas 旋转回来(所以坦克旋转),然后按原样重新绘制其余部分。我不知道还能做什么。

目前我已经得到了我在 Tank1 的旋转缓冲区和 Tank2 的 canvas 旋转中尝试过的东西。

提前感谢您的帮助。

存储坦克的绝对旋转并使用它而不是累积变换矩阵(只是add/subtract旋转角度到这个值,f.ex一个 tank1_rotation)。如果你保持相对,你必须相对地转换场景中的所有东西,这使得跟踪事物变得复杂。

旋转并绘制坦克后,approach/change 将允许您简单地调用以下命令来检查所有内容:

context.setTransform(1,0,0,1,0,0);

这会将转换矩阵重置为初始状态,并且比使用 save/restore 快很多倍。

下次绘制坦克时,只需使用存储的角度,绘制并重复上述步骤。

在尝试了这些之后,我发现最直接的做法(我是一名数学专业的学生)是手动绘制坦克的所有点并使用矩阵相应地旋转每个点。

drawTank1 = function(x, y, w, h) {
    cos1 = Math.cos(tank1_angle);
    sin1 = Math.sin(tank1_angle);
    var centre_x = tank1_x;
    var centre_y = tank1_y;
    var corner1_x = - 20 * cos1 - 20 * sin1 + centre_x;
    var corner1_y = 20 * sin1 - 20 * cos1 + centre_y;
    var corner2_x = - 20 * cos1 + 20 * sin1 + centre_x;
    var corner2_y = 20 * sin1 + 20 * cos1 + centre_y;
    var corner3_x = 20 * cos1 + 20 * sin1 + centre_x;
    var corner3_y = - 20 * sin1 + 20 * cos1 + centre_y;
    var corner4_x = 20 * cos1 - 20 * sin1 + centre_x;
    var corner4_y = - 20 * sin1 - 20 * cos1 + centre_y;
    var corner5_x = 5 * cos1 - 20 * sin1 + centre_x;
    var corner5_y = - 5 * sin1 - 20 * cos1 + centre_y;
    var corner6_x = 5 * cos1 - 30 * sin1 + centre_x;
    var corner6_y = - 5 * sin1 - 30 * cos1 + centre_y;
    var corner7_x = - 5 * cos1 - 30 * sin1 + centre_x;
    var corner7_y = 5 * sin1 - 30 * cos1 + centre_y;
    var corner8_x = - 5 * cos1 - 20 * sin1 + centre_x;
    var corner8_y = 5 * sin1 - 20 * cos1 + centre_y;
    context.beginPath();
    context.fillStyle = '#00FF00';
    context.moveTo(corner1_x, corner1_y);
    context.lineTo(corner2_x, corner2_y);
    context.lineTo(corner3_x, corner3_y);
    context.lineTo(corner4_x, corner4_y);
    context.lineTo(corner5_x, corner5_y);
    context.lineTo(corner6_x, corner6_y);
    context.lineTo(corner7_x, corner7_y);
    context.lineTo(corner8_x, corner8_y);
    context.lineTo(corner1_x, corner1_y);
    context.closePath();
    context.fill();
    context.stroke();
}

感谢大家的帮助和建议