简体   繁体   中英

Issue Rotating Canvas Shape WIth Arrow Keys

I would like the left and right arrow keys to rotate my canvas shape clockwise and anticlockwise, respectively. Currently the shape moves only linearly.

In the long run, I am trying to replicate the movement of my ROS (Robot Operating System) TurtleSim using this javascript code, and the left & right keys rotate the turtlesim in this way. (I am fairly new to javascript.)

<script>
function Parent(){
    //diffColor = false;
    mainCanvas.load();
    tracker = new track(30, 50, "white", 30, 120); //create object that will move with keys;

    click();
    //touch();
    //animate();
    //mapCanvas.load();
}

function click(){
        window.addEventListener("click", getClickPosition, false);

    function getClickPosition(e){
        tracker.distanceX = e.clientX - (tracker.width / 2); //move tracker to near center of tracker; clientX gets horizontal coordinate of cursor
        tracker.distanceY = e.clientY - (tracker.height / 2);

        }
}


var mainCanvas = {
    canvas : document.createElement("canvas"),
    load: function(){

        this.canvas.width = (window.innerWidth)/2;
        this.canvas.height = window.innerHeight;
        this.ctx1 = this.canvas.getContext("2d");

        document.body.insertBefore(this.canvas, document.body.childNodes[0]);
        this.interval = setInterval(moveTracker, 20);

        window.addEventListener ("keydown", function(e){
            console.log(e.keyCode);
            mainCanvas.key = e.keyCode; //execute movement when key pressed
        });
        window.addEventListener ("keyup", function(e){
                mainCanvas.key = false; //stop movement once key is released
                });

    },

    clear: function(){
        this.ctx1.clearRect(0, 0, this.canvas.width, this.canvas.height);
    }
}

    function track(width, height, color, distanceX, distanceY, theSquare){ 
    this.width = width;
    this.height = height;
    this.speedX = 0;
    this.speedY = 0;
    this.distanceX = distanceX;
    this.distanceY = distanceY;
    this.rotationSpeedRight = 0;
    this.rotationSpeedLeft= 0;
    this.rotationLeft = rotationLeft;
    this.rotationRight = rotationRight;
    console.log("inside track()");

    this.update = function(theSquare){
        ctx = mainCanvas.ctx1;
        ctx.fillStyle = color;
        ctx.fillRect(this.distanceX, this.distanceY, this.width, this.height, this.rotationLeft, this.rotationRight);
        ctx.rotate(45*Math.PI/180);
        ctx.save();
        ctx.restore();
    }
    this.newPosition = function(){
    this.rotation += this.rotationSpeed;
    this.distanceX += this.speed * Math.cos(this.rotation);
    this.distanceY += this.speed * Math.sin(this.rotation);
    }
}

function moveTracker(){ //recognize keys from keyboard
    mainCanvas.clear();
    tracker.speedX = 0;
    tracker.speedY = 0;
    tracker.rotationSpeedRight = 0;
    tracker.rotationSpeedLeft = 0;
    if (mainCanvas.key && mainCanvas.key == 37) //left key; should move anticlockwise
        tracker.rotationSpeedLeft = -1;
    if (mainCanvas.key && mainCanvas.key == 38) //down key
        tracker.speedY = -1;
    if (mainCanvas.key && mainCanvas.key == 39) //right key; should move clockwise;
        tracker.rotationSpeedRight = 1;
    if (mainCanvas.key && mainCanvas.key == 40) //up key
        tracker.speedY=1;

    tracker.newPosition();
    tracker.update();
}

There is no such thing as a "left rotation" and a "right rotation", they both refer to the same thing. You only need one rotation value, it is the current angle of your drawing.

I also assume you want your up key to go in whichever direction you are facing rather than always up, so you can switch the speed values to only one value as well, the speed in the current direction. This basically changes your coordinate system from cartesian (x, y) to polar (angle and distance).
To know the final change on the XY plane of a move based on rotation and speed, you have to use speed * cos(angle) for X and speed * sin(angle) for Y (based on trigonometry).

rotate needs to be called before you draw your rectangle (it's basically saying "everything that I will do next will need to be rotated by that amount") and save and restore need to be called around all that, to cancel the rotation once you are done drawing your rotated shape.

Another note: rotate rotates the canvas around the origin (0, 0). To rotate around the center of your element, which is probably what you want to do, you will need to first translate to the position, then not forget to offset the position at which you draw the rectangle to take into account that initial translation.

A potential update of the bottom part of your code would be:

function track(width, height, color, distanceX, distanceY, rotation){
    this.width = width;
    this.height = height;
    this.distanceX = distanceX || 0;
    this.distanceY = distanceY || 0;
    this.speed = 0;
    this.rotation = rotation || 0;
    this.rotationSpeed = 0;

    this.update = function(){
        ctx = mainCanvas.ctx1;
        ctx.fillStyle = color;
        ctx.save();
        ctx.translate(this.distanceX, this.distanceY);
        ctx.rotate(this.rotation);
        ctx.fillRect(-this.width / 2, -this.height / 2, this.width, this.height);
        ctx.restore();
    }
    this.newPosition = function(){
        this.rotation += this.rotationSpeed;
        this.distanceX += this.speed * Math.cos(this.rotation);
        this.distanceY += this.speed * Math.sin(this.rotation);
    }
}

function moveTracker(){ //recognize keys from keyboard
    mainCanvas.clear();
    tracker.speed = 0;
    tracker.rotationSpeed = 0;
    // Adjust the values as you need here
    if (mainCanvas.key == 37) //left key
        tracker.rotationSpeed = -0.5 / Math.PI;
    if (mainCanvas.key == 38) //up key
        tracker.speed = 3;
    if (mainCanvas.key == 39) //right key
        tracker.rotationSpeed = 0.5 / Math.PI;
    if (mainCanvas.key == 40) //down key
        tracker.speed = -3;

    tracker.newPosition();
    tracker.update();
}

JSFiddle (rough version)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM