简体   繁体   中英

Rotating a sprite from a sprite sheet onto a html5 canvas, using arrows keys. (2d html5 canvas)

Let me try to explain what I have now, and what I am trying to add to it. Right now I have a canvas, 500x899 following a sprite(player), onto a background image(map) that's 5000x3750. Both are on the same sprite sheet. Right now if the arrow keys are pressed, the Player sprite moves in that direction along the Map while the canvas follows the player. - But what I would like is to have the left/right arrow keys rotate the player and the up key to move the player in that direction. Here's my code, it is a lot, but its organized:

// wrapper for "class" Rectangle
    (function(){
        function Rectangle(left, top, width, height){
            this.left = left || 0;
            this.top = top || 0;
            this.right = (left + width) || 0;
            this.bottom = (top + height) || 0;
        }

        Rectangle.prototype.set = function(left, top, width, height){
            this.left = left;
            this.top = top;
            this.width = width || this.width;
            this.height = height || this.height;
            this.right = (this.left + this.width);
            this.bottom = (this.top + this.height);
        }

        Rectangle.prototype.within = function(r) {
            return (r.left <= this.left && 
                    r.right >= this.right &&
                    r.top <= this.top && 
                    r.bottom >= this.bottom);
        }       

        Rectangle.prototype.overlaps = function(r) {
            return (this.left < r.right && 
                    r.left < this.right && 
                    this.top < r.bottom &&
                    r.top < this.bottom);
        }

        // add "class" Rectangle to our Game object
        Game.Rectangle = Rectangle;
    })();   

    // wrapper for "class" Camera (avoid global objects)
    (function(){

        // possibles axis to move the camera
        var AXIS = {
            NONE: "none", 
            HORIZONTAL: "horizontal", 
            VERTICAL: "vertical", 
            BOTH: "both"
        };

        // Camera constructor
        function Camera(xView, yView, canvasWidth, canvasHeight, worldWidth, worldHeight)
        {
            // position of camera (left-top coordinate)
            this.xView = xView || 0;
            this.yView = yView || 0;

            // distance from followed object to border before camera starts move
            this.xDeadZone = 0; // min distance to horizontal borders
            this.yDeadZone = 0; // min distance to vertical borders

            // viewport dimensions
            this.wView = 800;
            this.hView = 599;           

            // allow camera to move in vertical and horizontal axis
            this.axis = AXIS.BOTH;  

            // object that should be followed
            this.followed = null;

            // rectangle that represents the viewport
            this.viewportRect = new Game.Rectangle(this.xView, this.yView, this.wView, this.hView);             

            // rectangle that represents the world's boundary (room's boundary)
            this.worldRect = new Game.Rectangle(this.xView, this.yView, this.wView, this.hView);

        }

        // gameObject needs to have "x" and "y" properties (as world(or room) position)
        Camera.prototype.follow = function(gameObject, xDeadZone, yDeadZone)
        {       
            this.followed = gameObject; 
            this.xDeadZone = xDeadZone;
            this.yDeadZone = yDeadZone;
        }                   

        Camera.prototype.update = function()
        {
            // keep following the player (or other desired object)
            if(this.followed != null)
            {       
                if(this.axis == AXIS.HORIZONTAL || this.axis == AXIS.BOTH)
                {       
                    // moves camera on horizontal axis based on followed object position
                    if(this.followed.x - this.xView  + this.xDeadZone > this.wView)
                        this.xView = this.followed.x - (this.wView - this.xDeadZone);
                    else if(this.followed.x  - this.xDeadZone < this.xView)
                        this.xView = this.followed.x  - this.xDeadZone;

                }
                if(this.axis == AXIS.VERTICAL || this.axis == AXIS.BOTH)
                {
                    // moves camera on vertical axis based on followed object position
                    if(this.followed.y - this.yView + this.yDeadZone > this.hView)
                        this.yView = this.followed.y - (this.hView - this.yDeadZone);
                    else if(this.followed.y - this.yDeadZone < this.yView)
                        this.yView = this.followed.y - this.yDeadZone;
                }                       

            }       

            // update viewportRect
            this.viewportRect.set(this.xView, this.yView);

            // don't let camera leaves the world's boundary
            if(!this.viewportRect.within(this.worldRect))
            {
                if(this.viewportRect.left < this.worldRect.left)
                    this.xView = this.worldRect.left;
                if(this.viewportRect.top < this.worldRect.top)                  
                    this.yView = this.worldRect.top;
                if(this.viewportRect.right > this.worldRect.right)
                    this.xView = this.worldRect.right - this.wView;
                if(this.viewportRect.bottom > this.worldRect.bottom)                    
                    this.yView = this.worldRect.bottom - this.hView;
            }

        }   

        // add "class" Camera to our Game object
        Game.Camera = Camera;

    })();

    // wrapper for "class" Player
    (function(){
        function Player(x, y){
            // (x, y) = center of object
            // ATTENTION:
            // it represents the player position on the world(room), not the canvas position
            this.x = x;
            this.y = y; 
            // move speed in pixels per second
            this.speed = 200;       

            // render properties
            this.width = 85;
            this.height = 80;
        }

        Player.prototype.update = function(step, worldWidth, worldHeight){
            // parameter step is the time between frames ( in seconds )

            // check controls and move the player accordingly
            if(Game.controls.left)
                this.x -= this.speed * step;
            if(Game.controls.up)
                this.y -= this.speed * step;
            if(Game.controls.right)
                this.x += this.speed * step;
            if(Game.controls.down)
                this.y += this.speed * step;        

            // don't let player leaves the world's boundary
            if(this.x - this.width/2 < 0){
                this.x = this.width/2;
            }
            if(this.y - this.height/2 < 0){
                this.y = this.height/2;
            }
            if(this.x + this.width/2 > worldWidth){
                this.x = worldWidth - this.width/2;
            }
            if(this.y + this.height/2 > worldHeight){
                this.y = worldHeight - this.height/2;
            }
        }

        Player.prototype.draw = function(context, xView, yView){
            context.save();
            // before draw we need to convert player world's position to canvas position
            context.drawImage(imgSprite,1700,599, this.width, this.height,(this.x-this.width/2) - xView, (this.y-this.height/2) - yView, this.width, this.height);
            context.restore();
            }   
        // add "class" Player to our Game object
        Game.Player = Player;
    })();


    // wrapper for "class" Map
    (function(){
        function Map(width, height){
            // map dimensions
            this.width = width;
            this.height = height;

            // map texture
            this.image = null;
        }

        // generate an example of a large map
        Map.prototype.generate = function(){
            this.x = 0;
            this.y = 0; 
            var ctx = document.createElement("canvas").getContext("2d");        
            ctx.canvas.width = this.width;
            ctx.canvas.height = this.height;    
            ctx.drawImage(imgSprite,0,2250,this.width,this.height,this.x,this.y,this.width,this.height);    


            ctx.restore();  

            // store the generate map as this image texture
            this.image = new Image();
            this.image.src = ctx.canvas.toDataURL("image/png");                 

            // clear context
            ctx = null;
        }

        // draw the map adjusted to camera
        Map.prototype.draw = function(context, xView, yView){                   
            var sx, sy, dx, dy;
            var sWidth, sHeight, dWidth, dHeight;

            // offset point to crop the image
            sx = xView;
            sy = yView;

            // dimensions of cropped image          
            sWidth =  context.canvas.width;
            sHeight = context.canvas.height;

            // if cropped image is smaller than canvas we need to change the source dimensions
            if(this.image.width - sx < sWidth){
                sWidth = this.image.width - sx;
            }
            if(this.image.height - sy < sHeight){
                sHeight = this.image.height - sy; 
            }

            // location on canvas to draw the croped image
            dx = 0;
            dy = 0;
            // match destination with source to not scale the image
            dWidth = sWidth;
            dHeight = sHeight;                                  

            context.drawImage(this.image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);            
        }

        // add "class" Map to our Game object
        Game.Map = Map;

    })();


    // Game Script
    (function(){
        // prepaire our game canvas
        var canvas = document.getElementById("gameCanvas");
        var context = canvas.getContext("2d");

        // game settings:   
        var FPS = 30;
        var INTERVAL = 1000/FPS; // milliseconds
        var STEP = INTERVAL/1000 // seconds

        // setup an object that represents the room
        var room = {
            width: 5000,
            height: 3750,
            map: new Game.Map(5000, 3750)
        };

        // generate a large image texture for the room
        room.map.generate();

        // setup player
        var player = new Game.Player(85, 80);

        // setup the magic camera !!!
        var camera = new Game.Camera(0, 0, 800, 599, room.width, room.height);      
        camera.follow(player, 800/2, 599/2);

        // Game update function
        var update = function(){            
            player.update(STEP, room.width, room.height);
            camera.update();
        }

        // Game draw function
        var draw = function(){
            // clear the entire canvas
            context.clearRect(0, 0, 800, 599);

            // redraw all objects
            room.map.draw(context, camera.xView, camera.yView);     
            player.draw(context, camera.xView, camera.yView);       
        }

        // Game Loop
        var gameLoop = function(){                      
            update();
            draw();
        }   

        // <-- configure play/pause capabilities:

        // I'll use setInterval instead of requestAnimationFrame for compatibility reason,
        // but it's easy to change that.

        var runningId = -1;

    Game.play = function(){ 
        if(runningId == -1){
            runningId = setInterval(function(){
                gameLoop();
            }, INTERVAL);
            console.log("play");
        }
    }

    Game.togglePause = function(){      
        if(runningId == -1){
            Game.play();
        }
        else
        {
            clearInterval(runningId);
            runningId = -1;
            console.log("paused");
        }
    }   
})();
// <-- configure Game controls:
Game.controls = {
    left: false,
    up: false,
    right: false,
    down: false,
};
window.addEventListener("keydown", function(e){
    switch(e.keyCode)
    {
        case 37: // left arrow
            Game.controls.left = true;
            break;
        case 38: // up arrow
            Game.controls.up = true;
            break;
        case 39: // right arrow
            Game.controls.right = true;
            break;
        case 40: // down arrow
            Game.controls.down = true;
            break;
    }
}, false);
window.addEventListener("keyup", function(e){
    switch(e.keyCode)
    {
        case 37: // left arrow
            Game.controls.left = false;
            break;
        case 38: // up arrow
            Game.controls.up = false;
            break;
        case 39: // right arrow
            Game.controls.right = false;
            break;
        case 40: // down arrow
                Game.controls.down = false;
            break;
        case 80: // key P pauses the game
            Game.togglePause();
            break;      
        }
    }, false);
    // start the game when page is loaded
    window.onload = function(){ 
        Game.play();
    }

Again this works for the canvas to follow the player and all, but now I'm trying to rotate the player sprite using the arrow keys. I'v used google and tried some codes similar too :

var thrust = 0;
var rotation = 0;
ctxPlayer.translate(this.width/2, this.height/2);
ctxPlayer.rotate(this.angle);
ctxPlayer.translate(this.x,this.y);
if(Game.controls.left)
this.angle =-3

(Sorry i dont have exactly what I have tried regarding the rotation, as I've deleted them every time it didn't work). Using codes similiar to this the only rotation I have gotten is the player rotating in a giant circle around a coordinate. (Not actually rotating in one spot and not with the push of a key)

Any help or advice is really appreciated.

Change the order of operations. Rotate the sprite first, then move it. You will want the center of your sprite to be at 0,0 (top left) in order to get the effect your looking for. The following code assumes your already starting at 0,0:

ctxPlayer.save();
ctxPlayer.translate(this.x,this.y);
ctxPlayer.rotate(this.angle);
ctxPlayer.translate(-this.width/2,-this.height/2); // before we draw the sprite lets set the anchor point to its center.
ctxPlater.restore();

http://jsfiddle.net/LRpBM/

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