使用多个画布绘制图像的问题

时间:2013-08-18 20:47:54

标签: html5 drawing html5-canvas

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

(我尝试设置一个JSFiddle,但我无法在那里获取图像。)

更新 我的问题的一半是由markE修复的。我目前唯一的问题是,我的entitiesCtx是唯一可以绘制图像/矩形的上下文。其他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修复的。我目前唯一的问题是,我的entitiesCtx是唯一可以绘制图像/矩形的上下文。其他ctx只是无法绘制任何东西。我更新了代码。

1 个答案:

答案 0 :(得分:1)

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

[我扩展了我的答案,包括使用你的JS类的例子]

此示例说明了在画布上绘制图像的2个js类

  • 实体类控制并在画布上绘制图像。
  • Hero类控制并在画布上绘制spritesheets。

还有一个图像加载器,以便在使用之前将所有图像完全加载。

在你的问题中,你只包括你的js级代码,没有关于你的项目的细节。

所以我使用你的Hero和Entity课程组建了我自己的项目(原谅我的自由)。

此图片显示了您所有3幅画布上的实体和英雄类动作......

enter image description here

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

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

enter image description here

这是包含以下内容的舞台画布:

  • 一个加农炮,它是一个上下动画的实体类对象

enter image description here

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

  • 猫图像是包含在Hero类对象中的spritesheet图像
  • 猫对象动画精灵以响应大炮对象
  • 猫是由一个由英雄级别
  • 控制的精灵表

enter image description here

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

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

以下是Entity类的代码:

// 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类在画布上控制和绘制spritesheets

  • 从spritesheet图像中拉出各个精灵。
  • 每个精灵都是由spritesheet中具有x,y,width,height的对象定义的。
  • 精灵可以移动和缩放。
  • 英雄课有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>