资讯专栏INFORMATION COLUMN

canvas精灵封装

livem / 887人阅读

摘要:在做动画时,精灵封装的好坏,直接影响后续的编程体验。基本封装精灵名字绘制器,需另外封装行为,精灵行为属性是一个指向对象的引用,使用方法来绘制精灵。精灵绘制器即提供给对象的对象,和解耦。

在做canvas动画时,精灵封装的好坏,直接影响后续的编程体验。

下文的封装方法来自《HTML5 Canvas核心技术 图形、动画与游戏开发》,实现了精灵与绘制对象的解耦,很好用,平时自己也用这种写法。

一个完整的Sprite包含两部分:

Sprite的基本封装

Sprite Painter实现

拆开Sprite和Painter,实现了解耦,可以随意调整Painter功能。Pinter对象只需要实现: void paint(sprite, context)方法即可。这好像也叫策略模式。

Sprite 基本封装:
// name:精灵名字
// painter: 绘制器,需另外封装
// behaviors: 行为,精灵行为
var Sprite = function(name, painter, behaviors){
    this.left = 0,
       this.top = 0,
       this.width = 10,
       this.height = 10,
      this.velocityX = 0,
      this.velocityY = 0,
       this.visible = true,
       this.animating = false,
       this.painter = undefined, // object with paint(sprite, context)
       this.behaviors = [], // objects with execute(sprite, context, time)
       
       if(name){
        this.name = name;
    }
    if(painter){
        this.painter = painter;
    }
}

Sprite.prototype = {
    // painter属性是一个指向Painter对象的引用,使用paint(sprite, context)方法来绘制精灵。
    // behaviors属性指向一个对象数组,数组的每个对象都以execute(sprite, context, time)方法来对精灵进行操作
    paint: function(context){
        if(this.painter.paint !== undefined && this.visible){
            this.painter.paint(this, context);
        }
    },
    
    update: function(context, time){
        for(var i = this.behaviors.length; i > 0; --i){
            this.behaviors[i-1].execute(this, context, time);
        }
    }
}

behavior一开始有些难理解。书上的解释是:精灵的行为。

什么叫行为呢?

个人觉得,改变了Sprite基本属性的动作,都叫精灵的行为,改变了top、width、velocityX等balabala的都叫行为。

behavior里面会实现一个excute方法 void excute(sprite, context, time){}。在方法里面会修改各类的值。到Pianter绘制的时候,会实现修改后的效果。也就实现了精灵的多种行为。

精灵绘制器

即提供给Sprite对象的Painter对象,和Sprite解耦。

目前Painter对象分为三类:

  • 描边及填充绘制器
  • 图像绘制器
  • 精灵图绘制器
  • 描边绘制器可以随意控制,只要实现了 void paint(sprite, context)就可以了。

    1.图像绘制器

    var ImagePainter = function(imgUrl){
        this.image = new Image();
        this.image.src = imgUrl;
    }
    
    ImagePainter.prototype = {
        paint: function(sprite, context){
            if(this.image.complete){
                context.drawImage(this.image, sprite.left, sprite.top, sprite.width, sprite.height);
            } else{
                this.iamge.onload = function(e){
                    context.drawImage(this.image, sprite.left, sprite.top, sprite.width, sprite.height);
                }
            }
        }
    }
    

    2.精灵绘制器

    var SpriteSheetPainter = function(cells){
        this.cells = cells;
    };
    
    SpriteSheetPainter.prototype = {
        cells: [],
        cellIndex: 0,
        
        advance: function(){
            if(this.cellInde === this.cells.length -1 ){
                this.cellIndex = 0;
            } else{
                this.cellIndex++;
            }
        },
        paint: function(sprite, context){
            var cell = this.cells[this.cellIndex];
            context.drawImage(spritesheet, cell.x, cell.y, cell.w, cell.h,
                                sprite.left, sprite.top, cell.w, cell.h);
        }
    }
    
    精灵动画制作器

    SpriteAnimator包含两个参数,Painter数组和回调函数。

    var SpriteAnimator = function(painters, elapsedCallback){
        this.painters = painters;
        if(elapsedCallback){
            this.elapsedCallback = elapsedCallback;
        }
    };
    
    SpriteAnimator.prototype = {
        painters: [],
        duration: 1000,
        startTime: 0,
        index: 0,
        elapsedCallback: undefined,
        
        end: function(sprite, originalPainter){
            sprite.animating = false;
            if(this.elapsedCallback){
                this.elapsedCallback(sprite);
            } else{
                sprite.painter = originalPainter;
            }
        },
        
        start: function(sprite, duration){
            var endTime = +new Date() + duration,
                period = duration / (this.painters.length),
                  interval = undefined,
                  animator = this, // for setInterval() function
                  originalPainter = sprite.painter;
                  
              this.index = 0;
              sprite.animating = true;
              sprite.painter = this.painter[this.index];
              
              interval = setInterval(){
                  if(+new Date() < endTime){
                      sprite.painter = animator.painters[++animator.index];
                  } else{
                      animator.end(sprite, originalPainter);
                      clearIntercal(interval);
                  }
              }, period);
        }
    }
    

    文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

    转载请注明本文地址:https://www.ucloud.cn/yun/80252.html

    相关文章

    • 学习 PixiJS — 交互工具

      摘要:设置缩放比例的构造函数还可以传入第三个参数,这个可选的参数用来确保使用的坐标将匹配画布的缩放像素坐标。将其设置为将再次启用拖动。 说明 Pixi 内置一组功能有限的用于鼠标交互和触摸交互的方法,但是对于游戏和应用程序所需的丰富交互性,建议使用第三方库来简化操作,这篇文章介绍的是 Tink 库,它有通用的指针对象、拖放精灵、按钮对象、键盘控制 等一些有用的功能。 使用 Tink 库 要...

      zlyBear 评论0 收藏0
    • 可扩展面向对象的canvas画图程序

      摘要:方法创建弧曲线用于创建圆或部分圆圆的中心的坐标。弧的圆形的三点钟位置是度。规定应该逆时针还是顺时针绘图。注意事项构造函数的形参只有两个是必须的,就是定位点的坐标。选中元素时调用,判断选中位置。 面向对象的canvas画图程序 项目简介 整个项目分为两大部分 场景场景负责canvas控制,事件监听,动画处理 精灵精灵则指的是每一种可以绘制的canvas元素 Demo演示地址Demo为...

      Lavender 评论0 收藏0
    • 使用 canvas 实现精灵动画

      摘要:文章首发于个人博客在最近项目中需要实现一个精灵动画,素材方只提供了一个短视频素材,所以在实现精灵动画之前先介绍两个工具来帮助我们更好的实现需求。 文章首发于个人博客:http://heavenru.com 在最近项目中需要实现一个精灵动画,素材方只提供了一个短视频素材,所以在实现精灵动画之前先介绍两个工具来帮助我们更好的实现需求。在这篇文章中,主要是介绍两个命令行工具来实现将一个短视频...

      岳光 评论0 收藏0

    发表评论

    0条评论

    最新活动
    阅读需要支付1元查看
    <