0

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

(我尝试设置一个 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 就是不能画任何东西。我更新了代码。

4

1 回答 1

1

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

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

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

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

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

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

因此,我使用您的 Hero 和 Entity 类创建了自己的项目(请原谅我冒昧)。

此图像显示了您在所有 3 个画布上的动作绘图中的实体和英雄类...

在此处输入图像描述

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

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

在此处输入图像描述

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

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

在此处输入图像描述

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

  • 猫图像是包装在 Hero 类对象中的 spritesheet 图像
  • 猫对象响应大炮对象动画精灵
  • 猫由一个由 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 由一个在 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>
于 2013-08-18T21:28:09.387 回答