【问题标题】:Issues with drawing images using multiple canvas's使用多个画布绘制图像的问题
【发布时间】:2013-08-20 15:24:23
【问题描述】:

绘图工作正常,直到我决定使用多个画布。我有一个舞台画布、一个实体画布和一个对象画布。不过,我可能最终会结合对象和实体画布。无论如何,正如你在下面看到的,我的英雄类画得很好。然后我尝试使用相同的绘制函数创建一个实体类,但是当我调用该函数时它不会让我绘制。我的背景画布几乎有同样的问题。我还没有背景课程,但我会的。但是我尝试简单地使用舞台的上下文绘制图像,它会破坏代码。

(我尝试设置 JSFiddle,但无法在其中获取图像。)

更新 markE 解决了我的一半问题。我目前唯一的问题是我的 entityCtx 是唯一可以绘制图像/矩形的上下文。其他 ctx 就是不能画任何东西。请帮忙!我更新了代码。

var stage = document.getElementById('stage');
var ctxStage = stage.getContext('2d');
var entitiesStage = document.getElementById('entities');
var ctxEntities = entitiesStage.getContext('2d');
var bg = document.getElementById('bg');
var ctxBg = bg.getContext('2d');
var playerImg = new Image();
playerImg.src = 'res/player_sprite_sheet.png';
var bgImg = new Image();
bgImg.onload = function() {
    ctxBg.drawImage(bgImg,0,0,80,50,-200,-90,1000,700);
};
bgImg.src = 'res/background.png';
var consoleImg = new Image();
consoleImg.onload = function() {
    ctxEntities.drawImage(consoleImg,0,0,80,50,20,20,1000,700);
};
console.src = 'res/console.png';

var hero = new Hero();
var prop;

var isPlaying = false;

window.onload = init;
var requestAnimFrame = window.requestAnimationFrame ||
                        window.webkitRequestAnimationFrame ||
                        window.mozRequestAnimationFrame ||
                        window.oRequestAnimationFrame ||
                        window.msRequestAnimationFrame ||
                        function(callback) {
                            window.setTimeout(callback, 1000 / 60);
                        };

function init() {
    console.debug('initializing...');

    document.addEventListener('keydown',keyDown,false);
    document.addEventListener('keyup',keyUp,false);

    ctxStage.imageSmoothingEnabled = false;
    ctxStage.webkitImageSmoothingEnabled = false;
    ctxStage.mozImageSmoothingEnabled = false;
    ctxEntities.imageSmoothingEnabled = false;
    ctxEntities.webkitImageSmoothingEnabled = false;
    ctxEntities.mozImageSmoothingEnabled = false;

    prop = new Entity(consoleImg,20,20,80,50,0,0);

    startLoop();
}

function startLoop(){
    console.debug('starting loop...');
    isPlaying = true;
    loop();
}

function stopLoop(){
    console.debug('stopping loop...');
    isPlaying = false;
}

function loop(){
    if(isPlaying){
        requestAnimFrame(loop);
        draw();
        update();
    }
}

function update(){
    hero.update();
}

function clearCtx(){
    ctxEntities.clearRect(0,0,stage.width,stage.height);
}

function draw(){
    clearCtx();
    ctxEntities.fillStyle = 'black';
    ctxEntities.fillRect(0,0,stage.width,stage.height);
    ctxEntities.drawImage(bgImg,0,0,80,50,-200,-90,1000,700);
    hero.draw();
    prop.draw();
}


// hero class
function Hero() {
    this.xpos = 140;
    this.ypos = 320;
    this.srcX = 0;
    this.srcY = 0;
    this.width = 10;
    this.height = 20;
    this.scaleX = 50;
    this.scaleY = 80;
    this.isUpKey;
    this.isDownKey;
    this.isLeftKey;
    this.isRightKey;
    this.img = playerImg;

    this.speed = 2;
    this.defspeed = 3.5;
    this.dir = 'right';
}

Hero.prototype.draw = function() {
    ctxEntities.drawImage(this.img,this.srcX,this.srcY,this.width,this.height,this.xpos,this.ypos,this.scaleX,this.scaleY);
};

Hero.prototype.update = function() {
    this.checkKeys();

    if(this.dir == 'right'){
        if(this.scaleX >= 0){
            this.srcX = 0;
        }
        if(this.scaleX >= 40){
            this.scaleX = 40;
            this.speed = this.defspeed;
        }else{
            this.xpos -= 2.3;
            this.speed = 0;
            this.scaleX += 5;
        }
    }else if(this.dir =='left'){
        if(this.scaleX <= 0){
            this.srcX = 10;
        }
        if(this.scaleX <= -40){
            this.scaleX = -40;
            this.speed = this.defspeed;
        }else{
            this.xpos += 2.3;
            this.speed = 0;
            this.scaleX -= 5;
        }
    }
};

Hero.prototype.checkKeys = function() {
    if(this.isLeftKey){
        this.xpos += -this.speed;
        this.dir = 'left';
    }
    if(this.isRightKey){
        this.xpos += this.speed;
        this.dir = 'right';
    }
};
// end of hero class


// entity class
function Entity(img,xpos,ypos,width,height,scaleX,scaleY){
    this.img = img;
    this.xpos = xpos;
    this.ypos = ypos;
    this.width = width;
    this.height = height;
    this.scaleX = scaleX;
    this.scaleY = scaleY;
}

Entity.prototype.draw = function(){
    ctxEntities.drawImage(this.img,0,0,this.width,this.height,this.xpos,this.ypos,this.scaleX,this.scaleY);
};
// end of entity class


// input handling
function keyDown(e){
    var keyID = (e.keyCode) ? e.keyCode : e.which;

    if(keyID == 38 || keyID == 87){ //w
        e.preventDefault();
        hero.isUpKey = true;
    }
    if(keyID == 37 || keyID == 65){ //a
        e.preventDefault();
        hero.isLeftKey = true;
    }
    if(keyID == 40 || keyID == 83){ //s
       e.preventDefault();
       hero.isDownKey = true;
    }
    if(keyID == 39 || keyID == 68){ //d
        e.preventDefault();
        hero.isRightKey = true;
    }
}

function keyUp(e){
    var keyID = (e.keyCode) ? e.keyCode : e.which;

    if(keyID == 38 || keyID == 87){
        hero.isUpKey = false;
    }
    if(keyID == 37 || keyID == 65){
        hero.isLeftKey = false;
    }
    if(keyID == 40 || keyID == 83){
        hero.isDownKey = false;
    }
    if(keyID == 39 || keyID == 68){
        hero.isRightKey = false;
    }
}
// end of input handling

更新 markE 解决了我的一半问题。我目前唯一的问题是我的 entityCtx 是唯一可以绘制图像/矩形的上下文。其他 ctx 就是不能画任何东西。我更新了代码。

【问题讨论】:

    标签: html drawing html5-canvas


    【解决方案1】:

    使用 JS “类”在多个画布上绘制

    [我扩展了我的答案以包括使用您的 JS 类的示例]

    这个例子说明了你的 2 个在画布上绘制图像的 js 类

    • Entity 类控制并在画布上绘制图像。
    • Hero 类控制并在画布上绘制精灵表。

    还有一个图像加载器,以便您的所有图像在使用前都已完全加载。

    在您的问题中,您只包含了您的 js 类代码,没有包含您的项目的细节。

    所以我使用你的 Hero 和 Entity 类创建了我自己的项目(请原谅我冒昧)。

    这张图片展示了你的 Entity 和 Hero 类在你所有 3 个画布上的动作绘图...

    这是包含以下内容的背景画布:

    • 一个天蓝色的矩形填充画布(天空)
    • 背景包含 2 个 Entity 类对象。
    • 一个太阳,它是一个包裹在 Entity 类对象中的图像
    • 一堵墙,它是一个包裹在 Entity 类对象中的图像

    这是舞台画布,包含:

    • 大炮是一个实体类对象,可以上下动画

    这是包含以下内容的实体画布:

    • 猫图像是封装在 Hero 类对象中的 spritesheet 图像
    • cat 对象为 sprite 设置动画以响应 cannon 对象
    • 猫由一个由 Hero 类控制的 spritesheet 组成

    Entity 类控制并在画布上绘制图像:

    • 图像可以移动和缩放。
    • Entity 类有 3 个方法。
    • Entity.draw() 将在画布上绘制图像。
    • Entity.set() 将设置图像在画布上的 XY 位置。
    • Entity.scale() 将缩放图像。

    这里是实体类的代码:

    // Entity class
    function Entity(context,img,x,y){
        this.context=context;
        this.img = img;
        this.xpos = x;
        this.ypos = y;
        this.width = img.width;
        this.height = img.height;
        this.scaleX = img.width;
        this.scaleY = img.height;
    }
    
    // Entity.set()
    Entity.prototype.set = function(x,y){
        this.xpos=x;
        this.ypos=y;
    }
    
    // Entity.scale()
    Entity.prototype.scale = function(scaleX,scaleY){
        this.scaleX=scaleX;
        this.scaleY=scaleY;
    }
    
    // Entity.draw()
    Entity.prototype.draw = function(){
        this.context.drawImage(this.img,
            0,0,this.width,this.height,
            this.xpos,this.ypos,this.scaleX,this.scaleY);
    }
    

    Hero 类控制并在画布上绘制精灵表

    • 从 spritesheet 图像中提取各个 sprite。
    • 每个 sprite 由一个对象定义,该对象在 spritesheet 中具有其 x、y、width、height。
    • 精灵可以移动和缩放。
    • Hero 类有 3 个方法。
    • Hero.draw() 将在画布上绘制其中一个精灵。
    • Hero.set() 将设置绘制的精灵及其在画布上的 XY 位置
    • Hero.scale() 将缩放精灵。

    这是 Hero 类的代码:

    // Hero class
    function Hero(context,img,spriteDefs) {
        this.context=context;
        this.spriteDefs=spriteDefs;
        this.img = img;
        this.xpos = 0;
        this.ypos = 0;
        this.srcX = 0;
        this.srcY = 0;
        this.width = img.width;
        this.height = img.height;
        this.scaleX = img.width;
        this.scaleY = img.height;
        this.isUpKey;
        this.isDownKey;
        this.isLeftKey;
        this.isRightKey;
    
        this.speed = 2;
        this.defspeed = 3.5;
        this.dir = 'right';
    }
    
    // Hero.set()
    Hero.prototype.set = function(spriteNumber,x,y){
        // pull the specified sprite
        var sprite=this.spriteDefs[spriteNumber];
        this.srcX=sprite.x;
        this.srcY=sprite.y;
        this.width=sprite.width;
        this.height=sprite.height;
        // default scale to 100%
        this.scaleX=sprite.width;
        this.scaleY=sprite.height;
        this.xpos=x;
        this.ypos=y;
    }
    
    // Hero.scale()
    Hero.prototype.scale = function(scaleX,scaleY){
        this.scaleX=scaleX;
        this.scaleY=scaleY;
    }
    
    // Hero.draw()
    Hero.prototype.draw = function() {
        this.context.drawImage(this.img,
            this.srcX,this.srcY,this.width,this.height,
            this.xpos,this.ypos,this.scaleX,this.scaleY);
    }
    

    这是一个图像加载器,可确保在使用之前加载所有图像

    var imageURLs=[];
    var imagesOK=0;
    var imgs=[];
    imageURLs.push("cats.png");
    imageURLs.push("cannonLifted.png");
    imageURLs.push("brickwall.jpg");
    imageURLs.push("sun.png");
    loadAllImages();
    
    function loadAllImages(){
        for (var i = 0; i < imageURLs.length; i++) {
          var img = new Image();
          imgs.push(img);
          img.onload = function(){ imagesOK++; imagesAllLoaded(); };
          img.src = imageURLs[i];
        }      
    }
    
    var imagesAllLoaded = function() {
      if (imagesOK==imageURLs.length ) {
         // all images are fully loaded an ready to use
         cat=imgs[0];
         cannon=imgs[1];
         wall=imgs[2];
         sun=imgs[3];
         start();
      }
    };
    

    这是完整的代码和小提琴:http://jsfiddle.net/m1erickson/yCW9U/

    <!doctype html>
    <html>
    <head>
    <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    
    <style>
        body{ background-color: ivory; padding:20px; }
        h3{ font-size:2em; }
        #wrapper{
            position:relative;
            width:350px;
            height:400px;
        }
        #bg,#stage,#entities{
            position:absolute; top:0px; left:0px;
            border:1px solid green;
            width:100%;
            height:100%;
        }
    </style>
    
    <script>
    $(function(){
    
    
        //////////////////////////////
        // get context references
        //////////////////////////////
    
    
        // stage
        var stage = document.getElementById('stage');
        var ctxStage = stage.getContext('2d');
        // entities
        var entitiesStage = document.getElementById('entities');
        var ctxEntities = entitiesStage.getContext('2d');
        // background
        var bg = document.getElementById('bg');
        var ctxBg = bg.getContext('2d');
    
    
        //////////////////////////////
        // public variables
        //////////////////////////////
    
    
        // images
        var wall,cat,cannon,sun;
    
        // display objectx
        var sunEntity,wallEntity,cannonEntity,catHero;
    
        // animation vars 
        var cannonX=65;
        var cannonMove=-10;
        var cannonMin=75;
        var cannonMax=185;
        var cannonY=185;
        var cannonSafe=145;
    
        // cat hero sprites
        var catSpriteNames={
            laying:0,
            layingX:250,
            layingY:127,
            standing:1,
            standingX:165,
            standingY:25
        };
        var catSprites=[
            {x:80, y:30, width:67, height:48},
            {x:15, y:8,  width:47, height:78}
        ];
    
    
        //////////////////////////////
        // preload all images
        //////////////////////////////
    
    
        var imageURLs=[];
        var imagesOK=0;
        var imgs=[];
        imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/cats.png");
        imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/cannonLifted.png");
        imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/BrickWall.jpg");
        imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/sun.png");
        loadAllImages();
    
        function loadAllImages(){
            for (var i = 0; i < imageURLs.length; i++) {
              var img = new Image();
              imgs.push(img);
              img.onload = function(){ imagesOK++; imagesAllLoaded(); };
              img.src = imageURLs[i];
            }      
        }
    
        var imagesAllLoaded = function() {
          if (imagesOK==imageURLs.length ) {
             // all images are fully loaded an ready to use
             cat=imgs[0];
             cannon=imgs[1];
             wall=imgs[2];
             sun=imgs[3];
             start();
          }
        };
    
    
        //////////////////////////////
        // build the display objects 
        // and start animation
        //////////////////////////////
    
    
        function start(){
    
            // static background (canvas: bg)
            // rectangle=blue sky
            ctxBg.rect(0,0,bg.width,bg.height);
            ctxBg.fillStyle="skyblue";
            ctxBg.fill();
            // sun image @ 75% scale
            sunEntity=new Entity(ctxBg,sun,185,15);
            sunEntity.set(25,15);
            sunEntity.scale(sun.width*.75,sun.height*.75);
            sunEntity.draw();
            // wall image
            wallEntity=new Entity(ctxBg,wall,250,bg.height-wall.height);
            wallEntity.set(250,bg.height-wall.height,wall.width,wall.height);
            wallEntity.draw();
    
    
            // stage (canvas: stage)
            // contents: wall
            cannonEntity=new Entity(ctxStage,cannon,cannonX,cannonY,cannon.width,cannon.height,cannon.width,cannon.height);
            cannonEntity.draw();
    
    
            // entities (canvas: entities)
            // contents: 
            catHero=new Hero(ctxEntities,cat,catSprites);
            catHero.set(catSpriteNames.laying,catSpriteNames.layingX,catSpriteNames.layingY);
            catHero.draw();
    
            animate();
        }
    
        function animate(){
    
            cannonY+=cannonMove;
            if(cannonY<cannonMin){ cannonY=cannonMin; cannonMove=-cannonMove; }
            if(cannonY>cannonMax){ cannonY=cannonMax; cannonMove=-cannonMove; }
    
            cannonEntity.context.clearRect(0,0,stage.width,stage.height);
            cannonEntity.set(cannonX,cannonY);
            cannonEntity.draw();
    
            if(cannonY>cannonSafe){
                catHero.set(catSpriteNames.laying,catSpriteNames.layingX,catSpriteNames.layingY);
            }else{
                catHero.set(catSpriteNames.standing,catSpriteNames.standingX,cannonY-50);
            }
            catHero.context.clearRect(0,0,entities.width,entities.height);
            catHero.draw()
    
    
            window.setTimeout(function(){animate();},500);
        }
    
    
        // Hero class
        function Hero(context,img,spriteDefs) {
            this.context=context;
            this.spriteDefs=spriteDefs;
            this.img = img;
            this.xpos = 0;
            this.ypos = 0;
            this.srcX = 0;
            this.srcY = 0;
            this.width = img.width;
            this.height = img.height;
            this.scaleX = img.width;
            this.scaleY = img.height;
            this.isUpKey;
            this.isDownKey;
            this.isLeftKey;
            this.isRightKey;
    
            this.speed = 2;
            this.defspeed = 3.5;
            this.dir = 'right';
        }
        // Hero.set()
        Hero.prototype.set = function(spriteNumber,x,y){
            // pull the specified sprite
            var sprite=this.spriteDefs[spriteNumber];
            this.srcX=sprite.x;
            this.srcY=sprite.y;
            this.width=sprite.width;
            this.height=sprite.height;
            // default scale to 100%
            this.scaleX=sprite.width;
            this.scaleY=sprite.height;
            this.xpos=x;
            this.ypos=y;
        }
        // Hero.scale()
        Hero.prototype.scale = function(scaleX,scaleY){
            this.scaleX=scaleX;
            this.scaleY=scaleY;
        }
        // Hero.draw()
        Hero.prototype.draw = function() {
            this.context.drawImage(this.img,
                this.srcX,this.srcY,this.width,this.height,
                this.xpos,this.ypos,this.scaleX,this.scaleY);
        }
    
    
        // Entity class
        function Entity(context,img,x,y){
            this.context=context;
            this.img = img;
            this.xpos = x;
            this.ypos = y;
            this.width = img.width;
            this.height = img.height;
            this.scaleX = img.width;
            this.scaleY = img.height;
        }
        // Entity.set()
        Entity.prototype.set = function(x,y){
            this.xpos=x;
            this.ypos=y;
        }
        // Entity.scale()
        Entity.prototype.scale = function(scaleX,scaleY){
            this.scaleX=scaleX;
            this.scaleY=scaleY;
        }
        // Entity.draw()
        Entity.prototype.draw = function(){
            this.context.drawImage(this.img,
                0,0,this.width,this.height,
                this.xpos,this.ypos,this.scaleX,this.scaleY);
        }
    
    }); // end $(function(){});
    </script>
    
    </head>
    
    <body>
        <h3>Watch out Kitty!</h3><br>
        <div id="wrapper">
            <canvas id="bg" width=350 height=400></canvas>
            <canvas id="stage" width=350 height=400></canvas>
            <canvas id="entities" width=350 height=400></canvas>
        </div>
    </body>
    </html>
    

    【讨论】:

    • 谢谢!这解决了问题的一半。剩下的唯一问题是我的 ctxStage 仍然没有绘制图像,并且我的道具(实体类)仍然没有绘制。 html/css 没有错误。
    • 我在答案中添加了有关您的图像的解释。在尝试绘制图像之前,您必须给图像时间加载。为此,您可以使用 image.onload。
    • 我快搞定了!它只是画了一秒钟。当我用 ctxEntities 绘制它时效果很好;但是,ctxStage 无法绘制图像或矩形。
    • 如果这有帮助,您可以在此处查看该项目。我目前正在使用entitiesCtx 绘制背景图像和矩形。我想用stageCtx来画它。我的 Entity() 道具对象仍然没有绘制。 c9.io/benjihansen/canvasgame/workspace/index.html
    • 确保对项目中的其他图像也使用 image.onload ——所有图像都需要时间加载;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-16
    • 2012-01-14
    • 2018-07-06
    • 2013-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多